discussion mock · 2026-08-11 · sources: internal/status/status.go · _pipeline.md · change-lifecycle.md · adopted — implemented by 260811-3ol6
The adopted design changes neither state machine. Machine 1 (the stage graph) and Machine 2 (the per-stage state vocabulary and its event transitions) are byte-identical before and after. What changes is the execution locus — who runs each stage's behavior — routed by a single plan-size check that rides an existing seam: plan.md is co-generated inline at apply entry in both modes, and the resulting task count decides the lane. No entry heuristic, no guessing from the intake — the decision point is a fact, not a forecast. Validated against loom's archive: 21% of 972 completed changes (195/927 measurable; 137 with PRs) would have run light end-to-end, and only ~7% of light runs would see any rework — handled inline, no mode switch. The change-type entry heuristic from the first draft is rejected — loom shows 68% of type-eligible changes blow past the size threshold while 154 small feat/fix changes slip through it.
intake → apply → review → hydrate → ship → review-pr · forward via finish (auto-activates next) · one backward edge (review rework)
Six stages, one manual gate (intake, where all human judgment is frontloaded), one rework
back-edge (review fail → reset apply, bounded at max_cycles, default 3), and two
special paths: /fab-adopt enters late with apply: skipped, and a
Copilot-timeout leaves review-pr deliberately active. Node color shows the
execution locus — that's the only thing the adopted design touches.
Ctrl/Cmd + wheel to zoom · drag to pan · double-click to fit · ⛶ opens full size
Ctrl/Cmd + wheel to zoom · drag to pan · double-click to fit · ⛶ opens full size
| stage / step | today (all changes) | after — light lane | after — full lane |
|---|---|---|---|
intake |
main session | main session | main session |
| plan co-generation (apply entry) | inside the apply worker | inline this is where the lane decision reads its input | inline new for full too — the worker receives the finished plan (the plan-exists seam already in the contract) |
| task execution (apply) | worker native / pane / headless, resumable across rework | inline orchestrator already holds the always-load layer + intake + memory | worker co-gen skipped; dispatch prompt can carry the task list |
review |
fresh worker | fresh worker — kept reviewer independence is the pipeline's highest-value dispatch; tiny diff ⇒ cheap anyway | fresh worker |
hydrate |
worker | inline often near-no-op for small changes (empty Affected Memory) | worker |
ship |
/git-pr subagent | inline mechanical: commit, push, draft PR | /git-pr subagent |
review-pr |
/git-pr-review subagent | inline eliminates the yield-seam hazard the synchronous-poll directive exists to fight; the 10-min Copilot poll is wall-clock either way | /git-pr-review subagent |
fab status finish / fail / reset choreography fires in the same order, the same
artifacts (intake.md, plan.md, result contract) are produced, and the
review-iteration counter invariant (finish apply is the only counted re-entry) holds
verbatim. Inline stages run on the session model and skip fab resolve-agent —
consistent with the existing rule that an undispatched stage never switches the session model.
internal/status/status.go · defaultTransitions + review/review-pr overrides · validated against AllowedStates per stage
Ctrl/Cmd + wheel to zoom · drag to pan · double-click to fit · ⛶ opens full size · ® = review / review-pr only
| event | from | to | scope | side effects |
|---|---|---|---|---|
start |
pending | active | all stages | pre hook runs first — non-zero exit blocks the start |
start |
failed | active | review, review-pr | recovery re-entry from a parked failure |
advance |
active | ready | all whose schema allows ready (not ship / review-pr) |
— |
finish |
active, ready | done | all stages | auto-activates next pending stage (the only counted review re-entry); post hook after save; auto-logs review/review-pr "passed" |
reset |
done, ready, skipped | active | all stages | cascades all downstream stages → pending; preserves iterations |
skip |
pending, active | skipped | all except intake (schema forbids the target) | forward-cascades downstream pending → skipped (adopt's entry mechanism) |
fail |
active | failed | review, review-pr | auto-logs review/review-pr "failed" |
refresh |
not a transition | all stages | pull-based recompute of derived fields (change type, plan counts, confidence) — the one fab status command dispatched workers may run |
|
Per-stage nuances from AllowedStates: intake can only hold
active / ready / done (never pending, skipped, or failed); ship and
review-pr can never hold ready; only review and
review-pr can hold failed.
progress
map, and a promoted run continues from whatever stage state it reached. (An earlier idea worth
not pursuing: a light-done or merged-stage state would fork every consumer
of this table — pr-meta, display glyphs, preflight routing.)
proposed · orchestrator-level, orthogonal to both machines above · decided at PLAN time, once, with no mid-run mode changes
Decided once, immediately after the inline plan co-generation at apply entry — the earliest
moment the strongest size signal (the actual task list) is a fact. No intake-keyword
inference: the first draft's change-type heuristic was rejected on loom's data (68% of
type-eligible changes outgrow the threshold; 154 small feat/fix changes escape it).
--light / --full skip the check. There is no promotion valve — light
rework stays inline under the same max_cycles budget, and exhaustion parks to the
manual menu identically in both lanes. A parked light run re-enters however the user chooses,
including --full.
Ctrl/Cmd + wheel to zoom · drag to pan · double-click to fit · ⛶ opens full size
loom_light_analysis.py over fab/changes/archive/**/.status.yaml +
.history.jsonl review-failed events.
review: failed state are the
backstop, and because Machines 1 and 2 are identical in both lanes, a parked light run re-enters
cleanly as full. Scope discovered mid-rework (a plan revision adding tasks) rides the same
backstop rather than any automatic promotion. V1 keeps the lane in the orchestrator's context
only (no .status.yaml field); a weight event in
.history.jsonl (see 04) covers both resume-consistency and measurement.
agent.profiles, and skip pane/headless adapters
entirely. The reviewer stays independent in both lanes — the one dispatch whose value survives
at every change size.
side effects of the plan-time decision — each independently adoptable
| # | optimization | why it falls out of this design |
|---|---|---|
| 1 | Full mode gets faster too | Inline plan co-gen means the dispatched apply worker starts with the plan in hand (the plan-exists seam already in the apply contract) — its cold start does task execution only, and the dispatch prompt can carry the task list. |
| 2 | Light rework = worker continuation for free | In the light lane the orchestrator is the apply author — it remembers what the reviewer rejected with zero SendMessage / pane-delivery machinery. The entire § Worker Continuation apparatus is the full lane's problem only. |
| 3 | Guard the inline co-gen worst case | If the intake's affected scope is obviously large, skip inline co-gen and dispatch apply with co-gen exactly as today — graceful degradation to the shipped path bounds the orchestrator-context cost of planning a big change inline. |
| 4 | Threshold as a project knob | Loom's risk gradient is smooth — no magic knee at 5. A config leaf (e.g.
pipeline.light_max_tasks, default 5) lets a repo with different change
anatomy cut bolder (6–8 tasks = another 21% coverage at 11% rework). |
| 5 | Stamp the lane into history | A weight event in .history.jsonl makes
realized savings measurable later — this page's loom analysis was only possible because
review outcomes were logged. It doubles as the resume-consistency record. |
| 6 | Attack the last wall-clock: the Copilot poll | For a light run, the external 10-minute review-pr poll now dominates end-to-end time. Requesting the Copilot review during ship (at PR creation) lets the wait overlap hydrate-index regen and PR bookkeeping instead of starting cold at review-pr entry. Independent of light mode — benefits every run. |