The mount-local baseline guard was seeded from "a baseline already exists in
the log", which a resumed session and a hot plugin remount both satisfy. That
made a resume skip its baseline, so offline AGENTS.md edits or removals never
reached the first resumed request — violating the documented resume contract.
Distinguish the two by agent/session-start: a startup or resume emits it before
the first step, while a remount attaches to an already-live session and never
witnesses it. Only a remount (no witnessed start, baseline already logged)
keeps the single logged baseline and skips; a resume falls through and
re-composes from current files. Adds a regression that resumes a session with
an offline baseline edit and asserts the fresh baseline reflects it.
Every PR that changes product-user-visible GUI behavior now includes a
demonstration GIF with real provenance (that branch's built tree, real
key, real model rounds). Recording stays side-effect-free; the skill
gains a bounded final publication step: GIFs go on an append-only
orphan assets branch (one per PR series) and embed via the blob URL
with ?raw=true, never on the PR branch itself.
Folds in the operational lessons from the Code Mode UI series:
.playwright-mcp/ screenshot roots (now gitignored), per-PR staging and
precise server teardown, one-call DOM polling for transient states,
exact-text completion predicates, prompt engineering for UI states,
and the export-before-invoke GIF_SKILL_DIR encoder pitfall.
Agent Note: implemented/process/2026-07-26-gui-pr-gif-evidence-and-assets-branch (+ zh pair); the 2026-07-23 recording note now defers publication policy to it.
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.
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).
The public classifier existed to defend an exported reader against
arbitrary signals, but its only production caller is the loop reading
its own machine-private turn signal, where cancel() is the sole aborter
and always writes one frozen canonical cause. Delete the export and its
15-line structural validation: settle() states the slot invariant with
one cast, the boolean call sites ask signal.aborted directly, and the
retry veto drops entirely because a requested window already implies a
live signal (cancel() retires the window before aborting).
The abort(reason) channel and first-wins semantics are unchanged; only
the reader's publicness is gone, and with it the paranoia it required.
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 #662:
- LANG_ALIASES is a Map: an assistant-authored fence label like
constructor or __proto__ now misses (plain render) instead of resolving
an inherited object property and crashing shiki mid-conversation. Test
sweeps the inherited-key labels.
- The singleton is pre-warmed in a deferred task at plugin boot (the
~120-175ms engine+grammar construction long task moves off the first
finalized fence's render); the lazy path remains the correctness
fallback, and unref keeps non-browser imports from pinning the loop.
Agent Note updated (both languages).
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.
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).
The automation bridge inherited two master-era assumptions the message
machine no longer honors. A prompt blocked at pre-turn admission opens no
turn, so no turn/end could ever settle it — the bridge now watches
whenIdle() and reports a turnless slot as cancelled (the disposed-agent
guard moved to a registry identity check before send). A failed turn no
longer rejects at its turn/end either: agent.retry() closes the failed
turn and opens a successor on the same history, so the bridge holds the
terminal error and lets a retry-triggered turn/start adopt the prompt,
rejecting only at quiescence with no successor.
Also: refresh the empty-response-retry fixture for retry-as-turn logging,
adapt master-side tests to the unified send()/UserMessageData API and
registry-fact disposal, resync the doc pairs both sides touched, trim
architecture.md back under its word ceiling, and regenerate the event and
persistence catalogs.
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.