Why: make material, background work, confirmations and files accessible to nontechnical users across desktop and mobile.
Evidence: Dev SELF receipts for Frontend tsc, 190 tests, knip baseline, build, nine fixture browser cases and two real HTTP/browser smoke cases using MockRunner.
Impact: existing API and permissions remain authoritative; stale events/queries and duplicate effects are guarded, while one file preview and reading state are preserved.
Refs: work-companion-ui design r0.2 and plan r1 U2-U5; UI01-UI13.
Why: Existing event and helper tests missed the SurfaceMeta to snapshot
reload path that blanked the app after the integration pointer regressed.
Evidence: New restore regressions fail on 1edd872 and pass on compatible
main; independent reviewer replays and real browser contract replay are
recorded in the Dev surface-black-screen-recovery task card.
Impact: Tests only; protects reload, partial failure, newer live revisions,
conversation switching, and two-page browser preview.
Refs: Frontend #68; Dev #454 and #452; Dev surface-black-screen-recovery
Why: GET .../surfaces returns SurfaceMeta without identity; writing it into
surfaces let PreviewPane crash on x.identity.surfaceId after refresh.
Evidence: npx vitest run (118 passed), including surfaceKey.test.ts
Impact: openConversation fetches SurfaceSnapshot via surfaceGet; find paths
use surfaceKey; Meta no longer enters the surfaces projection
Refs: fix/surface-list-hydrate
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: When a slow-lane progress card is active, hide the plan/todos
CurrentTaskCard so the work column has one authoritative task object.
Evidence: npx vitest run (workbench-progress + full suite)
Impact: Workbench work tab; tidyCards skips done+danger failures.
Refs: fast-slow-channel-display-u1-plan W4
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: the repo's @playwright/test version has no toBeReadOnly matcher.
Evidence: failing run shows TypeError at the matcher; the attribute
assertion works across versions.
Impact: none beyond the spec assertion.
Refs: 2026-10-12 diagnostic report, increment 3.
Why: the change-password modal rendered loose password inputs outside any
<form> with no autocomplete or username association (browser password-form
warnings; Enter did not submit), and its 401 handling collapsed every
cause into "wrong current password". SettingInput masked ALL free-text
config values as password fields.
Evidence: vitest 24 files / 116 tests incl. new settingInputAttrs matrix;
knip and tsc -b && vite build pass; e2e changepw-form spec (driven by the
dev-repo e2e.sh plain phase) covers form submit via Enter, autocomplete
trio, readonly username and the classified error copy.
Impact: ChangePasswordModal uses form onSubmit, htmlFor/id association,
username/current-password/new-password autocomplete and reuses
humanChangePasswordError; SettingInput renders text inputs unless the
field is secret.
Refs: 2026-10-12 diagnostic report, increment 3.
Why: dev-repo main advanced the frontend pin to d01a3eb (admin-zone
section hosting), diverging from the gating branch; the task-sync gitlink
conflict requires the component-level merge first.
Evidence: post-merge vitest 23 files / 112 tests, knip 42 <= 43, and
tsc -b && vite build all pass; store.ts conflict resolved by keeping both
rdmAuditAvailable and adminSections state.
Impact: gating branch now contains frontend main d01a3eb.
Refs: 2026-10-12 diagnostic report, increment 2; frontend #63/#64.
Why: BuildWorkspaceOptions / RdmErrorKind / RdmErrorView are only consumed
inside their own modules, so exporting them pushed unused exports 45 over
the knip baseline 43 and failed make test.
Evidence: npx vitest run 23 files / 112 tests pass; node scripts/check-knip.mjs
passes at 42 <= 43.
Impact: no API change - consumers pass object literals and consume the
classified error structurally.
Refs: 2026-10-12 diagnostic report, increment 2.
Why: phase 4 runs after the RDM phase already forced the password change,
so the initial-password attempt 401s and the sidebar never renders.
Evidence: phase-4 failure log shows the login form still up at the
15s .tsb-tool timeout; rdm-audit spec already carries this branch.
Impact: plain-base login helper mirrors rdm-audit's gate-aware login.
Refs: 2026-10-12 diagnostic report, increment 2.
Why: the phase-3 playwright run scans the whole e2e/ directory, so the
plain-base assertions ran against the RDM combo where the audit entry is
legitimately visible and failed.
Evidence: phase-3 rerun shows 4 rdm-audit tests passing with plain-base
failing out of place; the spec now skips unless E2E_PLAIN_BASE=1, which
scripts/e2e.sh phase 4 injects.
Impact: plain-base scenario only executes against the plain base serve.
Refs: 2026-10-12 diagnostic report, increment 2.
Why: the rdm-audit entry was an unconditional builtin, so on a plain base
without any rdm.inspect.* commands the workspace opened straight into a
rejected receipt (400) - diagnosed 2026-10-12. The page also rendered raw
receipt JSON instead of a readable error.
Evidence: vitest 23 files / 112 tests pass incl. the new contract matrix
(workspaces.test.ts, rdm-errors.test.ts) and design-guard; tsc -b &&
vite build pass; e2e plain-base scenario added (driven by dev-repo
scripts/e2e.sh phase 4).
Impact: audit entry shows only when GET /api/commands lists all seven
rdm.inspect.* commands enabled (store.rdmAuditAvailable, refreshed with
the workspace list); audit errors classify into capability-missing /
auth-expired / query-failed with the raw receipt kept in a Collapsible.
Refs: 2026-10-12 diagnostic report, increment 2.
Why: src/contracts.ts is fully regenerated from Core by make contracts;
the hand-added interface there is deleted on every sync (surfaced as a
dirty tree in the Dev composite test run).
Evidence: npx vitest run 101/101, tsc --noEmit clean, knip 42 <= 43;
Dev composite CI is authoritative.
Impact: AdminZoneSection now lives in api.ts (backend-only endpoint
type, matching existing local-type precedent); contracts.ts restored to
the generated mirror; imports updated in store and AdminZone.
Refs: WP3-I3; follows Frontend PR #63.
Why: KTD4 requires the RDM audit partition to be reachable from the admin
zone by RDM domain admins and base superadmins, without hardcoding RDM
into the base AdminZone or merging roles in the frontend.
Evidence: npx vitest run 101/101 green (incl. design-guard), tsc --noEmit
clean, knip 42 <= 43; Dev composite CI is authoritative.
Impact: AdminZone merges admin-only builtin sections with sections
declared by compiled plugins (GET /api/admin-zone/sections, loaded in
refreshPlugins); the entry menu shows when isAdmin OR declared sections
exist; declared sections render via an id-keyed builtin component map
(rdm.audit -> RdmAuditWorkspace) with a version-mismatch placeholder for
unknown ids; unknown icons fall back to the generic grid icon. Token and
color usage unchanged.
Refs: WP3-I3/KTD4; task card feature-adminzone-plugin-sections.
Why: U6 brings generated pages into the work view - a compact
task-page section renders the latest conversation surface under the
current-task card (SurfaceView), a pin freezes the shown page against
new arrivals (unpin follows latest), a jump button opens the full
preview, and the project-level aggregate loads on conversation open
for cross-session visibility; when the plugin is disabled or no pages
exist the section disappears and the work view is untouched.
Evidence: tsc clean; vitest 101/101 including the pin/follow test;
knip unchanged.
Impact: Frontend-only; consumes the U6 backend aggregate endpoint.
Refs: proposal r2 U6; Backend #163; Dev task feature/generative-ui-u6
Why: store.me was only written by the forced-change gate's onDone
(refreshMe sole caller), so after any page reload or a normal
re-login me stayed null and the admin menu (me?.isAdmin gate in
TaskSidebar/AdminZone) vanished permanently - reported repeatedly as
the user-management page becoming unavailable.
Evidence: vitest 100/100 pass and tsc+vite build clean after the
change; grep shows refreshMe had exactly one call site before
(App.tsx mustchange onDone).
Impact: admins keep the system-management entry across reloads and
normal logins; no behavior change for non-admins (me loads but
isAdmin=false).
Refs: dev task card feature/fe-me-refresh; companion Dev-repo pin
bump.
Why: /api/plugins now merges compiled-in plugins (backend.mode=inproc);
the list needed to badge them as builtin, count their commands, and stop
printing a dangling "v" when the synthesized manifest has no version.
Evidence: npx vitest run 100/100 green incl. design-guard; tsc --noEmit
clean for src (../ui errors are the symlinked-deps environment only);
CI (make test) is authoritative.
Impact: PluginsSection label hides empty versions, desc adds a command
count and falls back to manifest intent counts, and inproc entries get a
"内置" badge next to the api badge. No token or color changes.
Refs: WP3-I4; task card feature-plugins-compiled-listing.
Why: seeded sections carry no confirmed trace edges yet, so the no-relations empty state is the correct U4 presentation.
Evidence: scripts/e2e.sh rerun in this task.
Impact: test-only.
Why: rdm.inspect.tree docs is two-level (parent=<docId> returns sections), but the U4 workspace only fetched level one - the tree showed bare documents, clicking a doc hit unsupported inspect.object kind, and the trace tab always showed no sections.
Evidence: tsc + design-guard green; scripts/e2e.sh full run in this task.
Impact: tree browsing expands documents into sections; trace entry lists sections aggregated per document.
Refs: U4/U3 read-service contract; task feature/rdm-e2e-acceptance.
Why: the first docs-tree node is document-level and carries no event history; U4 evidence-finding targets sections.
Evidence: scripts/e2e.sh rerun in this task.
Impact: test-only.
Why: buildWorkspaceEntries pushed only BUILTINS[0] (agents); the U4
rdm-audit workspace was declared but never ranked, so no user could
open the trace/audit workspace from the sidebar.
Evidence: vitest workspaces.test.ts 4/4 (updated expectations plus a
new overflow-truncation case); full browser run in scripts/e2e.sh.
Impact: sidebar gains the second builtin tool; server-declared
workspaces keep their shortcut precedence.
Refs: U4 (Dev #368) regression; task feature/rdm-e2e-acceptance.
Why: U4 acceptance requires real-browser runs of the trace/audit
workspace; the repo had only a manual .playwright.ts stub gated on
PLAYWRIGHT_BASE_URL with no config, deps, or service wiring.
Evidence: config/deps/spec staged; full run driven by Dev-side
scripts/e2e.sh (seed-only smoke in progress in this task branch).
Impact: dev-only additions (@playwright/test devDep, preview proxy
segment, e2e/rdm-audit.playwright.ts); no production bundle changes.
Refs: Dev task feature/rdm-e2e-acceptance; U4 in
modules/documents/docs/proposals/2026-10-11-rdm-two-trees-trace-audit-integration.md
Why: A single run re-registering one deliverable left three identical
report files side by side (storage is append-only by design and the
prompt even teaches revisions-as-new-versions); the panel listed every
row. Per the owner ruling, storage keeps all versions - the panel now
groups by name, shows only the latest row, badges multi-version groups
with the count, and expands (Collapsible primitive) to list history
with per-version preview/download.
Evidence: tsc clean; vitest 99/99 including new grouping tests (latest
selection by updatedAt, ordering, cross-name independence, empty);
knip unchanged.
Impact: Frontend-only display logic; no storage, API, or prompt
changes.
Refs: Dev task fix/artifact-version-dedupe
Why: Field evidence - surfaces arrived and tabs opened in state but the
screen showed nothing: the event branch missed syncFilesEntry (right
panel stayed on work tab, collapsed, or list view), refresh/reentry had
no way back (openSurface was dead code), and the files panel listed no
pages.
Evidence: tsc clean; vitest 97/97 including new cases (event switches
rightTab=files + preview view; suppressed path keeps projection
consistent); knip unchanged.
Impact: Frontend-only behavior fixes; no API changes.
Refs: Dev task fix/genui-page-visibility
Why: U5 (#367) introduced a two-parameter callback but SurfaceView (@ui) expects (id: string) => void; TypeScript build fails on main.
Evidence: SELF tsc --noEmit zero errors after fix.
Impact: PreviewPane.tsx one-line type fix; no behavior change (payload path dormant until @ui widens the interface).
Refs: Dev #367
Why: U5 closes the interactive loop - the surface view's action click
carries the user's typed drafts (and nothing else - unsubmitted input
has no upload path), the store builds the idempotent request
(client-generated requestId, current revision), guards double-clicks
in flight, and maps server outcomes to toasts (awaiting-confirm card,
revision conflict refresh, disabled rejection).
Evidence: tsc clean; vitest 95/95 including the request-shape test
(explicit data only, unique requestId per submission); knip unchanged.
Impact: Frontend-only; backend endpoint from the U5 backend branch.
Refs: U5 action-scope r2 (approved); UI PRs #46/#47; Dev task
feature/generative-ui-u5
Why: the master plan U4 requires a four-entry traceability audit workspace as a builtin Dev frontend workspace; U3 rdm.inspect.* commands are the server contract.
Evidence: SELF tsc --noEmit zero errors in new files; design guard compliance verified (tokens only, no raw colors, no inline fontSize, no details element); CI (GATE) will run full suite.
Impact: RdmAuditWorkspace.tsx (new, ~500 lines), api.ts (+rdmCommand), Workspaces.tsx (+rdm-audit dispatch), workspaces.ts (+builtin), styles.css (+rdm-audit-* using only @ui tokens).
Refs: Documents eb36571 master plan U4; U3 rdm.inspect.* contract
Why: the auth middleware prefers Bearer keys over the session cookie, so a stale key left in localStorage shadows valid cookie sessions and every request after password login returns 401 (observed at http://192.168.3.2:8788 on 2026-10-11).
Evidence: modules/frontend vitest 19 files / 88 tests green; auth.test.ts covers beginSession clearing the stored Bearer before any fetch.
Impact: password logins switch to the HttpOnly cookie session cleanly; API-key logins unchanged.
Refs: task card feature-login-clear-stale-key in Agent-System-Dev.
Why: entering the forced-change gate with an API-key credential always
fails 401 (passwords are session-owned), and the gate mapped every 401
to "Incorrect username or password", masking the real reason and hiding
the self-service exit; admins got locked out before reaching user
management.
Evidence: npx vitest run green (20 files / 93 tests incl. new
test/loginpage.test.ts); tsc -b and check-knip green.
Impact: App boot routes key+mustChange to the login page (key cleared);
the API-key tab advises password login for must-change accounts; the
gate maps backend error strings to distinct actionable messages; api.me
type gains authVia.
Refs: Dev task feature/admin-auth-gate-fix.
Why: U4 read-only experience - surface.updated events project into a
surfaces slice with a strict revision guard (stale/duplicate events
never overwrite; server snapshot is the single owner), preview tabs
gain a surface: kind that renders SurfaceView (doc-refs bridge into
artifact previews), a new page auto-opens a tab without stealing the
user's active non-surface tab, and opening a conversation reloads the
authoritative surface list so refresh/断线 restores pages.
Evidence: tsc clean; vitest 87/87 including new surface projection
tests (stale/duplicate/multi-surface); UI SurfaceView suite green in
its repo.
Impact: Frontend-only; no backend or contract changes.
Refs: Core PRs #27/#28; UI PRs #42/#43/#44; Dev task
feature/generative-ui-u4
Why: Core PR #26 added the node id/source fields to ts/types.ts (the
single authority); the mirror is regenerated so the sync header and
content match make contracts output exactly (manual edits drift).
Evidence: File generated by the make contracts copy steps; combined
verification in the Dev workspace after re-pinning.
Impact: Header banner plus the already-reviewed id/source fields.
Refs: Core PR #26; Dev task feature/generative-ui-u2
Why: Core PR #25 adds optional id/source to UINode for the Generative
UI Surface layer; the TypeScript contract authority mirrors core types.
Evidence: Type-only additive change; combined verification runs in the
Dev workspace make test.
Impact: No component or behavior change.
Refs: Agent-System-Core #25; Dev task feature/generative-ui-u2
Why: Removing the artifacts builtin shifts the shortcut ranking, so the
workspaces tests now expect agents at cmd-1; Workbench no longer selects
previewOpen in its outer scope (FilesTab owns that read).
Evidence: npx vitest run 85/85 passed; npm run build (tsc -b && vite
build) passed in the task worktree (SELF).
Impact: test/workspaces.test.ts expectations; Workbench.tsx selector
cleanup. No behavior change beyond the committed layout rework.
Why: The three-column workbench redesign converges entries and hierarchy:
project switching tops the left rail (identity shown once), sessions and
search stay centered, files/workspaces/account sink to the bottom. The
right column becomes a Work/Files third column that absorbs the preview
pane, which is no longer an independent fourth region; the artifacts
workspace overlay folds into the Files entry, and stop control
consolidates into the input area with a light fast/slow-lane status hint.
Evidence: make test-frontend NOT_RUN at commit time; the run and its
outcome are recorded in the Dev task card before integration.
Impact: App.tsx layout and divider width tiers (work 280-560, files with
open preview 420-1100); store UI state rightTab work/files plus filesView
with syncFilesEntry replacing syncPreviewRail; Workbench dual entry;
PreviewPane gains a back-to-list control; TaskSidebar project switcher;
TopBar drops project identity; Conversation drops the header stop button
and gains the input status line; workspaces.ts drops the artifacts builtin.
Refs: three-column workbench proposal (2026-10-11), DESIGN.md 6/9.3
revision follows in the Dev repo.
Why: reproduced with headless Chromium - clicking an artifact row with no
conversation selected closed the workspace overlay and nothing else appeared.
requestPreview stores tabs under currentConvId ?? '_' while the render side
required a non-null currentConvId, so the preview pane never mounted in the
empty state. The empty state was itself a trap: currentConvId was not
persisted, so every reload landed there.
Evidence: vitest 85/85 (new preview-empty-state tests for the key contract
and orphan-tab merge); browser replay on the fixed build shows the preview
pane mounting with rendered docx content from the empty state and the
conversation restoring after reload (screenshots in the Dev task card).
Impact: previewTabsKey() unifies the read/write key; entering a conversation
adopts orphan '_' tabs; the last conversation id persists and restores once
on boot; deliverable cards toast when the artifact is gone instead of
silently doing nothing.
Refs: Dev task feature/empty-state-preview-fix; diagnosis session 2026-10-10.
Why: run.Usage now carries the WP6 split fields; the badge should show
them ('+last · cumulative · duration · tools', cache hits in the
tooltip).
Evidence: npx tsc --noEmit clean; npx vitest run 82/82 green.
Impact: display only.
Refs: Agent-System-Backend#96, N3 plan WP6
Why: .main { display: flex } overrides the UA [hidden] rule, so previewExpanded left the conversation column in the row and squeezed the preview.
Evidence: vitest test/previewfit.test.ts and test/design-guard.test.ts passed (10 tests). Headless Chromium at 1512x900: expanded .main is display:none and the preview slot is 1184px with the page centered (center delta 0); at 420px and 640px the wrapper stays column-width and the page stays left-aligned.
Impact: expanded preview fills the main row; docx pages center only when the column is wider than the page. Narrow-column fit scaling is unchanged. previewfit still returns 1 when available width is <= 0.
Refs: App.tsx hidden={previewExpanded}; styles.css .main and .docx-wrapper
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: The pane pinned .ui-fp to the column height, and the docx fit host then clipped overflow, so the right-hand preview could not scroll. The fullscreen DocViewer was a second shell around the same FilePreview.
Evidence: npx vitest run (17 files, 82 tests) and npx tsc --noEmit passed. Headless Chromium laid out a 1400px docx host inside a 764px pane (body scrollHeight 1400) and a pdf iframe that filled that pane.
Impact: .preview-pane-body is the scroll owner. Docx refit also watches page height. The overlay viewer is gone; expand/restore and text edit/save live on the pane.
Refs: Agent-System-Dev#196, Agent-System-Frontend#44
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: Headers, HITL details, tool lists, and status words used faint text, semantic colors were used as text, and the molv sidebar primary button matched the navy surface. There was no control for --ui-font-size.
Evidence: npx vitest run (17 files, 81 tests), npx tsc --noEmit, and knip unused exports 43 <= 43 passed in modules/frontend.
Impact: Content classes move to --text-dim or *-text. Sidebar active, focus, and the new-task button use the sidebar tokens. Settings gains 小/标准/大/特大, stored only in localStorage as ui.fontSize. Before: no font-size control and a 1:1 new-task button on molv. After: four local sizes and a light sidebar button.
Refs: feature/contrast-typography
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: tsconfig.tsbuildinfo is a local tsc cache, and a fresh typecheck rewrites it, which leaves the frontend submodule dirty.
Evidence: git ls-files still listed it after the ignore rule, and git status showed it modified after npx tsc -b.
Impact: The file remains on disk and is now ignored. No source or preview behavior changes.
Refs: feature/docx-paper-preview
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: tsc -b writes tsconfig.tsbuildinfo into the worktree, which showed up as a dirty submodule during the paper-preview check.
Evidence: git status listed tsconfig.tsbuildinfo as untracked after npx tsc -b.
Impact: The artifact stays local. No runtime or preview behavior changes.
Refs: feature/docx-paper-preview
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: An A4 page is wider than the preview column, and the page background followed the app theme, so body text disappeared in dark mode.
Evidence: npm test (17 files, 81 tests) and npx tsc -b passed in modules/frontend.
Impact: Docx pages stay on --paper with their own styles and shrink to fit the column. A column wider than the page, including fullscreen, keeps them at 100%. Before: section background var(--bg) and color var(--text). After: var(--paper) and var(--paper-ink).
Refs: feature/docx-paper-preview
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: tsc -b rewrote the tracked build info after the contract mirror changed.
Evidence: make build completed and left only tsconfig.tsbuildinfo dirty.
Impact: The feature branch working tree matches the production build.
Refs: .task/feature-sillytavern-review.md
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: Core is the authority for the shared types, and the section shape no longer needs its own export.
Evidence: make contracts copied modules/core/ts/types.ts. Frontend knip stays at 43.
Impact: Callers still read sections on the observation object.
Refs: .task/feature-sillytavern-review.md
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: Preview setup clears a node with innerHTML = '' before appending sanitized children, and the ratchet treated that space as a write.
Evidence: npx vitest run test/html-sinks.test.ts. Non-empty assignments still match.
Impact: The preview path can keep clearing nodes. Writing HTML strings in components still fails the test.
Refs: docs/records/2026-10-04-sillytavern-review.md
Why: Keys must be added without writing masks back, and a turn needs copy, exclude, and regenerate without deleting history.
Evidence: npx tsc -b. Session notes and candidate switches call the new conversation and message routes.
Impact: Settings gains key, lore, and slash-template panels. Excluded messages stay visible and are dimmed.
Refs: docs/records/2026-10-04-sillytavern-review.md
Why: The conversation and office fallbacks wrote marked output straight into the page, including converted docx HTML.
Evidence: html-sinks ratchet forbids new innerHTML writes outside @ui safeHtml.
Impact: Conversation keeps line-break rendering. Unsafe links are stripped after docx and pptx preview. dompurify is deduped with the UI package.
Refs: feature/sillytavern-review
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: tracked workspace writes need a visible way to return files to the state before a user message.
Evidence: the confirm lists the files the rewind API would restore or skip.
Impact: the control only calls the new checkpoints and rewind endpoints. Usage may include the model that served.
Refs: feature/durable-rewind
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: Plan, default, and auto-edit have to be visible where the user sends a message, and confirmation cards need to show the arguments.
Evidence: The mode control and card detail only use existing color, radius, and type tokens.
Impact: An empty mode still renders as 默认. Confirm cards use the wait color instead of the success color.
Refs: feature/permission-hooks
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: The phase type has to be consumed by the screen that branches on it, or the unused-export ratchet fails.
Evidence: knip stays at the existing baseline after the conversation annotates ShellPhase.
Impact: No behavior change.
Refs: feature/runstate-shell
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: The send button, stop button, and queued sends each looked at a different slice of run state, so a reconnect or a late assistant message could disagree.
Evidence: A depth-4 walk of send, HTTP results, SSE, reconnect, conversation switch, and flush keeps busy aligned with an in-flight run, hides the live bubble once an assistant message exists, and keeps one user message per request id.
Impact: The event listener list is exhaustive over the stream contract, including run.check. A disconnected stream shows 重连中.
Refs: feature/runstate-shell
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: Dead exports were unchecked, and async run state needs one owner.
Evidence: knip unused exports stay at 43. design-guard passed.
Impact: A ratchet on export count. No runtime behavior change.
Refs: feature/architecture-baseline
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: The pull request cannot merge while the head is behind main.
Evidence: origin/main is 539aae6, one commit ahead of this branch.
Impact: Keeps the live-run fix and the retried request-id fix together.
Refs: Frontend #38
Why: Stamping the user message with the run id made the live bubble look settled, and the composer stayed on 发送 until the next reconcile.
Evidence: npx tsc -b passed. vitest 75, including hasSettledReply and mergeStartedRun. On a mock server the button became 停止/排队 within 250ms and the reply grew while the run was open.
Impact: Composer, live bubble, and agent tracker only. A stored user message no longer hides the stream. Reopening replays from resumeSeq when the server sends it.
Refs: Dev fix/live-run-visibility
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: A busy 409 used to enqueue a new id, so the retry created a second user message after the server had already stored the first.
Evidence: vitest run passed, 13 files and 69 tests, including the outbox retry case.
Impact: Data layer only. sendMessage and outbox flush reuse the queued message id as requestId. No screen changes.
Refs: Dev feature/pi-durable-borrow
Co-authored-by: Cursor <cursoragent@cursor.com>