Responding to review on #661: a public method on the generic ToolRegistry
service whose only caller is the run_code bridge was ad-hoc surface
widening. The bridge now receives it as a registry-private capability
closure in RunCodeBridgeOptions (the requireRuntime idiom, alongside the
cap), the method is private, and it leaves the generated service
catalog/API surfaces.
The pattern is now named as a code smell where reviewers look: the
packages/AGENTS.md capability-interface rule gains the inverse-smell
clause (ceiling 660→675 — the list is at capacity and the clause needs
one sentence), and dsh-code-review's capability-fit check tells reviewers
to flag single-consumer public service methods and require the closure
form.
Validate replay sidecars and cross-copy failure facts, make browser console tripwires and macOS temp paths deterministic, and wait for asynchronous TUI resume details. Keep the owning docs, translations, and generated catalog aligned.
A stale-lib eslint --fix pass during the merge stripped the 'as never'
casts the branded WorkspaceId/SessionId parameters require; typecheck
rejects the push. Take master's version verbatim.
Conflict resolution: scripts/type-equiv.manifest.json takes master's new
paired-derivative format (one primary entry per pair) and re-adds this
stack's CodeDispatchLog entry in that format. zh README pairs brought
along for the dispatch-log arm (spill-policy behavior/limitations bullets,
tools limitation bullet now pointing at the shipped bounding).
master's bilingual README pairing (new since this branch forked) covers
packages/core/tools and packages/client/runtime, whose EN sides this PR
edits. Translate the scheduling-contract sentences (bridge pool, SDK
overlap line, loop cross-reference, codeDispatches lifecycle) into the zh
sides — including the verbatim shared model-facing block — and re-record
both pairing records.
Master made bilingual pairing mandatory repo-wide; this PR's seam-split
edits to the tasks docs get their zh counterparts: a new pair for the
dsh-tasks-local README and minimal updates to the tasks core-data doc,
agent-spine-demo README, and the tasks family READMEs, with pairing
records re-recorded.
Two new keyless scenarios for the functionality master gained since this
lane's base (#644 websettings, #643 workspace browser rework), both zero
model calls:
- settings-chrome: the modal shell (sidebar-foot trigger aria states,
role=dialog, aria-current section switch to the deliberately empty
Models, Escape + close-button paths, dialog aria golden); the Appearance
row as the REAL theme gesture — retiring lifecycle-chrome's
TODO(web-theme-gesture): clicking 深色 runs aria-pressed -> persisted
dsh.theme -> body[data-ds-dark-theme] -> alias-token flip, survives
reload, and 'system' follows the emulated OS scheme both ways; the
Language row switches the settings-scoped copy to English (dsh.locale
persisted, survives reload) and restores zh. Intentional reloads tear
the SSE stream, so the spec drains exactly its own reconnect warnings —
the tripwire still fails on unexpected connection loss.
- workspace-management: create-by-name twice through the region-header
dialog (host-durable via ctx.workspace.list()); rename end to end —
hover-revealed row menu (the button is display:none until the row
hovers), duplicate-name pre-check (inline role=alert + disabled primary
before any wire call), then workspace.rename through the real RPC,
row update, host durability, reload survival; the flat 'In one list'
view (section label flips, group headers drop, dsh.workspace.view
persists across reload, grouped restored); the session hover card
(dwell to open, closes on pointer leave). The one session row reuses
seeded-history's committed seed — no new recording. Deliberately not
driven: the inert menu rows and drag reorder (deferred in the note
with re-entry triggers).
Agent Note gains scenarios 8-9 and the drag-reorder deferred item in both
languages; llm-replay README's zh side catches up with the { patches }
paragraph; pairings re-recorded.
Responding to ds-review-bot round 2 on #661:
- logWork is bounded: past maxParallelSubCalls pending shaped-append tasks
the ordered commit lane holds (Promise.race drains one), so a slow spill
backend backpressures the run instead of accumulating unbounded pending
I/O and retained results. Tasks self-remove on settlement; run
settlement still drains every task inside the open turn. New spill test
drives three oversized reads against a hung backend at cap 1 and proves
the third dispatch cannot start until a save drains.
- shapeDispatchLog's catch uses errorMessage() (total), so a thrown value
with a throwing toString cannot escape the containment and lose the
settle event.
- CodeDispatchLog.content documented as the RENDERED result projection
(native tool/result vocabulary), not what the program received — the
program gets the structured value; doc pair + type-equiv re-synced.
- New RECORDED tui-agent snapshot scenario code-mode-dispatch-spill: the
real Loader-visible composition (worker runtime + spill-local + policy)
drives an oversized bash sub-call end-to-end; replay proves the durable
dispatch copy is bounded to preview + locator while the program value
stays whole (the outer result carries just the line count).
Agent Note updated (both languages).
Conflict resolution: drainDispatches composes both sides — the reworked
single-lane driver's drive() (ordered stages, mid-flight commit drain)
followed by this branch's logWork drain, so every shaped settle append
still lands inside the open run_code turn.
Conflict resolution: session.ts keeps this branch's paired-start callTime
(the start event exists here; a settle-only window stays null — the PR2
fix's semantics compose). The README's codeDispatches section is restored
to the running→settled lifecycle this branch implements, keeping PR2's
null-callTime nuance for starts outside the window.
Responding to ds-review-bot round 2 on #658 (three critical findings, one
warning — all rooted in the pump/commit split racing ordered stages):
- ONE driver lane now owns every ordered stage: the start append, prepare
(pre-execute/guards), and the head-of-line commit (post-execute, context
deferral, settle append). start() is awaited before the next entry can
start, so concurrent submissions can no longer run pre-execute pipelines
concurrently; only the around-dispatch/body stage overlaps, matching the
native loop's fillPool sequencing.
- An exclusive call's barrier now holds through its COMMIT: later starts
wait for the exclusive pipeline (post-execute included) to finish, the
native exclusive-group semantics.
- drainDispatches() awaits the driver run itself, so a commit already
mid-flight when the program returns is drained before run_code closes
the turn — the settle event and deferred contexts land inside it.
- maxParallelSubCalls is resolved and validated at construction (positive
integer), so direct construction can no longer wedge the pool with 0.
New tests: overlapping-submission ordered-prepare, barrier-through-commit,
drain-mid-commit, cap rejection. 96 keyless snapshots replay unchanged;
Agent Note updated (both languages).
Responding to ds-review-bot round 2 on #653: the tool/code-dispatch event
is appended at settlement, so using its time as callTime fabricated a
zero-duration call for duration-aware consumers — it is now null (start
unknown) per the ToolResultNode contract, pinned in the session spec. The
README's codeDispatches section described the PR3 running→settled
lifecycle a stack ahead of this tree; it now documents the settled-only
index this PR ships (the running shape lands with the start event in
#658, which already merges cleanly over this).
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).
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.
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.
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).
ds-review-bot finding: awaiting shapeDispatchLog before resolving the
binding let a slow spill backend delay the program and occupy a
dispatch slot. The settle now resolves the program immediately; the
shaped append runs as tracked side work (logWork) drained at run
settlement, so every tool/code-dispatch event still lands inside the
open turn. New spec pins the contract: with a hung spill backend the
second dispatch starts and the program completes both calls, and both
settle events land once released.
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.