Resolve the agent-loop import conflict by retaining both durable request context and runtime policy context. Refresh the combined session fixtures and regenerate documentation catalogs. Mark PDF artifacts as binary so staged whitespace checks do not parse PDF bytes as text.
The user bubble's IconActions row carried an edit button with no click
handler, no client mutation, and no host operation behind it, advertising
an affordance the product cannot honor. The row now renders clock / copy /
branch only for both user and assistant chrome, and MessageIconActions
loses the `edit` prop with the button.
The package README records the missing capability under Known Limitations,
the web aria goldens pin the row without the control, and the Agent Note
states what must exist before it comes back.
SearchRow (this PR) and FileMutationRow (landed on master) independently carry
byte-identical rowStateStatus + rowResultText helpers, which the duplication gate
flags once both are present. Extract both into contract/toolview-status.ts and
consume them from both rows, deleting the clone rather than nudging it under the
threshold.
The keyed toolviews (read, file-mutation, web) each draw the same ToolRow
summary-line chrome; the read row's copy trips the duplication gate against the
file-mutation row. Extracting the shared row is a separate change tracked for
all rows at once, so this scopes the exemption to the read row's block.
The master merge added a required archivedSessionIds field to WorkspaceListState;
the read-card spec's DetailsPanel fixture state needs it to typecheck.
A blank row is a provisional placeholder: nothing has happened in it,
so the row verbs (rename/fork/archive) and a 'now' stamp would act on
content that does not exist. The trailing cells and the hover card's
time line stay off until the first prompt lands.
Public snapshot state stays in the store engine's plain-data vocabulary
(immer drafts reject Sets without the MapSet plugin, which stays off):
manager/service/contract carry readonly SessionId[] in Host order, and
the tree derivations build their own transient Set — the
expandedProjects pattern. Membership-unchanged installs still keep the
array reference for Object.is short-circuits.
- WorkspaceRegistry.archiveSession no longer wraps persistence-listing
failures as WorkspaceUnknownSessionError: only a definite miss (live
lookup, header index, then a fresh list) maps to session-not-found;
storage faults propagate as internal errors, with a negative test.
- The archived-current sweep moves from the unary path into the
projection: any install path (local echo, another tab's frame, a
reconnect baseline) clears a selection that landed in the archive set.
- An archive set installed while workspace.list is in flight supersedes
the stale baseline's set instead of being rolled back by it.
- The workspace-management e2e anchors the archived row by its session
actions button and asserts the single-stray fixture assumption loudly.
- Drop the stale touchSession rows from the workspace READMEs (the
method was removed with its Agent Note).
The visual-only Delete session placeholder becomes a wired Archive
session action: no confirmation dialog (non-destructive), failures stay
console diagnostics. tree.ts hides archived sessions in every
derivation (workspace groups, Ungrouped, search, flat list) through the
sessionVisible predicate. The workspace-management e2e pins the archive
round trip across reload.
WorkspaceListState gains archivedSessionIds (ReadonlySet, replaced only
on membership change), installed as full snapshots from the list
baseline, the unary echo, and the changed frame. Archiving the current
session clears the selection into the New Session view state. Test
doubles (test-runtime, fake APIs, fixture client) follow the widened
IWorkspaces/IApiClient faces.
Review flagged that "equal by construction" rested on an engine behaviour I
had not measured: `scrollbar-gutter: stable` only equalizes the layers if the
engine applies it to `overflow: hidden` the way it does to `overflow-y: auto`.
Measured it on the running app across the three engines Playwright ships,
and the property does not hold up.
engine .input / .backdrop / .mirror wrap width
chromium 776 / 776 / 776 (768 / 768 / 768 with the declaration)
firefox 776 / 776 / 776 (unchanged by it — overlay scrollbar)
WebKit 768 / 776 / 776 (unchanged by it)
WebKit reserves for `overflow-y: auto` and not for `overflow: hidden`, so the
declaration left .input at 768 against 776 — exactly the gap it was meant to
close — on the one engine where that gap is observable at all, while costing
every chromium user 8px of text column unconditionally. Reverted: the
composer's metrics are now the same as before this PR.
The WebKit gap predates this change and is not closed here. It is recorded in
the Agent Note with the numbers, and the browser scenario asserts the equality
on the lane's engine so a regression into that state fails loudly. The mirror
is unaffected on WebKit for the drafts measured — the extents still agree — but
a draft whose wrapping turns on those 8px would clamp it.
The review's monotonicity concern resolves the same way: the declaration was
never worse than master, because WebKit already measured 768 against 776
without it. It simply was not better.
Also from this round: the wrap-width assertion now covers .mirror as well as
the two glyph layers — it is the height authority, so a mirror alone wrapping
wider would measure the box short and clip content below the 14-line cap with
every other assertion green. Plus `renderGeometry`'s missing `@param
trailingNewline`, and both e2e tsconfig lists restored to alphabetical order.