worker: make coder review routing durable

This commit is contained in:
2026-08-10 02:01:08 +09:00
parent b9dadb6a08
commit 64ced7dbad
18 changed files with 925 additions and 136 deletions
+3 -1
View File
@@ -69,7 +69,9 @@ Flow invocation uses the normal Submit/Run segment vector rather than a Worker-c
Runtime accepts exactly one Flow segment only when the resolved Profile enables `feature.flow` and a Workspace client is available. The Worker asks Workspace authority only for an immutable source snapshot, creates the instance locally, replaces the Flow segment with the entered state's instructions, and commits that runtime state atomically with the remaining Submit segments before LLM execution. A Worker with an active Flow rejects the duplicate input without changing its local state or events.
The generic model-facing `WorkerSpawn` accepts `initial_submit: Vec<Segment>` and routes them unchanged through the shared Workspace spawn request into Runtime `CreateWorkerRequest.initial_input`. It does not have a parallel `initial_text` or a role-specific `SpawnCoder` wrapper. Backend derives the flat content projection from the canonical segment vector, validates Flow shape before spawn, and includes the segment vector in lifecycle idempotency fingerprints. Restoring the same Worker never replays spawn initial segments.
The generic model-facing `WorkerSpawn` accepts `initial_submit: Vec<Segment>` and routes them unchanged through the shared Workspace spawn request into Runtime `CreateWorkerRequest.initial_input`. It does not have a parallel `initial_text` or a role-specific `SpawnCoder` wrapper. Backend derives the flat content projection from the canonical segment vector, validates Flow shape before spawn, and includes the segment vector in lifecycle idempotency fingerprints. Runtime does not commit Worker creation or report spawn success merely because the initial Run method entered the Worker's in-memory channel: Runtime assigns the Submit an opaque id, the Worker commits that id as an extension on the same `UserInput` entry as any initial `FlowRuntimeState`, and the execution backend must return a matching typed input-commit acknowledgement. Restoring the same Worker never replays spawn initial segments.
When an Orchestrator supplies `ticket_id` to generic `WorkerSpawn`, the Worker tool derives the assignment operation id from the durable tool-call id rather than accepting lifecycle authority from model input. The shared Workspace worker-create route projects that request into a Coder Ticket-role intent and atomically applies the existing queued-Ticket assignment operation only after Runtime has returned the input-commit acknowledgement. A spawn or pre-commit input failure therefore leaves the Ticket queued and unassigned.
`RequestFlowTransition` accepts only:
@@ -0,0 +1,32 @@
# SubWorker completion notification did not wake an idle parent
Date: 2026-08-06
Ticket: `00001KZKNWP5X`
## Observed behavior
A Reviewer SubWorker finished after its parent Worker had returned to idle. Although the completion notification was marked `auto_run: true`, the parent did not run until the user submitted another message. The notification appeared only in that later turn.
## Root cause
The completion callback called `NotifyBuffer::push_notify(..., true)` directly. A running parent checks that buffer at turn end and can stage a follow-up, but an idle controller waits on its method channel. Writing the buffer alone therefore could not wake an already-idle parent.
## Fix
Normal controller-owned Workers now give the SubWorker tool a weak sender for the parent method channel. Completion is delivered through the existing:
```rust
Method::Notify {
message,
auto_run: true,
}
```
path, which commits the notification through the normal inbox and wakes an idle controller. A `WeakSender` avoids a controller/tool/channel reference cycle that would otherwise keep the controller alive after external handles are dropped. Internal Worker sessions without a controller retain the direct buffer target.
## Regression coverage
- SubWorker completion sends exactly one `Method::Notify { auto_run: true }` to the parent controller channel.
- The controller notification target does not keep the method channel alive after the strong sender is dropped.
- Existing running-parent notification follow-up tests remain green.
- `cargo test -p worker --lib`: 514 passed.