docs: design model activity signal filter

This commit is contained in:
User
2026-07-15 03:10:10 +02:00
parent ffef01eb0a
commit eef4cf0f50
@@ -0,0 +1,108 @@
# Model Activity Signal Filter Design
**Date:** 2026-07-15
## Goal
Keep the left **Model activity** panel useful without exposing low-level execution chatter. The
panel must show the user's prompt, genuine model reasoning when the provider emits it, meaningful
status messages, and reviewer gates. It must not show assistant narration, tool lifecycle rows, or
turn lifecycle rows.
## Current behavior and root cause
`sessionStore` intentionally builds a complete chronological `activityLog` containing prompt,
thinking, assistant, tool, gate, status, and lifecycle entries. `ModelActivityPanel` currently
renders every entry in that array. As a result, a non-reasoning model can fill the panel with rows
such as `tool / completed / bash`, `lifecycle / Turn end`, and assistant narration such as
"Let me try...".
Those events are useful to workflow state, replay, the central transcript, and diagnostics, but
they are not all suitable for the user-facing activity panel.
## Visibility contract
The panel uses an explicit allowlist:
| Activity kind | Visible | Purpose |
| --- | --- | --- |
| `prompt` | Yes | Shows the question or reviewer input that started the work. |
| `thinking` | Yes | Shows genuine reasoning/COT when the configured provider emits it. |
| `status` | Yes | Shows meaningful informational, warning, and error milestones. |
| `gate` | Yes | Shows that the workflow reached a reviewer decision point. |
| `assistant` | No | Avoids exposing operational narration; user-facing assistant text remains in the central transcript. |
| `tool` | No | Avoids repetitive implementation details such as `bash completed`. |
| `lifecycle` | No | Avoids transport/turn noise such as `Turn end`. |
This is a strict kind-based contract. The UI must not guess whether a particular assistant sentence
is "internal" or "final" by matching text. Such heuristics would be language-dependent and brittle.
## Architecture and data flow
The filter belongs at the rendering boundary in `ModelActivityPanel`:
1. `SessionBridge` continues to sanitize and emit tool/system events.
2. `sessionStore` continues to fold every event into the complete in-memory `activityLog` and to
update transcript, current phase, pending gate, and agent-active state exactly as today.
3. `ModelActivityPanel` derives `visibleActivity` from the allowlisted kinds and renders only that
projection.
Keeping ingestion unchanged preserves the existing SSE/replay, tool correlation, end-of-turn,
resume, and diagnostic contracts. It also keeps the central transcript independent: hiding an
`assistant` entry from the left panel does not remove it from `transcript`.
The visibility predicate should be a small exported pure function or a named exported kind set so
the contract can be tested directly without duplicating conditions in test code.
## Interaction details
- The empty state is based on `visibleActivity.length`, not the raw log length. If only hidden
events have arrived, the panel displays `No activity yet.` instead of a visually empty viewport.
- Automatic bottom-following reacts only when the visible tail changes. The effect must depend on
the identity of the last visible entry (and the visible count), not merely on a newly allocated
filtered array. Hidden tool, assistant, or lifecycle events therefore cannot move a reader's
scroll position, while appended or streamed visible entries still follow correctly.
- Phase, level, Markdown rendering, accessibility labels, close behavior, and the 48 px
near-bottom threshold remain unchanged for visible rows.
- No new toggle, preference, expansion control, or raw-details view is introduced.
## Error and edge-case behavior
- Unknown future activity kinds are hidden by default because they are not allowlisted.
- Warning and error status rows remain visible and retain their textual severity labels.
- A provider that emits no `thinking` still shows prompt/status/gate milestones; the panel does not
synthesize reasoning from assistant narration or tool names.
- Closing and reopening the panel does not mutate the underlying complete log or the visible
projection.
## Testing
Frontend tests must prove:
1. A mixed F1 sequence renders prompt, thinking, status, and gate rows but does not render
assistant narration, tool names/statuses, or lifecycle text.
2. A hidden-only sequence produces the `No activity yet.` state.
3. Assistant output still exists in the central transcript/store after being excluded from the
activity panel.
4. Hidden-only updates do not trigger bottom-follow scrolling; visible updates retain the existing
near-bottom behavior.
5. Warning/error labels, Markdown, closing/reopening, and the complete store fold remain covered by
the existing regression suite.
The implementation follows RED/GREEN TDD and runs the focused panel/store tests, the complete
frontend suite, TypeScript, the production build, and `git diff --check`.
## Deployment
Only the frontend is expected to change. Rebuild and force-recreate the frontend container, then
restart only `omics_portal-web-1` if the Vite entry hash changes. Verify the running asset, container
state, and a live Qwen no-COT session showing prompt/status/gate information without assistant,
tool, or lifecycle rows.
## Out of scope
- Changing backend event emission or the sanitization boundary.
- Removing entries from `activityLog`.
- Reclassifying assistant text through content heuristics or an LLM.
- Changing the central transcript or workflow state machine.
- Redesigning the panel layout beyond the visibility and empty/scroll behavior described above.