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>
Why: tool artifacts were only reachable via the collapsed process
section or the artifacts workspace; users had to read model text to
learn a file existed. Deliverables should appear directly in the
conversation as an openable card (ZCode/Kimi pattern) that opens the
right-rail preview.
Evidence:
- Conversation.tsx artifact_ref renderer upgraded from a small chip to
a deliverable card (icon + name + kind/size meta + preview affordance
+ single download action); whole card click = rail preview (the one
preview placement, fullscreen still reachable from the rail header)
- live.ts projects artifact items as content parts pinned after the
reply text, isomorphic with the new llm.go persisted order; card is
visible while streaming
- styles: deliverable-card uses tokens only (radius-lg card, bg-raised,
hairline border, mk-rise-in entrance); design-guard suite green
- vitest 40/40 (live.test pinned-tail case updated, messageparts.test
covers new persisted order plus legacy inline order); tsc clean
Impact: every generated artifact (docx/pdf/image/…) now surfaces as an
in-chat card immediately, click-to-preview in the right rail with real
formatting for styled docx; workspace panel (⌘1) unchanged as the
file-system fallback.
Refs: task feature/deliverable-docx-r1 (backend: write_docx + pinned
artifact_ref)
Why: Approved redesign phase 4: process folds, long-reply folds, thinking
blocks and context-observation fold move to the @ui Collapsible primitive
(two-layer height+fade animation, delayed unmount, open-state memory);
tool calls render as ToolBlock rows with running sweep and paired results;
the live bar gains the ZCode worked-time line with sweep; input placeholder
states the backend's honest busy semantics (serialized per conversation).
Evidence: npx tsc -b clean; npm test -> 39 passed (details-guard included);
npm run build succeeds; combined make test recorded in the Dev task card.
Impact: Conversation.tsx replaces all <details> usage (guard-enforced);
ProcessParts pairs tool_call with its trailing tool_result into ToolBlock;
styles.css rewrites fold selectors for the Collapsible structure and adds
message mount animation (mk-rise-in); no contract or API changes.
Refs: Agent-System-Dev task feature/ui-tokens-v3 (phase 4).
Why: Phase 1 of the approved frontend redesign: re-skin the shell to the
Zai look (floating rounded panels on an inset base with 4px gutters),
invert primary buttons to the mono scheme, and move every font size onto
the --fs-ui-* scale. Also wires @ui/motion.css and replaces local
keyframes with mk-* utilities.
Evidence: npx tsc -b clean; npm test -> 38 passed (new host-side
design-guard ratchet); npm run build succeeds. Combined Dev make test
recorded in the Dev task card.
Impact: styles.css fully re-tokenized (panel borders/radius, primary
button color-mix hover, login brand panel in near-mono navy); inline
fontSize literals in components replaced with scale tokens except one
decorative glyph in the ratchet baseline. No component class names or
behavior changed.
Refs: Agent-System-Dev task feature/ui-tokens-v3; DESIGN.md (parent repo).
Why: the merge commit left tsc broken in two spots - an artifact.created
handler still pushing to the removed LiveState.parts, and main's newer ui
icons not yet checked out in this worktree; also Part was imported unused.
Evidence: artifact.created now appends an artifact LiveItem (process=true,
matching the backend's ae8e5d0) projected to artifact_ref by
liveToMessage; new test asserts it lands after its tool call. tsc -b exit
0 after initializing the ui submodule checkout; vitest 33/33.
Impact: live artifact chips render inside the process stream and fold on
reconcile; no functional change elsewhere.
Refs: feature/chat-process-split-r1
Why: main advanced with PR #15/#16 (part-order preservation, artifact
downloads, cross-session UI); task-sync requires the branch to carry it.
Evidence: resolution keeps the arrival-ordered items stream from this
branch (tool-driven process marking, pure/testable logic in live.ts) and
adopts main's rendering and ids: groupParts in-place process blocks,
real tool callIds on live tool parts, messageparts utilities, and the
restored phase-driven showProcessInline predicate alongside the CF0
long-reply excerpt that main's rewrite had dropped. vitest 32/32
(includes main's messageparts suite and this branch's 12 live cases);
tsc -b clean.
Impact: single coherent live pipeline - items accumulate in event order,
liveToMessage projects Parts with tool-driven process marks, rendering
folds consecutive process blocks in place; responding still collapses
the process area (Cursor-style) as originally reviewed.
Refs: feature/chat-process-split-r1
Why: liveToMessage emitted all text buckets then all tools, while the
persisted message interleaves per turn (thinking, text, calls), so parts
reordered on reconcile with 2+ tool turns. Commentary stayed in the reply
area until the next turn's text bucket appeared, because the process flag
was positional (i < length - 1) instead of tool-driven.
Evidence: LiveState now holds an arrival-ordered items stream
(thinking/text deltas merge into their last segment; tools land in place),
so event order - which matches the backend's per-turn append order - maps
1:1 onto persisted parts. A text segment is process iff a tool.call lands
before the next thinking/text segment, aligning with the backend's
Process: len(calls) > 0; the collapse predicate moved to testable
showProcessInline. Long replies (>800 chars) now show a 100-char excerpt
and label the count as Markdown source length. vitest 27/27 pass (was 5
live cases, now 12 incl. multi-turn order, immediate process marking,
collapse predicate); tsc -b clean.
Impact: streaming UI no longer reshuffles parts across turns or on final
reconcile; tool-turn commentary folds into the process area as soon as the
tool call arrives. Residual edge (documented in live.ts): a silent
tool-only turn with no text and no thinking attributes its call to the
previous text segment.
Refs: code review of feature/chat-process-split-r1 (2026-09-30)
Why: AssistantMessage reordered a message's parts by the process flag,
so tool calls floated above the text that surrounded them instead of
appearing where they actually ran; live streams had the same defect via
a fixed template order and never showed artifacts mid-run. Generated
files (e.g. meeting-minutes docx) had no visible download path, the
artifacts panel was a bare list, DocViewer nested a modal inside the
overlay, and settings rows used a legacy grid with a floating save
button.
Evidence: messageparts.ts adds groupParts (order-preserving grouping of
consecutive process parts, unit-tested) plus humanSize/artifactIcon
helpers; Conversation renders blocks in original order and the artifact
chip becomes icon + open + download; LiveState.parts accumulates events
in arrival order including artifact_ref so live view matches the
persisted message; ArtifactsPanel gains search/kind filter/upload and
per-row preview/download/delete-confirm; DocViewer is a single-layer
OverlayHost with pdf iframe, csv/json monospace, and a binary info card
with a download CTA; SettingsModal migrates to @ui SettingRow with the
save button pinned in the shell actions bar; inbox cards receive the
docBridge so result cards can open artifacts. tsc clean, vitest 20
passed, production build succeeds.
Impact: message timelines read in true execution order during and after
runs; every artifact is previewable and downloadable from the message
chip, the workspace panel, and the viewer; settings render on the fixed
two-column shell.
Refs: task feature/chat-order-artifact-files (ui# c3e1f3b backend#
44b51fa).