Broca's run lifetime is separate from the session.send RPC: the reply acknowledges
durable admission, while the lineage actor owns execution and queued submissions.
Shutdown must therefore count actors' work, not just the daemon's forwarded RPCs.
- The daemon closes route admission and sends a channel-0
PUSHwith{"op":"module.draining","reason":"restart","deadline_ms":...}over the module's registered connection. Broca callsLineageRegistry::begin_stop: new runs are refused, durable queued work stays queued, and active runs finish their current step. It keeps serving health probes and receiving tool results. - At the next clean step-entry boundary,
on_restart: "resume"runs durably writeRunPaused{Restart}; other runs writeRunFinished{Interrupted}. No cancellation or final seal is triggered by the drain notice. The wall-clockdeadline_msis logged, not used to start a timer: it is the daemon's drain ceiling, not broca's post-GOODBYE budget. - The daemon probes
health.check. Broca's manifestself_signalsentry namedruns_in_flighthaskind: "busy"andanchored_to: {"health_gauges":{"gauges":["runs_in_flight","opening","closing"]}}. These are existing registry counters inmetrics, not WAL-derived estimates. Opening actors may still be admitting work; closing actors may still be syncing/joining their writers. Idle open actors and paused runs are not busy. A restart-paused actor stays open but clearsruns_in_flight. - Once forwarded requests and all declared gauges are zero, or the drain ceiling
expires, the daemon sends channel-0 GOODBYE. The serve loop returns and
stop_and_sealstarts its unchanged 10 s grace / 20 s total budget. Actors still driving work after grace are sealed concurrently; unresolved tool calls recordoutcome_unknownandInterrupted, never a resumable restart pause. - A replacement resumes durable restart pauses through ordinary admission checks with the same run/send IDs and reconstructed provider request bytes. Queued work is recovered after the unfinished episode. See graceful restart policy.
The default module restart offers up to 30 s drain + 10 s grace to reach a
boundary. The drain can end early when idle; --drain-ms and --now can shorten
it. SIGTERM or connection loss without a drain notice offers only the 10 s grace.
The 20 s final budget includes grace and teardown, not 20 s in addition to grace.
Repeated drain notices are idempotent and do not escalate to a seal.
The current daemon has no module drain-abort command or admission-resume notice.
Once it sends module.draining, it proceeds to teardown, not back to serving.
Broca intentionally leaves admission stopped even if GOODBYE is delayed or never
arrives: reopening on a local deadline would admit work onto routes the daemon
still marks draining. A transport failure runs the same final seal path; an
operator must replace a module whose daemon cannot complete its drain.
Daemon source references (paths relative to the subconscious checkout):
crates/subc-protocol/src/session.rs:115-139: the one-way command enum contains onlymodule.draining { reason, deadline_ms }, no abort/resume command.crates/subc-daemon/src/supervise.rs:8235-8281: serializes that command asFrameType::Push, channel/epoch/corr 0, and sends throughtarget.sink(the registered module connection).crates/subc-daemon/src/supervise.rs:8547-8584,8605-8614,8664-8686: closes admission, sends draining before waiting for quiescence, then sends GOODBYE; there is no cancellation branch. A restart failing after initiation is markedFailed, not reverted toRunning(supervise.rs:6420-6439).crates/subc-protocol/src/manifest.rs:357-404,472-484: declares a busy signal inself_signalswithkind: busyandSignalAnchor::HealthGauges { gauges }.crates/subc-daemon/src/supervise.rs:8061-8087: reads gauge names from the registered manifest's busy self-signals.supervise.rs:8015-8033reads each non-negative integer directly from thehealth.checkresponse'smetricsand sums them; omitted/invalid values remain busy.supervise.rs:8107-8147probes during drain and returns early when the sum and forwarded request count are zero.crates/subc-daemon/src/supervise.rs:79: default drain ceiling is 30 s.
These references describe the inspected daemon implementation, not a new broca wire protocol or a promise to reverse a drain locally.