From eef4cf0f50efc9c76dbe9862e71ec8b2a58368d4 Mon Sep 17 00:00:00 2001 From: User Date: Wed, 15 Jul 2026 03:10:10 +0200 Subject: [PATCH] docs: design model activity signal filter --- ...-15-model-activity-signal-filter-design.md | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 docs/superpowers/specs/2026-07-15-model-activity-signal-filter-design.md diff --git a/docs/superpowers/specs/2026-07-15-model-activity-signal-filter-design.md b/docs/superpowers/specs/2026-07-15-model-activity-signal-filter-design.md new file mode 100644 index 00000000..0d9de87b --- /dev/null +++ b/docs/superpowers/specs/2026-07-15-model-activity-signal-filter-design.md @@ -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.