Skip to content

SDD Control Flow

This traces one run of the Mission loop — the conductor advancing a single change request (CR) against the project spec — end to end. For the cast of players and the loop model, see the Overview.

There is no spawned lead delegate between the gateway and the work. For an attended session, the gateway loads start-mission in the current session and the work proceeds there — the session itself holds the user channel, grills live, and (within its leash) ratifies. The only exception is headless dispatch: with no user channel, the gateway spawns the automaton (sdd:sdd-automaton), which runs the identical mission loop but self-asserts within leash and batches needs-input up its own relay instead of asking live.

sequenceDiagram
actor Council
participant GW as Gateway (sdd)
participant CD as Conductor (this session)
participant D as Delegates (producers / judges)
Council->>GW: invoke sdd (intent)
GW->>GW: classify: change vs manage vs escape
GW->>CD: load start-mission in-session
activate CD
CD->>D: run producers inline, spawn cold judges
D-->>CD: artifacts / verdicts
CD-->>Council: grill live, ask at seed-intent / cap / gate
Council-->>CD: answers / ratification
CD-->>Council: handoff — PR / commits / summary
deactivate CD

The gateway resolves intent to a skill via a two-level menu when the request is bare (never more than four options per AskUserQuestion), or skips straight to the matched skill on a fast path (“add a start-mission skill to sdd”, “work on <issue url>”).

User intentHandler
Make any change to the project (add, revise, implement, land)start-mission
Manage the corpus — bootstrap, inspect, audit, housekeepingmanage
No suite-relevant behavior, or an ignored artifactescape — no CR, no record
Product / structure / process retrospective, field correctionsthe campaign / formation / doctrine / forge loop → a new CR (start-mission)

One project is one durable spec — routing classifies what the user wants to do to the project, never which spec in a fleet to pick.

A mission carries one CR from intent to a landed result, in segments (autonomous sittings, checkpointed via pause-mission / resume-mission) rather than one unbroken run:

  1. Intake — recover the request, locate the project spec via discover-specs, scaffold .agents/plans/<cr-ref>-<what>.plan.md, and run the escape check (no suite-relevant behavior, or ignored via resolve-tracking).
  2. Explorebuild to learn. Resolve each touched file’s production chain (resolve-governances), place and classify each node, then loop: grill the user live, write the draft spec.md + .feature, spawn the cold spec-judge, spike the impl-producer builder to steer the grill. Ends at the spec gate.
  3. Deliverbuild to keep. Spawn the impl-producer builder against the now-frozen suite (the read-set is scoped to the frozen .feature, the optional .solution.md, and the implementation files — not the prose spec). The impl gate spawns the cold impl-judge to verify every frozen scenario.
  4. Handoff — a Warden placement pass relocates any provisionally-placed node to its blessed home (a pure rename, freeze-preserving), then lands per the project’s delivery shape (branch/PR, decomposed by unit of work), with follow-ups filed as new CRs.
flowchart TD
start([Conductor: start-mission]) --> intake[Intake: open CR, scaffold plan, escape check]
intake --> resolve[Resolve production chain per touched file]
resolve --> grill[Grill loop: draft spec + .feature, cold spec-judge, build-to-learn spike]
grill -->|converged| gate1{Spec gate}
grill -->|blocked / cap hit| ask[Ask: accept-as-is / keep looping / change direction]
ask --> grill
gate1 -->|approve, freezes .feature| deliver[Deliver: build to keep against frozen suite]
deliver --> gate2{Impl gate: cold impl-judge}
gate2 -->|every scenario passes| handoff[Handoff: placement pass, land, follow-up CRs]
gate2 -->|reject / Oracle revert| deliver

At run start the conductor evaluates blast radius and the other dimensions and writes a run-level kind: leash block to its own ledger/ shard: auto-none | auto-spec | auto-all, with by: derived | user and containment approach[]. At each gate it re-derives the leash against discovered state and either self-asserts within it (approval.<gate>: { verdict: approve, by: agent, why } — provisional, landing in an async review queue) or stops with a verdict packet for the human.

LeashSelf-assertsStops at
auto-nonenothingthe spec gate
auto-specthe spec gatethe impl gate
auto-allboth gatesnothing

Hard floors always stop, regardless of leash: Clearance (narrowing/deleting an acceptance scenario), Compatibility (the semver class exceeds the authorized ceiling), and Conflict (a logical contradiction in the suite, not pre-authorizable). Human ratification — writing by: <name>, advancing status — is reserved to the in-session position holding the real user channel; a headless automaton never writes it, even when a coordinator relays “the user approved.”

Two separate stores, never conflated:

StoreHomeHoldsLifetime
Combat log.agents/plans/<cr-ref>.log.jsonl, beside the plan briefreport / correction / halt — chatty mid-flight detail, each with a write-time UTC tstracked, deleted at retro once distilled and merged
Ledgerledger/ directory, sibling to the root spec.md; one <cr-ref>.<hash>.jsonl shard per CR per writerrun-start leash, gate verdicts, Scanner-drafted strategy — no tsdurable, never deleted, never frozen

Sharding (one file per writer per CR) makes concurrent appends collision-free by construction — no merge driver is needed. Readers glob ledger/*.jsonl (plus a legacy ledger.jsonl if present).

WriterWrites
The gate (internal step in start-mission)status; the human ratification of approval (by: <name>); the freeze (@frozen tag)
Conductor<!-- open: --> markers; the produced-by map; a provisional self-asserted approval (by: agent); combat-log report/correction/halt; the ledger leash block and self-asserted gate lines
Producersspec.md body, the .feature, <unit>.solution.md
Scanner (doctrine loop)ledger strategy lines
Gatewaynothing — it only classifies and routes
stateDiagram-v2
[*] --> draft: start-mission (new or backfill)
draft --> approved: spec gate
approved --> implemented: impl gate
approved --> draft: behavior change (re-open)
implemented --> draft: behavior change (re-open)
draft --> deprecated: Oracle-lens kill
approved --> deprecated
implemented --> deprecated

approved and implemented freeze each touched .feature (a per-file @frozen tag, not a per-project state). The unfreeze trigger is risk, not phase: an additive scenario self-clears and stays frozen; a pure git mv rename preserves the freeze (letting handoff relocate a node without reopening its contract); only a narrowing or rewriting edit is a re-open — a ratified transition back to draft, after which the node re-passes its gates.