The previous hygiene fix re-serialized with json.dumps defaults (spaced
separators), leaving the line byte-identical; explicit compact
separators make the header-scrub guard pass.
deferRegistration() stays the shipped form; the note pins the follow-up
direction (bridge declarations into slot:<name> services, migrate
registrants to nested ctx.inject, delete the helper) and the boundaries
a separate PR must settle.
The re-records for the SDK-prompt change had harvested live v4-pro
headers while every replay overlay pins v4-flash, so keyless replay
diverged on provenance; keyless refresh reconciles the affected
scenarios (dispatch-start pairs preserved).
ds-review-bot findings: the browser e2e's error-state check now requires
at least one error sub-row (was >= 0); the runtime README documents the
codeDispatches snapshot contract and the ui-conversation README the code
variant + nested sub-row semantics.
ds-review-bot findings on the parallel bridge: sub-dispatches now run
through the registry's staged scheduler view (the loop's own seam) —
ordered prepare (pre-execute/guards) at submission-ordered start time,
only the dispatch/body stage overlapping, and a head-of-line commit
cursor running post-execute, context deferral, and the settle event in
submission order (new spec pins post order + context order under
out-of-order completion). Queued dispatches reclassify via
executionMode() immediately before starting, so a registry mutation
while queued flips them exclusive (native lazy-reclassification
semantics). Config and tool catalogs regenerated; the tool-catalog
metadata now names the start/settle pair and the scheduling contract.
ds-review-bot findings: the packaged Python runtime smoke's scripted
run_code call gains the required description; the ToolDefinition JSDoc
and the Code Mode foundation note (both languages, pair re-recorded) now
state both required parameters; the cordis-dynamic-toolchain fixture's
request/header line is re-compacted so the header-scrub hygiene guard
passes (my earlier patch had re-spaced it). The TUI terminal fixture was
already regenerated from keyless replay in the previous commit.
The scripted (non-recorded) fixtures' run_code calls predate the required
description parameter, so replay rejected them at validation before any
dispatch: patch the scripted programs' args (tool/call, message blocks,
and chunk deltas together) and refresh goldens keylessly. Also picks up
the v4-pro re-records of the code-mode scenario pair whose live model
drifted from the overlay pin, and drops tmp-path churn.
One tiny recorded text turn drives three whole-page concerns:
- workspace flow over the real wire: the empty-state hero's first send
materializes a real Workspace + Session (the jsdom workspace-flow suite
pins this state machine over the fixture client; this scenario pins it
through HTTP RPC + SSE + the gateway). Durable proof: the session
header's cwd is the create-by-name target <workspaceRoot>/workspace.
Adds the hero waiting-state aria golden.
- reload recovery: collapse the sidebar (persisted dsh.layout.panels),
page.reload, and the surface comes back whole from persistence alone —
layout collapsed, selection restored (dsh.sessions.current), the
recorded turn re-rendered from session.history with zero model calls
(the drained replay cursor makes any stray request fail loud at close).
- dark mode: no product control flips the theme yet, so the scenario
drives the ThemeService's entire DOM contract — body[data-ds-dark-theme]
— and pins the shipped cascade: the alias token flips, a painted surface
repaints, and removing the attribute restores the light sample exactly.
TODO(web-theme-gesture) upgrades to a real settings control; no theme
golden per the lane's scope ruling (aria is color-blind).
Agent Note scenario list extended in both languages; pairing re-recorded.
The bridge replaces its serialization queue with a pool that reuses the
native concurrency contract: submissions classify through
registry.executionMode (fail-closed isConcurrencySafe), start strictly in
submission order, overlap up to the validated maxParallelSubCalls config
(default 10; 1 restores serial), and exclusive calls drain the pool, run
alone, and bar later calls. Each started sub-call logs a
tool/code-dispatch-start event at pool entry; the existing
tool/code-dispatch settles the pair (started ⇔ settles exactly once;
abandoned queued calls log neither). SDK prompt guidance now states the
true Promise.all contract — re-recorded across every code/both-mode
snapshot (plus the stale cordis-dynamic-toolchain fixture gaining the
required description arg).
Client: CodeSubCall widens to RunningToolCall | ToolResultNode — starts
land the running shape (rows wear the native running ring), settles
replace in place preserving start order, callTime pairs to the start
time. Fixture emits start/settle pairs; jsdom pins the running sub-row;
runtime specs pin in-place settlement and out-of-order completion.
One two-turn seed (turn 1: bash + two parallel reads in a single assistant
message; turn 2: a markdown-heavy reply) rendered cold through the
seeded-history pattern — zero model calls — serving four surfaces:
- sidebar search: client-side title filter; asserted only after the durable
title lands with the attach baseline (a cold SessionSummary carries no
title — search matches the displayTitle the user sees). Negative query
empties the tree, positive narrows to the match + its force-expanded
group, clear restores.
- Trajectory tab: turn sections, the step group's tool mix ('bash read×2'),
and a view-area aria golden.
- Waterfall tab: span stats header + one lane per span. The P-I fold counts
a turn-0 prologue span (only assistant/steering nodes carry a turn
number) — pinned as-is; real spans are P-III per the view's ledger.
- details column: the bash toolview row routes click to openDetails;
open/closed is asserted on the frame's data-details-collapsed attribute
because close collapses the grid column to width 0 without unmounting
the subtree (hidden, not absent, is the contract).
Agent Note scenario list extended in both languages; pairing re-recorded.
The five settings-surface registrants carried near-identical
spec-check/ledger-judge/subscribe scaffolding (three jscpd clones);
ui-slots now owns deferRegistration() — ledger-judged presence, refresh
for registrant-localized labels, one-call disposal — and every
registrant shrinks to its registration body.
Both languages: the three new scenarios (live-interactions overrides,
question-composer takeover, wire-level steering), the product-delta list
({ patches } override form, the carried-failure fix, the llm-retry row),
two new Deferred items (web error surface, composer steering gesture),
and de-hardcoded scenario counts; pairing re-recorded.
The client indexes tool/code-dispatch events into
ConversationSnapshot.codeDispatches (parent callId -> ToolResultNode-shaped
sub-calls; live mux and history replay build the identical index). ChatView
renders each run_code parent as the new code variant (description summary,
program as the expanded monospace body) with its sub-dispatches as
always-visible indented rows — every sub-row dispatches through the SAME
keyed conversation.chat.toolview hole with the same GenericToolCard
fallback, so custom registrations (bash sample) take over sub-rows exactly
as top-level rows. The details panel resolves sub-callIds to full logged
args and complete output through the native path.
Evidence: fixture turn 64 + built-bundle jsdom snapshot, real-machinery
jsdom suites (nesting, error state, details, running parent, reference
stability), and a recorded code-mode browser e2e round (keyless replay +
aria golden). Scaffold gains a toolsMode patch knob.
Five browser e2e scenarios over the existing keyless lane, one recorded
base fixture per spec family:
- live-interactions: one tool-free recorded turn + per-run override
sidecars authored in the spec (content single-sourced from the fixture
via deriveReplayScript, minted into a spec-owned temp dir). Cancel uses
a hang patch with a readyFile marker — the marker proves the stream is
parked mid-turn before the Stop click, so mid-stream cancellation is
deterministic by construction (turn/end 'aborted', composer re-enabled).
AUTH pins the non-retryable path: turn/end 'error', zero llm/retry
events, composer recovers; FIXME(web-error-surface) marks the found
product gap (no error copy renders — the client consumes no agent/error
frames and a pre-chunk failure freezes no partial). SERVER retry appends
the fixture's own success after an injected throw and proves llm-retry
end-to-end in the browser via the durable llm/retry record.
- question-composer: the shipped ask_user_question takeover blocks the
turn mid-step on the real userInteraction seam; the test answers through
the composer (the one sanctioned model-content-reactive drive step: the
turn cannot complete without it) and the tool result carries the answer.
Adds the composer waiting-state aria golden.
- steering: steers mid-turn while the composer blocks the step (the
deterministic mid-turn window). The steer rides the real wire
(session.prompt mode:'steer' POSTed from the page; the locked composer
has no steering gesture yet — TODO(web-steer-composer)); downstream is
all product: gateway -> Agent.steer -> step-boundary drain -> durable
steering/message -> SSE -> badged interjection bubble. Record mode
rejects a fixture whose live reply ignored the steer.
Scaffold gains the replayOverride passthrough; specs register in both
tsconfig planes (client exclude, host include).
The ReplayConfig.overrideFile JSDoc still described only whole-script
replacement; it now names both sidecar forms and links ReplayOverrideDoc
(config catalog regenerated: source line shifted).
The web tree had no transient-failure recovery around the loop's model
calls; the TUI agent-spine composition already mounts llm-retry. Same
defaults (2 retries, 500ms->10s backoff). The browser e2e retry scenario
drives it end-to-end: an injected SERVER throw at call 0 recovers through
the durable llm/retry record and completes in the transcript.
markLlmAdapterFailure gated the own-`failure` data property on instanceof
HarnessError, which drops the validated facts exactly when class identity is
lost — two copies of this package in one process (e.g. a source-plane replay
harness throwing into a lib-plane boot) make the replay-thrown LlmError's
SERVER/AUTH code arrive as UNKNOWN and defeat llm-retry's retryable-code
match. The snapshot is already validated field-by-field and cross-checked
against the error's own code, so honor it on any Error.
The override sidecar now accepts { patches: [{ at, entry }] } alongside the
legacy whole-script ReplayEntry[] replacement: the JSONL-derived script is
kept and only the named call indexes are swapped (at == length appends, for
a retry attempt following an injected transient throw). Out-of-range or
non-integer indexes fail loud with the derived length in the diagnostic.
This is the mock-LLM error capability the web e2e scenarios drive: 'call N
throws AUTH/SERVER, everything else replays as recorded'.
The ui-layout apply bench provides a real LocaleService before the
theme plugin boots (ui-theme now injects slots/locale to register its
Appearance row); drop locale's unused clsx dependency.
Locale and ui-theme apply coverage on a real Context + SlotCore:
dictionary assembly, declaration-aware registration both ways,
inject-time getter re-sync, service write-back through the event flow,
HMR collapse recovery, and teardown reclamation. Four settings-surface
packages sit at full per-file coverage.
Generated docs follow the ui-models rename and the removed
ui-settings-general package; the English note side picks up the
feature-owner self-registration doctrine.
Settings collaboration direction (recorded in the note): the shell only
provides composition faces — feature plugins register themselves. The
General section moves into the ui-settings shell (order 0, skeleton
rows) and declares the settings.general.item list slot; locale registers
the Language row and ui-theme the Appearance row (each with its own
store mirror, dictionaries, and ledger-judged deferral); the
ui-settings-general package is gone. ui-settings-models becomes
ui-models — a feature package that contributes its Settings section
rather than a settings-owned satellite. The item-slot SlotMap entry is
authored in the ui-settings contract and repeated verbatim in
locale/ui-theme (reference-cycle avoidance; declaration merging keeps
the copies identical).