docs(#3034): give the brace one home instead of five

Measured after mara's "2/3 of this is docs, most of it duplicated": 243 of 380
added .rs lines were comments. The brace rationale was written out in full in
`model.rs`, the `templates.rs` module header, `quiesce`, `rebuild_subtree` and
`docs/coordinator.md` — five copies of one argument, which is why four docs
needed correcting earlier in this branch. Correcting every copy preserves the
thing that made them go stale.

`docs/coordinator.md` (_Braces_) is now the single home. The rest state what a
node *is* and point there. Also drops the per-operation DAG diagram from the
`templates.rs` header, which the same doc already carries, and cuts
`rebuild_subtree`'s node-by-node walkthrough down to the three choices a reader
would otherwise undo — the code below it is the source of truth for the shape.

Comments -59 lines, no behaviour change, 317 tests unchanged.
This commit is contained in:
atlas 2026-08-04 16:38:30 +02:00
commit 0a14055a33
4 changed files with 45 additions and 116 deletions

View file

@ -7,18 +7,9 @@
//!
//! **The one sanctioned exception is a brace** — a pure-resource-holder root
//! ([`NodeKind::AgentWindow`], [`NodeKind::DeployWindow`]) declaring for a
//! coordinated subtree whose members then declare nothing. Forced by the lease
//! being single-unit: two siblings that both declared it could never run
//! concurrently. Why this is not a relapse: `docs/coordinator.md`.
//!
//! ```text
//! rebuild(a): MetaSync(a) → AgentWindow(a){ Prebuild(a) → StopForUpdate(a) → Swap(a) →(ok) RebuildBookkeeping(a) } →(any) Reconcile(a)
//! rebuild(a) graceful: … AgentWindow(a){ Prebuild(a) ∥ Signal(a) → Drain(a); both →(ok) StopForUpdate(a) → … } [boot sweep only]
//! spawn(a): Provision(a) → Create(a) → WriteDropin(a) → Reconcile(a) [wanted=Up at approve]
//! perm-change(a): WritePermFile(a) → «rebuild subgraph»
//! meta-update(inp): MetaLock(inp) →«in-DAG rebuild subgraph per affected a»
//! reparent(moves): Reparent(moves) [no rebuild — topology.json is read live]
//! ```
//! coordinated subtree whose members then declare nothing. See
//! `docs/coordinator.md`, _Braces_ — which also carries the per-operation DAG
//! shapes, so they are not restated here.
//!
//! Nodes are **named, not counted** — a template holds the handle
//! [`JobBuilder::node`] hands back, so an edge says which node it waits on. Why that
@ -130,22 +121,13 @@ pub(crate) fn fanned_out_mechanical(builder: &JobBuilder, kind: NodeKind) {
/// The graceful quiesce pair — `Signal` then `Drain`: ask the agent to run its
/// stop-checkpoint turn, then wait for it to go quiet. Returns the `Drain`
/// handle, which is what a caller edges its stop onto.
/// handle, which is what a caller edges its stop onto. The container stays
/// **up** throughout; the actual stop is the caller's next node.
///
/// The container is still **up** throughout; this only reaches a point where
/// stopping is safe. The actual stop is the caller's next node.
///
/// `brace` must already hold [`Resource::Agent`] for its whole subtree. The two
/// nodes therefore declare **nothing** and borrow that grant — which is what
/// lets them run *beside* the brace's other children (a nix build, typically)
/// instead of serialising against them. Declaring the lease here would make
/// them mutually exclusive with any sibling that also declared it, since the
/// lease is single-unit; see this module's header for the general rule.
///
/// They are **siblings under the brace, dep-ordered**, not nested. Nesting
/// `Drain` under `Signal` is only necessary where `Signal` is itself the lease
/// holder and the nesting is what keeps the grant continuous — with a brace
/// above, that reason is gone.
/// `brace` must already hold [`Resource::Agent`] for its subtree; the pair
/// declares nothing and borrows it (see the module header). They are
/// dep-ordered **siblings**, not nested — nesting is only load-bearing where
/// `Signal` itself holds the lease, as in `submit.rs`'s `restart_chain`.
pub(crate) fn quiesce<'a>(builder: &'a JobBuilder, agent: &str, brace: Handle<'a>) -> Handle<'a> {
let a = || agent.to_owned();
let signal = builder.node(NodeKind::Signal { agent: a() }).part_of(brace);
@ -179,36 +161,22 @@ impl<'a> RebuildRoots<'a> {
}
}
/// The rebuild node subtree (three group roots). `after`, when given, is the
/// node this subgraph chains behind. Structure:
/// - `MetaSync` (**root**): the meta-repo preamble (dir prep, agent sync,
/// optional relock). Owns the global `MetaWindow` — and *only* for its own
/// short duration, which is why it is a sibling root rather than the brace's
/// parent: a resource is held across the holder's whole subtree, so parenting
/// the rebuild under it would extend a hive-global window over every
/// rebuild's nix build.
/// - `AgentWindow` (**root**): `AfterOk` `MetaSync`. The brace — declares the
/// build slot *and* the agent lease, atomically, and holds both for the whole
/// subtree. Everything below it declares **nothing** and re-enters these
/// grants.
/// - `Prebuild` and the **quiesce chain** (`Signal` → `Drain`, graceful only)
/// are siblings under the brace and run **concurrently** — they contend for
/// different resources, so nesting the stop under the build (as this template
/// did) only hid the graceful-stop timeout behind the nix build. The container
/// is still up throughout the quiesce.
/// - `StopForUpdate` (child of the brace): `AfterOk` **both** `Prebuild` and
/// `Drain`. Waiting on the build is deliberate — running the drain early is
/// the win, taking the container *down* early would be pure downtime.
/// - `Swap` (child of `StopForUpdate`), then `RebuildBookkeeping` (`AfterOk` its
/// sibling `Swap`): the Ok-only bookkeeping tail.
/// - `Reconcile` (**last, root**): `AfterAny` `AgentWindow`, which rolls up
/// terminal only once its whole subtree has settled — so it runs after the
/// swap regardless of outcome, and as a top-level root it survives the
/// cancel-cascade of a failed brace (recovery-start invariant). Fresh lease;
/// the tiny gap is harmless, `Reconcile` converges idempotently.
/// The rebuild node subtree — three group roots (`MetaSync`, the `AgentWindow`
/// brace, `Reconcile`). `after`, when given, is the node it chains behind. The
/// shape itself is in `docs/coordinator.md`; the code below is the source of
/// truth for it, so only the three choices a reader would otherwise undo are
/// called out here:
///
/// Why flattening the stop chain is safe, and why the lease-continuity argument
/// that used to justify nesting it is satisfied by the brace: `docs/coordinator.md`.
/// - **`MetaSync` is a sibling root, not the brace's parent** — it owns the
/// *global* `MetaWindow`, and a resource is held across the holder's whole
/// subtree, so parenting the rebuild under it would serialise every agent's
/// nix build behind one hive-wide window.
/// - **`StopForUpdate` waits on `Prebuild` as well as `Drain`** — running the
/// drain early is the win; taking the container *down* early is pure downtime.
/// - **`Reconcile` is a top-level root, not a child** — so it survives the
/// cancel-cascade of a failed brace and still converges the container
/// (recovery-start invariant). It takes a fresh lease; the gap is harmless
/// because it is idempotent.
fn rebuild_subtree<'a>(
builder: &'a JobBuilder,
agent: &str,