Resolutions: regenerate the conflicted generated docs (cordis services
catalog, event-producer-consumer, module-graph); take master's
packages/README pair and re-insert the telemetry row on both sides;
re-record the README and session-doc translation pairs.
A cursor-less adoption (process restart + resume, fork, seam-module
reload) replayed the session's full log from seq 0, re-exporting
history that already left the process — a resume re-billed its entire
stored log on every restart, and a fork re-shipped the parent's prefix
under the child's id, doubling query-time counts on OTLP backends with
no native ingest dedupe.
dsh-session now exposes the fact the constructor already validated but
discarded: Session.firstLiveSeq, the constructor-seed length — the
first seq appended in this process. header.seedLength cannot serve
here: it is the durable fork-lineage boundary, and a resumed session's
constructor seed is its full stored log while the header keeps the
original fork value (llm-replay and session-query-sqlite depend on
that meaning). Constructor seeds also never publish on the
session/event firehose, so adoption replaying them was inconsistent
with the system's own publication semantics.
Adoption's cursor-less fallback starts at firstLiveSeq; seed events
still feed the chunk projection, so mid-step continuations re-drop
after a resume. Fork streams are no longer self-contained: records now
carry session.seed_length (with the existing session.parent_id) so
receivers stitch the child's stream onto the parent's. Accepted cost,
consistent with at-most-once delivery and recorded in the revival
Agent Note: a resume no longer backfills records a previous process
failed to deliver — a deployment with that requirement needs the
deferred outbox, not replay.
Pinned red-first: seeded adoption exports nothing (assertion reversed
from the prior seed-readback test, obsolete behavior changed with its
test), resume-shaped seed rebuilds the projection without exporting,
and fork records carry the stitch attributes.
Regenerate event-producer-consumer.md after the queued-frame steering removal;
re-record the bilingual consistency records the master merge left stale; and
restore the eight archived notes the agent-loop rename had swept up (archived
notes are frozen — their archival-time path references stand).
Resolve merge by regenerating cordis/config catalogs and the doc graphs from
the merged tree, and re-record the tools README and tools doc bilingual pair
hashes so the pairing gate matches the merged content.
cancel() emitted agent/cancel-requested whenever queued or steering work
existed, even under keepInbox with no active turn — a call the contract
documents as a no-op. Consumers could misread that notification as a real
cancellation. Emit only when the call actually aborts the active turn or
discards pending work, matching the "effective call" contract.
goal-session rides retry turns and survives admission failures. A
recovery policy closes a goal round's failed turn and reopens its
history under a retry trigger; the attempt now adopts that turn and
drops the failed turn's provisional reason, so the round settles from
the retry's own outcome instead of blocking an armed goal with
turn-error after a successful response. A downstream admission hook
that throws (rather than blocks) used to strand the queued reservation
forever; the listener now clears a still-turnless matching attempt on
the rejection path and reschedules the round.
agent-loop contains a persistently rejecting step close in the catch
path the same way the finally contains the turn close, so the
post-finally tail always publishes the terminal status — previously a
double veto escaped run(), leaving status at running while whenIdle()
resolved. The whenIdle catch arm is annotated as the backstop it now
is: every driver rejection path is contained today.
workspace-context folds an already-appended baseline from the session
log when the plugin is hot-remounted over a live session, instead of
injecting a duplicate from its fresh mount-local guard.
The TUI's reference-admission discard listener installs before
followup(): admission runs synchronously inside it on the common path,
so a listener installed afterwards missed its own cleanup and leaked
one callback per referenced prompt.
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.
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 staged-promotion machinery (concludingParents keyed by parent token
plus a pendingParentConclusions staging map) spread one fact — this call
concluded the turn — across three registry-side collections with manual
cleanup. Align it with how additionalContexts already crosses the same
boundary: concludeTurn() marks only its own execution, the marker rides
that execution's successful result (ToolExecutionFailure types
concludesTurn as never, so a policy-converted failure sheds it with the
type), and the composite that owns the nested dispatch forwards it —
Code Mode's binding does so beside its existing context forwarding.
The registry loses both parent-keyed collections and the promotion
block; the propagation decision moves to the owning boundary; the
structured-output consumer's own two-phase commit is untouched.
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.