CI's full-tree coverage flagged three untaken paths this PR introduced:
- shapeDispatchLog's catch (a throwing tools/code-dispatch-log listener
must be contained — the settle event logs the unshaped content);
- the spill listener's flatten-decline arm (non-text sub-result content
passes through unchanged);
- the generated scope-key extractor row for tools/code-dispatch-log
(registered in the scope invariant matrix like the other tools events).
Responding to ds-review-bot on #664:
- SubSpanLane gains a 'timing' discriminant (measured | running | unknown).
A settle-only replay entry (callTime null, start outside the window) was
previously indistinguishable from a measured 0 ms span; it now renders
hollow with a 'duration unknown' hover title, and durationMs stays null
for anything unmeasured. Pairs with the client-runtime fix that stopped
fabricating callTime = settle time (826c3696a on the live-parallel PR).
- The built-client Code Mode fixture snapshot now switches to the
Trajectory and Waterfall tabs and pins the assembled rendering: three
Sub cells with real +0.8s durations and three measured lanes with their
hover titles — product-visible coverage through the real bundle graph,
not just package-level jsdom fixtures.
Agent Note (both languages) updated for the timing contract; pairing
re-recorded.
Both ds-review-bot findings were real:
- markLlmAdapterFailure's carried-facts cross-check read error.code
directly; a foreign Error with a valid own failure payload but a
throwing code accessor would replace the original adapter error with
the accessor exception, breaking the error-identity guarantee. The
read now goes through foreignErrorCode(), which contains the trap and
falls back to the normalized snapshot (test: hostile code accessor
beside a valid failure payload -> original identity kept, UNKNOWN
facts).
- live-interactions' afterEach caught scaffold.close() into undefined,
silently disabling ReplayHandle.assertConsumed() — the fixture-drift
tripwire — and hiding cleanup defects. Teardown now runs every step,
collects failures, and rethrows (AggregateError when several).
Responding to ds-review-bot on #664 (root cause lives here): when a history
window carries a tool/code-dispatch settle without its paired start, the
runtime fabricated callTime = settle time, so downstream duration views
presented a measured 0 ms. Match the native tool-result contract instead —
callTime: null = unknown — and pin it; the trajectory cell already renders
null as the em dash, and the waterfall gains explicit unknown handling in
its own PR.
The static CI gates run per-branch on the merged tree: the cordis
catalog/api, config-catalog, and type-equiv manifest updates for the
tools/code-dispatch-log waterfall and CodeDispatchLog payload previously
landed only on the shiki branch (09734f23b); this branch's own tree needs
the same regenerated outputs and manifest entries.
The coverage gate flagged three untaken paths in the bridge scheduler:
- the exclusive-head inFlight re-check was dead (the shared guard above
already returns for an exclusive head with any in-flight sibling) — removed;
- the commit-cursor undefined-dispatched break was structurally unreachable
once entries join commitQueue only after start() ran synchronously —
reordered the pump so the invariant holds by construction, annotated;
- the finish (final-result) commit arm and the pump re-entry guard gain a
covering test (throwing tools/pre-execute listener) and a defensive
annotation respectively; mid-run unregistration test renamed to match its
actual post-result settlement path.
Also covers the direct-construction maxParallelSubCalls default (index.ts)
and commits the regenerated persistence catalog for the new dispatch pair.
ui-sidebar shell landed on master (#643: geometry-only shell, the
browsing region moved to the sidebar.workspaces slot); this branch's
sidebar.settings foot seat re-applies on top — the hardcoded foot row
becomes the seat, the seat rides the railIn crossfade, and the shell
spec's renderSlot stub key-splits region vs settings.
Every spec now commits at least one golden and the interactive ones one
per distinct end-state (nine new .expected.md):
- live-interactions: cancel.expected.md (frozen partial + 已停止 marker),
error-auth.expected.md (the prompt bubble alone — the committed artifact
of the web-error-surface gap, the diff that flips when error rendering
lands), retry.expected.md (indistinguishable from a clean completion —
retries are deliberately invisible in the transcript).
- question-composer: answered.expected.md (the question resolved into its
tool round trip plus the final reply, takeover gone) beside the existing
waiting-state golden.
- steering: mid-steer.expected.md pins the accepted-but-INVISIBLE state
(the loop drains steering only at the step boundary, so no interjection
bubble exists while the question still blocks — if the client ever
renders pending steers eagerly, this golden flips first) and
settled.expected.md the badged bubble plus obeying reply.
- navigation-panes: waterfall.expected.md and details-open.expected.md
(tool-name header, Input args, Output result) beside the trajectory one.
- lifecycle-chrome: reloaded.expected.md — rendering the same settled
transcript from persistence alone IS the recovery claim.
Fixture inventories extended to the new closed sets; the Agent Note's
expected-outputs policy updated in both languages (per-end-state goldens
for interactive scenarios), pairing re-recorded.
The shell is now a pure composition face: no dictionaries, no locale
dependency, and three new chrome content seats (settings.trigger /
settings.header / settings.close) whose slot content also carries the
accessible names (trigger text, dialog aria-labelledby, visually hidden
close label). ui-settings-general returns as the owner of copy that
belongs to no single feature: chrome content, the General section with
its item slot, and the settings dictionaries. Slot types split homes —
trigger/header/close/section live in the shell contract; the
settings.general.item entry moves to the locale package (the common
dependency of every item registrant), with ui-theme consuming it
through a re-export seam; the verbatim duplicate merges are gone and
the dependency graph is a clean DAG.
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.
Review feedback (tianyicui, PR #657 inline): the missing-service message
should mention dsh-tasks, which defines ctx.tasks, rather than promoting a
specific backend. The seam's own surfaces (README, the direct-mount fence)
keep pointing at implementations, so the pointer chain still lands on
dsh-tasks-local without the producer strings going stale when another
backend becomes the recommended default. Agent Note updated accordingly
(en+zh, re-recorded).
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).
The static CI gates run per-branch on the merged tree: regen the cordis
catalog/api, config, persistence, and doc-graph outputs that PR3/PR4's
source changes shifted, and add the CodeDispatchLog manifest entries for
the tools.md pair's new type-equiv block.