Why: a lost write response was keeping the old duty version, so the next save replayed it, and a busy save could stay locked if another request advanced the sequence.
Evidence: SELF vitest duty-draft 6 passed, tsc passed, knip 43, Playwright duty flows 3 passed.
Impact: an unknown save reloads server roles, confirmation resets, and busy clears even if a later read is discarded.
Refs: docs/proposals/2026-10-15-rdm-duty-matrix-rework.md
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: project settings must keep the shared duty draft and must not regain template document creation from main.
Evidence: SELF vitest 292 passed, tsc --noEmit passed, knip unused exports 43.
Impact: the duties tab stays assignment-only while conversation ordering from main is included.
Refs: docs/proposals/2026-10-15-rdm-duty-matrix-rework.md
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: Completion or progress from an earlier task could appear in the process of an unrelated newer answer.
Evidence: The new ownership regression fails before the guard and passes afterward; the frontend suite, TypeScript and unchanged export gate pass.
Impact: Project child progress only into its originating live turn while still reconciling background results.
Refs: feature/workbench-flow-completion chronological display requirement
Why: Full execution history must retain outputs after the 500-event API page boundary.
Evidence: Ordered 502-event replay and nonadvancing-cursor rejection tests pass.
Impact: Add regression coverage only; production source is unchanged.
Refs: feature/workbench-flow-completion review testing gap
Why: A rejected result-reference request could discard the user text or uploads after the composer cleared.
Evidence: 286 frontend tests, TypeScript and the unchanged unused-export gate pass; mixed-input browser regression preserves the draft.
Impact: Validate incompatible inputs before clearing, retain failed pending input with its request identity, and require explicit retry while other messages can continue.
Refs: feature/workbench-flow-completion review frontend-races finding
Why: the settings page was mixing duty assignment with whole-document review and chapter objects. The three views need one draft and one save check.
Evidence: SELF vitest run of the frontend suite, 278 tests passed, including duty-draft and design-guard.
Impact: the duties tab assigns existing documents only. Submit, approve, reject, and final stay out of this page. Commands that are not ready keep the tab hidden.
Refs: feature/rdm-duty-matrix
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: Repeated progress and coupled scrolling obscured chat, and task choices lacked a reliable independent interaction path.
Evidence: 285 frontend unit tests and 23 browser scenarios pass locally before the shared event-loader extraction; final combination checks follow in Dev.
Impact: Coalesce cumulative progress, retain execution records, show timestamps and quiet notifications, support versioned work actions and explicit result references without automatic chat backfill.
Refs: feature/workbench-flow-completion
Why: the duties tab only listed existing documents — rdm.docs.instantiate
had no UI entry, so a fresh project showed an empty duties tab with no
setup path (owner trial feedback 2026-10-15).
Evidence: new docs-instantiate-params tests green; full vitest run shows
only the 12 pre-existing conversation-work failures also present at clean
HEAD; design-guard green.
Impact: duties tab gains a template picker + title input wired to
rdm.docs.instantiate (backend command rdm.docs.templates lists published
identities); instantiation refreshes the catalog and selects the new doc.
Refs: Agent-System-RDM docs/records/dhf/u4-header-footer-slots.md
Why: Independent review found component-local color derivation, a private transition, and missing dark/molv coverage in the visual candidate.
Evidence: Frontend design guard passes and 19 Playwright scenarios cover light, dark, molv, and 320-1920px layouts.
Impact: Keeps the approved visual direction while moving color ownership to @ui tokens and removing private motion.
Refs: Agent-System-Dev feature/workbench-visual-redesign
Why: Status words shared with a final reply could suppress a child completion record.
Evidence: 272 frontend unit tests, build, and 15 isolated browser scenarios.
Impact: Tag client-side collaboration replay so partial-delta deduplication preserves agent notes.
Refs: Agent-System-Dev feature/work-companion-visibility UI1
Why: A dropped delta batch can leave a short event prefix next to the complete saved message.
Evidence: 271 frontend unit tests, build, and 14 isolated browser scenarios.
Impact: Suppress overlapping partial replay text and thinking while retaining saved content.
Refs: Agent-System-Dev feature/work-companion-visibility UI1
Why: Event replay could hide saved retry notes and leave completed cards outside the active work filter.
Evidence: 270 frontend unit tests, build, and 14 isolated browser scenarios.
Impact: Merge replay into saved history, retain child progress, and locate cards under the right scope.
Refs: Agent-System-Dev feature/work-companion-visibility UI1 UI2
Why: Fast and slow channel cards duplicate across panes and completed replies hide process output.
Evidence: npm test; npm run build; 12 isolated Playwright scenarios with reload and responsive widths.
Impact: Preserve ordered folded process history, load durable run events, and give work cards one detailed pane.
Refs: Agent-System-Dev feature/work-companion-visibility UI1 UI2 UI3
Why: Complete the authorized export entry while preserving current main project and session behavior.
Evidence: SELF full frontend tests and build, 263 unit tests; deferred browser races reproduced then all 6 passed. Raw records stay outside source until Dev task closure.
Impact: Export callbacks are invalidated on project, identity and unmount changes. Command readiness and current main security paths remain intact.
Refs: Dev PR #488; Frontend PR #73; user takeover authorization on 2026-10-14
Why:
Project readiness is a write gate. Applying it to member, permission, and
document status queries hides history that the backend intentionally keeps
readable after archival or closure.
Evidence:
SELF archived and closed read regressions failed before the fix. Full npm
test, npm run build, and git diff --check passed with the amended code.
Receipts: /tmp/project-member-frontend-archived-read-red-20261013.json and
/tmp/project-member-frontend-archived-read-green-20261013.json.
Impact:
Resolve canonical project IDs separately from command readiness. Preserve
known read commands and existing settings tabs for historical projects;
keep mutations and new work blocked with existing disabled controls.
Server authorization remains authoritative.
Refs:
Dev project-member-access Task 4; independent Frontend review P2
Why:
An identity can change after an operation has passed its first response guard.
Later project loads, cleanup calls, and attachment refreshes must not reopen
private context or return the previous account's result to the new session.
Evidence:
SELF regressions failed before the guards: delayed project opening, task
creation success, completed-card cleanup, and upload artifact-ID return.
SELF npm test, npm run build, and git diff --check passed; full command
receipt: /tmp/project-member-frontend-final-checks-20261013.json.
Impact:
Guard post-await continuations with the same identity epoch. Preserve the
original server-side result and ignore stale client projections; do not undo
the previous account's already completed work.
Refs:
Dev feature-project-member-access implementation plan Task 4
Why:
Project members need RDM commands to address the registered domain project.
Failed project states and responses from a previous account must not create
work, report a rejected mutation as successful, or restore private content.
Evidence:
SELF npm test: 32 files and 251 tests passed, including project command,
mutation rejection, archived history, and delayed account response coverage.
SELF npm run build and git diff --check passed. Original regressions were
observed before implementation; root owns composition and independent replay.
Impact:
Keep host IDs for conversation and base settings APIs; send the decorated
domain ID to RDM project commands. Reuse existing sidebar, settings and toast
states. Reset identity projections and invalidate old asynchronous responses.
No deployment, database change, push, merge, or workspace cleanup.
Refs:
Dev feature-project-member-access task card and implementation plan Task 4
Why: The 2026-10-13 login contract makes username/password the default
login, replaces the browser ask_ tab with a one-time recovery key
entry, requires the forced set-password gate to drop the current
password field, and routes admin password recovery through admin-issued
login keys instead of direct password resets.
Evidence: vitest 218 passed, npm run build OK, check-knip 43<=43,
design-guard green (SELF, local run in task worktree).
Impact: LoginPage gains a redeem-only key tab (no key persistence);
ChangePasswordGate shows server-confirmed owner plus new/confirm only
and returns to the login page after success (reloginRequired); App
gates on sessionScope=set_password_only; UsersPanel replaces reset
password with issue/revoke login key UI showing plaintext once.
Refs: Dev task feature/svc-login-recovery-flow; backend companion
commit 467718a.
Why: when rdm.role.list is rejected (e.g. the operator lost the RDM
domain-admin ledger to an acceptance bootstrap), the roles table spun on
'加载中…' forever and the banner dumped the raw 400 receipt JSON.
Evidence: vitest test/rdmroles-reject.test.ts (SELF, run below); manual
repro on 8788 dev 2026-10-13 before the ledger fix.
Impact: placeholder row comes from rolesListPlaceholder (failure row when
a fetch rejected), domain-admin denials map via describeRoleListError to
a readable message naming the rdm.perm.transfer channel; other errors
pass through. No style tokens touched (design-guard clean).
Refs: Dev task feature/rdm-admin-lockout-recovery (R3)
Why: Ordinary explanations were folded with tool activity and the oldest result was selected as current work.
Evidence: Findings #5/#6 red-to-green actual-component and live-projection checks are retained; current full Frontend suite passes 210 cases.
Impact: Preserve business text, errors and file references in reading order; retain active/pinned priorities and newest-first host ordering.
Refs: ce-code-review 20261012-165912-cb241b46 #5/#6, UI03/UI05
Why: Background frames blocked terminal reconciliation, stale failures left confirmations busy, and delayed page hydration changed mobile navigation.
Evidence: Review findings #1/#2/#3 have recorded red-to-green checks; all 210 Frontend tests, tsc and knip pass, plus six real navigation browser checks.
Impact: Keep sequence high-water and operation ownership, merge observations by object, and use an explicit preview-opening intent.
Refs: ce-code-review 20261012-165912-cb241b46 #1/#2/#3, UI04/UI09/UI10/UI11
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: auditors need to generate and download a watermarked report from the overview, and that must not appear when the export commands are off or change whether the workspace itself opens.
Evidence: SELF npm test, 138 passed. Playwright download case is in e2e/rdm-audit.playwright.ts and runs under scripts/e2e.sh.
Impact: the overview shows type, generate, draft confirmation, watermark, sha256, expiry, and download only when the three export commands are enabled.
Refs: RDM pull request 301
Co-authored-by: Cursor <cursoragent@cursor.com>
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 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: 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: 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: 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: 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: 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: 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: 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: 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: 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: 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>
Why: Deliverable cards appeared as soon as a file was registered, and the last draft was shown as the answer before the run had finished composing one.
Evidence: vitest run test/live.test.ts test/toolkind.test.ts test/messageparts.test.ts test/design-guard.test.ts
Impact: Cards wait until the run ends. A finalizing phase keeps earlier text in the process block, and check rows render there.
Refs: feature/final-reply-compose
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: Streaming tool arguments looked like a frozen cursor, and a failed run folded the only narration into the collapsed process block.
Evidence: npx vitest run in modules/frontend, 13 files, 66 passed. npx tsc -b reports only a pre-existing missing docx-preview module.
Impact: Live tools move composing to running to done with arguments and output; finished runs lift the last narration; same-run errors and duplicate files collapse into the reply.
Refs: feature/stream-display-overhaul
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: The first S4 pass makes the project the navigation context, keeps deep views in one overlay, and leaves domain panels empty until a plugin declares them.
Evidence: npx tsc -b and npm test (61 passed) in modules/frontend.
Impact: Top bar, project sidebar, inbox all/todo filter, one-way scroll sync, drag-and-drop on the whole chat column, and local molv/system themes.
Refs: feature/s4-shell-overhaul
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: A background child should not look like the conversation is busy, and its completion note needs a compact row instead of a full assistant bubble.
Evidence: vitest run passed, including design-guard. tsc -b passed.
Impact: The stop button cancels the conversation run. System notices fold with the shared Collapsible.
Refs: feature/agent-harness-p3b
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: Process output folded on every text delta, successful tool
results disappeared after refresh, and generated files stayed plain
text instead of a card that opens a closable preview.
Evidence: npx tsc -b --noEmit (clean); npx vitest run (51 passed).
Impact: Live work stays expanded until the run ends, then folds to
one worked-time line. File cards open a per-conversation preview pane.
docx renders page by page, with mammoth if that fails.
Refs: feature/chat-timeline-preview
Co-authored-by: Cursor <cursoragent@cursor.com>
Why: a busy conversation rejected further input, and the file list lived
only behind the workspace overlay.
Evidence: npx tsc --noEmit and vitest 42 tests, including outbox
append/edit/promote. The queue uses Collapsible and design tokens.
The files tab reuses ArtifactsPanel.
Impact: while a run is active, Enter queues the draft (edit, delete, or
send-now). Finished and failed runs drain the queue. HTTP 409 also
enqueues instead of only toasting. Backend serialization is unchanged.
Refs: task feature/input-queue
Co-authored-by: Cursor <cursoragent@cursor.com>