forge-orkes 0.61.0 → 0.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/bin/create-forge.js +250 -99
  2. package/experimental/conventions/README.md +87 -0
  3. package/experimental/conventions/install.sh +179 -0
  4. package/experimental/conventions/source/rules/code-quality.md +17 -0
  5. package/experimental/conventions/source/rules/laravel-http.md +21 -0
  6. package/experimental/conventions/source/rules/laravel-jobs.md +19 -0
  7. package/experimental/conventions/source/rules/laravel-migrations.md +19 -0
  8. package/experimental/conventions/source/rules/laravel-services.md +21 -0
  9. package/experimental/conventions/source/rules/python.md +14 -0
  10. package/experimental/conventions/source/rules/testing.md +15 -0
  11. package/experimental/conventions/source/rules/vue-inertia.md +24 -0
  12. package/experimental/conventions/source/skills/laravel-conventions/SKILL.md +124 -0
  13. package/experimental/conventions/source/skills/python-conventions/SKILL.md +100 -0
  14. package/experimental/conventions/source/skills/testing-standards/SKILL.md +142 -0
  15. package/experimental/conventions/source/skills/vue-conventions/SKILL.md +92 -0
  16. package/experimental/conventions/uninstall.sh +97 -0
  17. package/experimental/m10/README.md +130 -0
  18. package/experimental/m10/install.sh +198 -0
  19. package/experimental/m10/source/hooks/forge-branch-guard.sh +61 -0
  20. package/experimental/m10/source/hooks/forge-claim-check-doctor.sh +77 -0
  21. package/experimental/m10/source/hooks/forge-claim-check.sh +113 -0
  22. package/experimental/m10/source/hooks/forge-session-id.sh +22 -0
  23. package/experimental/m10/source/mcp-server/README.md +74 -0
  24. package/experimental/m10/source/mcp-server/example.mcp.json +8 -0
  25. package/experimental/m10/source/mcp-server/index.js +460 -0
  26. package/experimental/m10/source/mcp-server/package.json +17 -0
  27. package/experimental/m10/source/skills/orchestrating/SKILL.md +223 -0
  28. package/experimental/m10/source/skills/orchestrating/bootstrap-checks.md +70 -0
  29. package/experimental/m10/uninstall.sh +69 -0
  30. package/package.json +3 -2
  31. package/template/.claude/settings.json +1 -7
  32. package/template/.claude/skills/upgrading/SKILL.md +105 -176
  33. package/template/.forge/FORGE.md +96 -200
  34. package/template/.forge/migrations/0.63.0-origin-first-upgrading.md +49 -0
@@ -1,6 +1,6 @@
1
1
  # Forge
2
2
 
3
- Lean meta-prompting framework. Context engineering + constitutional governance on agent-native primitives.
3
+ Lean meta-prompting framework. Context engineering + constitutional governance on agent-native primitives. This file is the always-loaded **routing/index layer**: tables, invariants, and pointers. Procedures live in the skills that execute them; rationale lives in ADRs — both load only on demand.
4
4
 
5
5
  ## Critical: No Native Plan Mode
6
6
 
@@ -21,13 +21,11 @@ All phases: **invoke via `Skill` tool**, never native behavior. `planning` → `
21
21
 
22
22
  ## Core Protocol And Adapters
23
23
 
24
- **Core protocol** lives in `.forge/`: project/constitution state, milestones, requirements, roadmap, context, streams, work packages, plans, verification, audits, and state ownership rules. The core protocol describes durable behavior, not one platform's tool names.
25
-
26
- **Platform adapters** translate the protocol into a runtime. Each platform adapter maps core behavior to its tools: Claude Code skills/hooks, Codex/AGENTS behavior, manual multi-session handoffs, or future agent surfaces. Adapter mechanics stay in adapter files and skills; they should not become core requirements.
24
+ **Core protocol** lives in `.forge/`: project/constitution state, milestones, requirements, roadmap, context, streams, work packages, plans, verification, audits, and state ownership rules durable behavior, not one platform's tool names. **Platform adapters** translate the protocol into a runtime (Claude Code skills/hooks, Codex/AGENTS behavior, manual multi-session handoffs). Adapter mechanics stay in adapter files and skills; they do not become core requirements.
27
25
 
28
26
  ## Project Streams
29
27
 
30
- Forge has three runtime coordination layers: Project, Stream, and Work Package.
28
+ Three runtime coordination layers: Project, Stream, Work Package.
31
29
 
32
30
  | Layer | Purpose | Default Context |
33
31
  |---|---|---|
@@ -35,36 +33,31 @@ Forge has three runtime coordination layers: Project, Stream, and Work Package.
35
33
  | **Stream** | One active line of work: goal, branch/worktree, state, blockers, next action | `.forge/streams/{stream}.yml` + `brief.md` |
36
34
  | **Work Package** | Delegated bounded task inside a stream | `.forge/streams/{stream}/packages/{id}.yml` |
37
35
 
38
- Use ordinary Quick/Standard/Full tiers inside a stream. Use Project Chief / Chief of Staff when coordinating multiple active streams or pivoting without dropping context. Workers never coordinate laterally; they report to the stream or project chief. M10 worktrees remain an optional backend for isolation/merge discipline, not the primary UX.
36
+ Ordinary Quick/Standard/Full tiers run inside a stream. Project Chief / Chief of Staff coordinates multiple active streams or pivots without dropping context. Workers never coordinate laterally; they report to the stream or project chief. M10 worktrees are an optional isolation backend, not the primary UX.
39
37
 
40
- **Merge often and early.** Integrate ready work **as soon as it is ready**, not at milestone end. Long-lived stream branches drift from main, shared surfaces go stale, and the merge gets larger and riskier the longer it waits — the opposite of the merge discipline streams exist to provide. The default posture is continuous integration, realized two ways: **producer-side** by publishing at verified checkpoints (below), and **project-side** by the Chief's Merge Cadence Check (cross-stream order + streams without checkpoints). Forge never force-pushes, never auto-resolves a conflict, and never auto-rebases.
38
+ **Merge often and early.** Integrate ready work **as soon as it is ready**, not at milestone end — long-lived stream branches drift and the merge grows riskier the longer it waits. Realized producer-side (checkpoint publishing, below) and project-side (the Chief's Merge Cadence Check). Forge never force-pushes, never auto-resolves a conflict, and never auto-rebases.
41
39
 
42
40
  ### Stream Integration Checkpoints
43
41
 
44
- Integration is **event-driven, not polled**: a stream publishes its work to main at plan-marked phase boundaries, and a lightweight flag tells sibling worktrees there is something to pull. No flag set → boot does no integration work.
42
+ Event-driven continuous integration. **Mechanism + rationale: [ADR-027](../docs/decisions/ADR-027-integration-checkpoints-declaration-split.md).** Producer implementation: `verifying` (Integration Checkpoint Publish). Consumer: `forge` boot (Step 1 preflight). In brief:
45
43
 
46
- - **Checkpoints (plan-marked).** `planning` marks selected phases as integration checkpoints (`integration_checkpoint: true` in the plan frontmatter) the points where a verified slice should land on main. Default heuristic: the last phase, plus any phase another stream/phase depends on. Advisoryplanning proposes, the operator confirms. **The mark is the opt-in:** a plan with no marked checkpoint never auto-publishes, so existing/unmarked work is unaffected.
47
- - **Producer — publish on verified checkpoint (fast-forward only, strand-guarded).** When `verifying` returns PASS for a checkpoint phase *and the session is a worktree*, it integrates that phase to main with a **fast-forward-only** push: `git push origin HEAD:main`. Git rejects a non-ff push (vs `origin/main`) — that surfaces a diverged *origin*, never force-pushed. But ff-vs-origin is not enough on its own: `origin/main` is not the operator's canonical checkout, and the local `main` ref can carry commits origin never saw (another stream's merge, a framework bump, state-sync commits). Pushing past a *behind* origin then leaves **local main diverged, not behind** — and the naive "you're behind, `git pull --ff-only`" advice *fails* on divergence (forge#13). So the producer **strand-guards** first: it publishes only when local `main` is an **ancestor of the worktree HEAD** (no local commits this checkpoint omits). Stranded (local main has such commits) it does **not** push; it surfaces "integrate through local main first" and leaves the work on the branch. On a strand-safe success it sets the **integration flag**. (No remote → fast-forward local `main` where possible, else record ready-to-ff for the primary checkout.)
48
- - **Producer — publish at intake (declaration split, second trigger for the same mechanic).** Milestone/stream intake (discussing's Milestone Gate, `forge` Step 1.2 backlog promotion, `prototyping` graduation) reuses this exact strand-guard + fast-forward + integration-flag mechanic, triggered at a different moment: not a `verifying` PASS, but the worktree's first commit. Before any content (the full `milestone-{id}.yml`, research, discussion, plans, code) is written, the worktree commits a **declaration** — milestone ID (+ reservation), one-line intent, stream registration, and coordination/touches claims, i.e. `.forge/streams/{stream}.yml` with `ownership.owned_surfaces`/`shared_surfaces` populatedand fast-forward-pushes it to `origin/main` immediately. Content stays worktree-only until the milestone's own checkpoint (above). This keeps `chief-of-staff`'s cross-stream conflict detection — which globs `.forge/streams/*.yml` from the current checkout only — sighted on in-flight work without teaching it to read across worktrees (rejected: this project spans machines, so cross-worktree reading needs the early-push step *plus* multi-branch readers — strictly more machinery). One-breath rule: main knows THAT work exists; the worktree knows WHAT it is.
49
- - **Flag (cheap, set by the producer).** A marker in the shared git common dir — `.git/forge/integration-pending` records the new main sha, the publishing stream, and the shared surfaces that changed. It is shared across all of a repo's worktrees on a machine, so any boot reads it for free; absent or already-seen → skip. The `main` ref is the source of truth the marker points at. Cross-machine (the marker is machine-local) falls back to the opt-in `forge.worktree_rebase_check` / a periodic fetch eventual, not instant.
50
- - **Consumer — auto fast-forward, else prompt (worktrees *and* the primary main checkout).** `forge` boot checks the flag in **both** checkout kinds. In a **worktree**: flag set (main advanced past this worktree's merge-base) and no divergent local commits → **fast-forward automatically** (`git merge --ff-only main`); diverged → **surface a rebase prompt** (never auto-rebase). In the **primary main checkout**: the strand guard guarantees local main is a clean ff of the new `origin/main`, so boot **fast-forwards local main automatically** (`git merge --ff-only origin/main`) — this is what keeps the operator's canonical checkout in lockstep with origin after every checkpoint, instead of drifting behind until the next local commit diverges it. Flag not set → no fetch, no scan, continue boot.
44
+ - **Checkpoints are plan-marked** (`integration_checkpoint: true` in plan frontmatter; planning proposes last phase + depended-on phases — the operator confirms). **The mark is the opt-in**: unmarked plans never auto-publish.
45
+ - **Producer:** on a checkpoint phase's verified PASS in a worktree session, fast-forward-only publish (`git push origin HEAD:main`), **strand-guarded** publish only when local `main` is an ancestor of the worktree HEAD; strandeddo not push, surface "integrate through local main first" (forge#13). On success, set the **integration flag** `.git/forge/integration-pending` in the machine-local git common dir.
46
+ - **Intake (declaration split, B3'):** a new milestone/stream's **first** worktree commit is a declaration — milestone id (+ reservation), one-line intent, stream registration with `ownership` claimsff-pushed to main immediately; content stays worktree-only until the milestone's own checkpoint. One-breath rule: main knows THAT work exists; the worktree knows WHAT it is.
47
+ - **Consumer:** boot reads the flag (absent or already-seen skip; no fetch, no scan). Clean fast-forwards run automatically in worktrees **and** the primary main checkout; any divergence surfaces a prompt never an auto-rebase. Cross-machine, the flag doesn't exist the opt-in `forge.worktree_rebase_check` / periodic fetch covers it, eventually.
51
48
 
52
49
  ### Worktree Convention (base)
53
50
 
54
- Worktrees are a **base concern** — Chief/Streams creates and references them with plain `git worktree`, independent of the experimental `orchestrating` skill. This convention is the single source of truth for *where worktrees live and what they're named*, so it lives here in base (not buried in an experimental skill) and stays upgrade-synced for every install (see [ADR-010](../docs/decisions/ADR-010-repo-scoped-worktree-root.md)).
51
+ Where worktrees live and what they're named single source of truth, base concern ([ADR-010](../docs/decisions/ADR-010-repo-scoped-worktree-root.md)). Chief/Streams uses plain `git worktree`.
55
52
 
56
53
  | Element | Convention |
57
54
  |---|---|
58
- | **Root** | `orchestration.worktree_root` from `project.yml`; if unset, default `../<repo-basename>-worktrees/`. Relative paths resolve against the **repo root** (not shell cwd); absolute and leading-`~` paths are honored verbatim. Per-repo sibling dirs keep each repo's worktrees from pooling into one shared dir. |
59
- | **Anchor** | `{milestone-id}-{session}` (e.g. `m-9-a1b2c3d4`). For a manual stream worktree with no session, the milestone/stream id alone is acceptable (`m-PLUG01`). |
60
- | **Path** | `{worktree_root}/{anchor}` — the resolved **absolute** path. |
55
+ | **Root** | `orchestration.worktree_root` from `project.yml`; default `../<repo-basename>-worktrees/`. Relative paths resolve against the **repo root**; absolute / `~` honored verbatim. |
56
+ | **Anchor** | `{milestone-id}-{session}` (e.g. `m-9-a1b2c3d4`); milestone/stream id alone acceptable for a manual stream worktree. |
57
+ | **Path** | `{worktree_root}/{anchor}` — resolved **absolute**. |
61
58
  | **Branch** | `forge/{anchor}`. |
62
59
 
63
- **Recorded path is authoritative once set.** When a worktree is created through `orchestrating`, the resolved absolute path is recorded in `lifecycle.worktree_path` (in `state/milestone-{id}.yml`) or in a stream's `runtime.worktree`, and every later operation reads it verbatim never re-derives. Changing `orchestration.worktree_root` later only affects **new** worktrees; live ones keep working off their recorded path. Move a live worktree only with `git worktree move` (a bare `mv` strips the gitdir pointer), then update the recorded path.
64
-
65
- **Fallback when no path was recorded.** A worktree created outside `orchestrating` (a manual `git worktree add`, an adopted stream) may have no recorded path. Resolve it from this convention — `{worktree_root}/{anchor}` — rather than assuming the experimental skill's internal default. Chief/Streams uses this fallback; `orchestrating` (when installed) implements the same scheme for the worktrees it creates.
66
-
67
- **Validated against the convention (advisory).** "Authoritative" means *honored*, not *unchecked*: `forge` boot (Step 1 preflight) and `chief-of-staff` adoption compare a recorded path's parent dir to the resolved `worktree_root` and **warn** — never block, never move — when it sits outside. This catches a manual `git worktree add ../forge-worktrees/m115` or pre-convention state that the verbatim-trust rule would otherwise sail past (the convention was a *fallback resolver* only, never a *validator*). The warning honors an explicit `orchestration.worktree_root`. Fix with `git worktree move` + update the recorded path.
60
+ **Recorded path is authoritative once set** `lifecycle.worktree_path` (milestone) / `runtime.worktree` (stream) is read verbatim, never re-derived; changing `worktree_root` affects only new worktrees; move a live worktree only with `git worktree move` + update the record. No recorded path resolve from the convention. `forge` boot and `chief-of-staff` adoption **validate advisorily**: recorded path outside the resolved root → warn (never block, never move); an explicit `worktree_root` is honored.
68
61
 
69
62
  ## Workflow Tiers
70
63
 
@@ -73,7 +66,7 @@ Auto-detects complexity. Override: "Use Quick/Standard/Full tier."
73
66
  ### Prototyping (minutes–hours, disposable)
74
67
  **Triggers:** "mock up"/"sketch"/"prototype"/"draw up"/"iterate on the UI"/"explore how X could look" — disposable in-app visual exploration behind an alpha/feature flag, no requirements locked yet
75
68
  **Flow:** `prototyping` — establish flag → iterate ⟲ (render → react → adjust) → resolve (graduate→milestone | park | discard)
76
- **No verify/review gate by design.** The deliverable is a thing to look at and react to, not shippable code. Fills the gap where Standard/Full ceremony (goal-backward verification, a milestone cursor) is the wrong shape and Quick's <50-line/1-2-file caps + commit-and-done don't fit an iteration loop. Real UI work with known requirements is Standard + `designing` (which *does* gate on quality). See [ADR-022](../docs/decisions/ADR-022-prototyping-tier.md).
69
+ **No verify/review gate by design** the deliverable is a thing to look at and react to, not shippable code. Real UI work with known requirements is Standard + `designing` (which *does* gate on quality). See [ADR-022](../docs/decisions/ADR-022-prototyping-tier.md).
77
70
 
78
71
  ### Quick (minutes)
79
72
  **Triggers:** bug fix, typo, config, dep bump, <50 lines
@@ -85,7 +78,7 @@ Auto-detects complexity. Override: "Use Quick/Standard/Full tier."
85
78
 
86
79
  ### Full (days)
87
80
  **Triggers:** new project, major milestone, complex multi-system, architectural decisions
88
- **Flow:** `researching` `discussing` `architecting` `planning` `executing` → `verifying` → `reviewing` → done
81
+ **Flow:** Standard flow + `architecting` between discussing and planning
89
82
  **Optional:** `designing` (UI), `securing` (auth/data/API), `debugging` (stuck), `testing` (e2e/integration/flake)
90
83
 
91
84
  ### Advisory (tier deferred)
@@ -103,15 +96,15 @@ Auto-detects complexity. Override: "Use Quick/Standard/Full tier."
103
96
  | Architectural decisions | `architecting` | Full |
104
97
  | Break work into tasks with gates | `planning` | Standard, Full |
105
98
  | Build with deviation rules + atomic commits | `executing` | All |
106
- | Prove work delivers on goals (+ M9 e2e validation gate when `e2e:true` stories present; captures the Human Verification Gate sign-off) | `verifying` | Standard, Full |
107
- | Audit health + catalog refactoring (+ M9 e2e soft-cap, orphan-test, flake-rate audits; hard-blocks completion on the Human Verification Gate) | `reviewing` | Standard, Full |
99
+ | Prove work delivers on goals (+ M9 e2e validation gate; captures the Human Verification Gate sign-off) | `verifying` | Standard, Full |
100
+ | Audit health + catalog refactoring (+ M9 e2e audits; hard-blocks completion on the Human Verification Gate) | `reviewing` | Standard, Full |
108
101
  | Small scoped fix | `quick-tasking` | Quick |
109
102
  | Rapid disposable UI mockup behind an alpha flag (no verify/review gate) | `prototyping` | Prototyping |
110
103
  | UI with design system | `designing` | When UI |
111
104
  | Security review | `securing` | When auth/data/API |
112
- | E2E/integration tests + suite audit (+ M9 author-mode gate refuses e2e without `e2e:true` + `validated:true`) | `testing` | When UI/flows or flaky suite |
105
+ | E2E/integration tests + suite audit (+ M9 author-mode gate) | `testing` | When UI/flows or flaky suite |
113
106
  | Systematic debugging | `debugging` | When stuck |
114
- | Upgrade Forge files | `upgrading` | On-demand |
107
+ | Upgrade Forge files from the npm registry (default; local dev sync only via explicit `/upgrading dev`) | `upgrading` | On-demand |
115
108
  | Cross-session memory | `beads-integration` | When Beads installed |
116
109
  | Project/read Forge work in Notion | `notion-integration` | When Notion configured |
117
110
  | Multi-agent backend (experimental) | `orchestrating` | Optional, usually selected by Chief/Streams |
@@ -123,88 +116,47 @@ Auto-detects complexity. Override: "Use Quick/Standard/Full tier."
123
116
  ### Size Gates
124
117
  | Artifact | Max | Reason |
125
118
  |----------|-----|--------|
119
+ | `FORGE.md` | 35 KB | Claude Code truncates memory files at 40k chars; routing-layer target ~28k |
126
120
  | `project.yml` | 5 KB | Forces clarity |
127
121
  | `requirements/m{N}.yml` | 50 KB/file | Prevents scope creep |
128
122
  | `plan.md` | 30 KB | Keeps executor context <50% |
129
123
  | `constitution.md` | 10 KB | Gates must be scannable |
130
124
  | `context.md` | 12 KB | Active decisions only; history archives to `context-archive.md` |
131
- | `refactor-backlog.yml` | 150 KB | Working backlog stays scannable; terminal items archive to `refactor-backlog-archive.yml` (advisory — flags, never blocks) |
132
- | `streams/active.yml` | 20 KB | Project Chief traffic map must stay cheap to load |
125
+ | `refactor-backlog.yml` | 150 KB | Terminal items archive to `refactor-backlog-archive.yml` (advisory) |
126
+ | `streams/active.yml` | 20 KB | Traffic map must stay cheap to load |
133
127
  | `streams/{stream}.yml` | 15 KB | Stream state stays resumable without becoming history |
134
- | `streams/{stream}/brief.md` | 8 KB | Stream context packet must fit into active session context |
128
+ | `streams/{stream}/brief.md` | 8 KB | Context packet must fit into active session context |
135
129
  | `streams/{stream}/packages/{id}.yml` | 10 KB | Delegated work contract stays bounded |
136
- | `reservations.yml` | 50 KB | Append-only ID-reservation registry; one short line per ADR/DEF/FR/NFR reserved |
137
- | `prototypes/{slug}.md` | 8 KB | Disposable-mockup state — current question + terse iteration log, not a design doc; terminal items archive to `prototypes/archive/` |
130
+ | `reservations.yml` | 50 KB | One short line per reserved id |
131
+ | `prototypes/{slug}.md` | 8 KB | Current question + terse iteration log; terminal items archive |
138
132
 
139
133
  ### Accumulating Artifacts
140
134
 
141
- Every new accumulating artifact needs: owner, size gate, archive/compaction rule,
142
- `derived` vs source-of-truth status, and migration behavior. Defaults:
143
-
144
- - `roadmap.yml`, `requirements/*.yml`, `releases.yml`, `reservations.yml` are
145
- source-of-truth; load scoped slices, not whole history.
146
- - `phases/`, `audits/`, `research/`, `archive/`, and `context-archive.md` are
147
- historical; load only by milestone/stream/package/version.
148
- - `prototypes/{slug}.md` is single-owner mutable while `status: exploring | parked`
149
- (the driving session writes it); terminal statuses (`graduated`, `discarded`)
150
- archive to `prototypes/archive/`. `forge` boot surfaces stale `parked` prototypes
151
- (>30d). Not derived, not shared — a prototype has exactly one driver.
152
- - Runtime/generated files (`.mcp-server/*.db*`, logs, spike DBs, and the
153
- `.git/forge/*` machine-local files — the id-reservation ledger + integration
154
- flag) are excluded from framework context and packages unless debugging them.
155
- - The board (ADR-025): `.forge/notion/map.yml` is **derived** (owner: main/orchestrator
156
- session; `forge-id → page-id` cache), **gitignored**, and rebuildable by query-self-heal
157
- (ADR-020) — never committed, never hand-edited, no size gate. The board **config** is the
158
- `board:` block in `project.yml` — **stable-shared**, governed by project.yml's 5 KB gate,
159
- changes via `/upgrading`; migration is lazy (absent block / `enabled:false` ⇒ inert, zero
160
- behavior change). The board itself accumulates nothing in-repo — it is a projection + inbox.
161
- - Template copies sync mechanically; do not treat them as separate concepts.
135
+ Every new accumulating artifact declares: owner, size gate, archive/compaction rule, `derived` vs source-of-truth status, and migration behavior. Defaults: `roadmap.yml`, `requirements/*.yml`, `releases.yml`, `reservations.yml` are source-of-truth — load scoped slices, not whole history. `phases/`, `audits/`, `research/`, `archive/`, `context-archive.md` are historical — load only by milestone/stream/package/version. `prototypes/{slug}.md` is single-owner mutable while `exploring|parked`; terminal statuses archive to `prototypes/archive/`. Runtime/generated files (`.mcp-server/*.db*`, logs, spike DBs, `.git/forge/*`) are excluded from framework context unless debugging them. The board (ADR-025): `.forge/notion/map.yml` is derived, git-ignored, rebuildable; board config is the `board:` block in `project.yml` (absent ⇒ inert). Template copies sync mechanically — not separate concepts.
162
136
 
163
137
  ### Fresh Agent Pattern
164
138
  Task touches 20+ files or complex subsystem → spawn fresh executor with isolated context. Prevents context rot.
165
139
 
166
140
  ### Context Handoff
167
- Each phase writes outputs to `.forge/` before completing. At phase boundaries, recommend `/clear`. Next phase loads from disk. Advisory — skip for short phases under 40% context.
141
+ Each phase writes outputs to `.forge/` before completing. At phase boundaries, recommend `/clear`; the next phase loads from disk. Advisory — skip for short phases under 40% context.
168
142
 
169
143
  ### Lazy Loading
170
- Skills load only when invoked. Active context is `.forge/context.md`; consult
171
- `.forge/context-archive.md` only when older decisions matter. Skill details stay
172
- on demand. Base context ~300 lines.
144
+ Skills load only when invoked. Active context is `.forge/context.md`; consult `.forge/context-archive.md` only when older decisions matter.
173
145
 
174
146
  ### Rules Layer (`.claude/rules/`)
175
- Three policy weights, lightest-first (ADR-018):
176
- - **`constitution.md`** — always-loaded architectural **gates** (heavy, project-wide, hard rules; size-gated 10 KB).
177
- - **`.claude/rules/`** — lightweight ambient guidance. Always-on (no frontmatter, loads every session) or path-scoped (`paths:` glob frontmatter, auto-attaches only when editing a matching file — **zero context cost until you touch that code**).
178
- - **Skills** — heavy, opt-in, loaded by task description.
179
-
180
- Core ships one always-on rule: **`agent-discipline.md`** (the stack-agnostic AI failure-mode floor; restates the everyday version of the executor's Deviation Rules). **Stack-specific** path-scoped rules (Laravel/Vue/Python) and convention skills ship in the **opt-in `experimental/conventions/` pack**, not core — keeping the base stack-neutral. Authoring: keep each rule under ~20 lines, imperative-first; if it grows past ~25 lines it is a skill in disguise. See `.claude/rules/README.md`.
147
+ Three policy weights, lightest-first (ADR-018): **`constitution.md`** (always-loaded hard gates, 10 KB) → **`.claude/rules/`** (lightweight ambient guidance — always-on, or path-scoped via `paths:` glob at zero cost until a matching file is touched) → **skills** (heavy, opt-in). Core ships one always-on rule, `agent-discipline.md`; stack-specific rules are opt-in (`experimental/conventions/`). Format + authoring: `.claude/rules/README.md` (itself always loaded).
181
148
 
182
149
  ## Model Routing
183
150
 
184
- Configure in `project.yml`:
151
+ Configured in `project.yml` under `models:` — `default`, `parent_session` (advisory), `by_complexity.{trivial|standard|complex}` (per-task, M24), `skills.{name}` (per-skill).
185
152
 
186
- ```yaml
187
- models:
188
- default: sonnet # fallback
189
- parent_session: sonnet # advisory — warns on mismatch
190
- by_complexity: # per-task complexity → model (M24). Overrides skills — see Precedence.
191
- trivial: haiku
192
- standard: sonnet
193
- complex: opus
194
- skills: # per-skill overrides
195
- architecting: opus
196
- planning: opus
197
- verifying: haiku
198
- quick-tasking: haiku
199
- ```
153
+ **Precedence:** `by_complexity.{task.complexity}` → `skills.X` → `default` → parent model. **Complexity overrides skill** (LOCKED, context.md § M24): a task's `by_complexity` resolution wins over `models.skills.{skill}` — the per-task signal is the granular one; a task with no complexity resolves via the unchanged chain, zero behavior change untagged.
200
154
 
201
- **Precedence:** `by_complexity.{task.complexity}` `skills.X` `default` parent model.
202
- **Complexity overrides skill** (LOCKED, context.md § M24): when a task declares a `<complexity>`, its `by_complexity` resolution wins over `models.skills.{skill}`. WHY — the per-task signal is the granular one and the whole point of M24; letting the coarser skill-level setting win would make per-task routing inert on any project that already sets `models.skills.executing`. A task with **no** complexity resolves via the unchanged `skills → default → parent` chain — zero behavior change for untagged tasks.
203
- **All advisory** — forge displays expected model at each transition, suggests `/model` on mismatch. Review gate logs model used. Cannot auto-switch.
155
+ **All advisory** forge displays the expected model at each transition and suggests `/model` on mismatch; the review gate logs the model used. Forge cannot auto-switch models.
204
156
 
205
- **Subagent inheritance.** When a skill spawns subagents via the Agent tool (parallel research, fresh-context reviewers, executor fan-out, tester author/analyst, etc.), the skill MUST pass the resolved `model` param explicitly. Subagents do NOT inherit skill-level routing automatically — without the param they run on the parent session's model, defeating the routing intent. Resolution is **per-task** where the task being spawned declares a `complexity` (`by_complexity` wins per the Precedence above), falling back to the skill-level chain (`models.skills.{skill}` → `models.default` → parent) otherwise — surface it: *"Spawning {role} with model: {model} (from {source})"*. **Inline-task limitation:** a task that runs inline (no spawn) inherits the parent session's model and cannot be re-routed — per-task routing is inherently a subagent-spawn feature, not something that reaches into an already-running skill session.
157
+ **Subagent inheritance.** A skill spawning subagents MUST pass the resolved `model` param explicitly subagents do NOT inherit skill-level routing (without the param they run on the parent model, defeating the routing intent). Resolve **per task** where the task declares `complexity`, else the skill chain; surface *"Spawning {role} with model: {model} (from {source})"*. An inline task inherits the session model and cannot be re-routed.
206
158
 
207
- **Spawn gate — predicate A (LOCKED, context.md § M24; refined 2026-07-20/m-33).** Executing's *mandatory* subagent spawn on a complexity-tagged task fires **only when the task's resolved model differs from the live session model** (the model the session is actually running on). Resolved == live — always the case when there is **no `models:` block** (the chain falls to parent == live) — makes the spawn a pure no-op (briefing overhead, no routing change), so the tag becomes a **context signal only**: spawn iff a context trigger (20+ files / deep subsystem / >40%) independently fires. The inline-task limitation above is real, but the leak it names only bites when a *different* model was actually available — exactly the resolved-≠-live case the gate keeps mandatory. (WHY: an unconditional spawn burned ~315k subagent tokens on m-30 for zero routing benefit.)
159
+ **Spawn gate — predicate A (LOCKED, context.md § M24; refined m-33).** Executing's mandatory spawn on a complexity-tagged task fires **only when the resolved model differs from the live session model**. Resolved == live — always the case with no `models:` block — makes the spawn a pure no-op, so the tag becomes a context signal only (spawn iff a context trigger independently fires). WHY: an unconditional spawn burned ~315k subagent tokens on m-30 for zero routing benefit.
208
160
 
209
161
  ## Agents
210
162
 
@@ -215,12 +167,12 @@ models:
215
167
  | `executor` | Building + deviation rules | All dev tools | Execution |
216
168
  | `verifier` | Goal-backward verification | Read + Bash (tests) | Verification |
217
169
  | `reviewer` | Security + architecture + refactoring (breadth pass, gates the health report) | Read, Bash, Grep, Glob | Reviewing |
218
- | `tester` | E2E/integration authoring + suite analysis | Dual-mode: author (Write/Edit/Bash/git) · analyst (Read/Glob/Grep/Bash read-only) | Testing skill |
219
- | `security-reviewer` | Confidence-gated security depth (≥8, exploit-scenario required) | Read, Grep, Glob, Bash | Optional deep-dive (from `reviewing` or direct) |
170
+ | `tester` | E2E/integration authoring + suite analysis | Dual-mode: author (Write/Edit/Bash/git) · analyst (read-only) | Testing skill |
171
+ | `security-reviewer` | Confidence-gated security depth (≥8, exploit-scenario required) | Read, Grep, Glob, Bash | Optional deep-dive |
220
172
  | `performance-reviewer` | Real bottlenecks only (Impact = frequency × cost; ≥8 + ≥Medium) | Read, Grep, Glob, Bash | Optional deep-dive |
221
173
  | `doc-reviewer` | Docs-vs-source accuracy (≥8; Blocker/Major/Minor) | Read, Grep, Glob, Bash | Optional deep-dive |
222
174
 
223
- The three specialist reviewers **complement** the generalist `reviewer` — single-axis, defensible depth, read-only. They are pulled in deliberately (the `reviewing` skill can spawn them, or invoke directly); the 3-mode `reviewer` remains the breadth pass that gates the milestone health report.
175
+ The three specialist reviewers complement the generalist `reviewer` — single-axis, defensible depth, read-only, pulled in deliberately (from `reviewing` or direct). The 3-mode `reviewer` remains the breadth pass that gates the milestone health report.
224
176
 
225
177
  ## Project Init (First Run)
226
178
 
@@ -234,116 +186,75 @@ Quick tier skips init.
234
186
 
235
187
  ## State Management
236
188
 
237
- State lives in `.forge/`:
238
- - `project.yml` — Vision, stack, design system, verification, constraints (<5KB)
239
- - `constitution.md` — Active architectural gates
240
- - `design-system.md` — Component mapping table
241
- - `requirements/m{N}.yml` — Per-milestone structured requirements with `[NEEDS CLARIFICATION]` markers. **FR-IDs, DEF-IDs, and NFR-IDs are globally unique across all milestone files** — `FR-001` may exist in exactly one `m{N}.yml`. Before adding a new ID, **reserve it via the ID Reservation Protocol** run `forge-reserve fr|nfr|def --milestone <id>` and use the id it prints (the helper dual-writes the machine-local ledger + `.forge/reservations.yml`; you commit `reservations.yml` with the work). The next number is `max(ledger ∪ in-tree ∪ main:reservations.yml) + 1`. The machine-local ledger is what makes the shared ID space safe across **concurrent worktrees**: bare scan-and-increment (or a branch-local `reservations.yml`) sees only committed/merged state, so two worktrees branched from one baseline claim the same number and collide silently until merge (see ADR-021, supersedes ADR-016). On a residual collision (legacy/un-reserved, e.g. during a migration), keep the older milestone's ID and renumber the newer. Concurrent milestones each own their file — no cross-stream contention on file writes, but ID space is shared. Functional requirements may carry M9 e2e gate fields (`e2e`, `observable_outcome`, `observable_outcome_hash`, `validated`) — lazy migration, absent fields default to `e2e:false`/`validated:false`.
242
- - `roadmap.yml` — Phases, milestones, dependencies
243
- - `state/index.yml` — DERIVED registry rolled up from milestone files (id, name, status, last_updated). Never hand-edited; never written by worktree agents. **Git-ignored render-on-read cache (0.53.0): regenerated at every boot from the milestone files, never committed** — so a committed projection can never drift stale from its source, and any session can render it locally without touching `main`. Absent on a fresh clone until the first boot renders it (the project sentinel is `project.yml`, not this file). The boot rollup also renders each unit's **derived `release_state`** into this cache (see below).
244
- - **Derived `release_state` (0.56.0, [ADR-024](../docs/decisions/ADR-024-merged-validated-fold.md))**a unit's `release_state ∈ {unmerged, merged, validated}` is **computed at rollup, never stored** (never an enum on `current.status`, never a committed field) and rendered only into the git-ignored cache. `merged` = the unit's landed SHA is an ancestor of the mainline; `validated` requires `merged` plus the repo's configured approval. Computed by the fold-of-record `.claude/hooks/forge-release-fold.sh` (git-only, offline, main-checkout-resolvable all field reads via `git show main:`). Validation is dispatched on `forge.validation_event` in `project.yml`: `in_session_signoff` (**default**, absent ⇒ this — `human_verified`/M0 signoff, legacy-complete grandfathered) or `promotion_approval` (a CI-signed `promotion/{sha}` tag verified offline via `git tag -v` + allowed-signers, validated by containment). Inert by default — every repo unchanged until it opts in. The gate-relocation consequence lives in the Human Verification Gate section; the full spec lives in ADR-024 + the fold header (not duplicated here — Article XII).
245
- - `state/milestone-{id}.yml` — Per-milestone cursor (single source of truth): position, progress, decisions, blockers. One owner at a time.
246
- - `state/desire-paths/`Append-only framework-usage observations, one file per observation. Occurrence counts derived by globbing (no mutable counter). Each carries `scope: project | framework` (set at capture; absent ⇒ project). **`forge` boot is the single review owner**: at 3+ occurrences it surfaces a concrete fix from the co-located suggestion table, persists declines to `declined/` (no re-nag), and for `scope: framework` signals routes them upstream — a portable block to `upstream/` plus a `gh issue` offer against `forge.upstream_repo`. This closes Principle 7's capture→act loop; `verifying` captures but no longer surfaces. See [ADR-012](../docs/decisions/ADR-012-upstream-desire-path-feedback-channel.md).
247
- - `context.md` — Active locked decisions + deferred ideas (target <=12KB)
248
- - `context-archive.md` — Historical locked decisions; load only when relevant
249
- - `streams/active.yml` — **DERIVED** Project Chief traffic map. Regenerated by the Stream Rollup from the per-stream files + active milestone files (see Stream Rollup below). **Never hand-edited**, like `index.yml`, and — since 0.53.0 — a **git-ignored render-on-read cache** regenerated at every boot, never committed (this is the durable kill for the drift where a committed `active.yml` phase went stale against its milestone). Each row carries the two orthogonal dimensions side by side: `phase` (from the milestone, for milestone-backed streams) and `coordination` (from the stream file). See [ADR-015](../docs/decisions/ADR-015-derived-stream-registry.md).
250
- - `streams/{stream}.yml` — Per-stream **source of truth**: coordination lifecycle, ownership, shared surfaces, blockers, merge readiness, and an optional `stream.milestone: m-{id}` link. Standalone (quick-fix) streams own their `status` here; milestone-backed streams omit workflow phase (the rollup reads it from the milestone).
251
- - `streams/{stream}/brief.md` — Human-readable stream context packet loaded when resuming that stream.
252
- - `streams/{stream}/packages/{id}.yml` — Work package contract for delegated workers or manual sessions.
253
- - `research/milestone-{id}.md` — Research findings snapshot (dated, immutable)
254
- - `phases/milestone-{id}/{phase}-{name}/plan-{NN}.md` — Task plans with must_haves frontmatter (`{id}`=milestone, `{phase}`=phase# preserved verbatim, `{name}`=kebab, `{NN}`=seq)
255
- - `refactor-backlog.yml` — Refactoring catalog (actionable items only), worked via quick-tasking. Canonical status vocab: `pending | in_progress | done | dismissed | deferred`. Terminal items auto-archive on the next reviewing/quick-tasking write (compaction-on-write).
256
- - `refactor-backlog-archive.yml`Append-only terminal-item archive (`done`/`dismissed`); keeps the audit trail out of the working backlog.
257
- - `releases.yml` — Append-only version-reservation registry (cross-session coordination point; see Version Reservation Protocol)
258
- - `reservations.yml` — Append-only ID-reservation audit trail + cross-machine floor for ADR/DEF/FR/NFR numbers, written by `forge-reserve` (ADR-021). The same-machine cross-worktree coordination point is the machine-local ledger `.git/forge/id-reservations`; see ID Reservation Protocol.
259
- - `archive/milestone-{id}/`Archived milestone artifacts (archive-delete)
260
- - `prototypes/{slug}.md` — Lightweight resumable state for a disposable in-app design mockup (Prototyping tier). Status vocab: `exploring | parked | graduated | discarded`. Terminal (`graduated`/`discarded`) → archive to `prototypes/archive/{slug}.md`. Single-owner mutable; not derived, not shared. See `Skill(prototyping)`.
261
-
262
- **Milestones** group phases into concurrent streams. Own state file — no conflicts across sessions. Can be deferred (frozen in place) or archive-deleted.
263
- `index.yml status` gates routing: `not_started | active | deferred | complete`.
264
-
265
- **Stream Rollup (`active.yml` is derived).** Mirrors the milestone Rollup: `active.yml` is a pure projection, regenerated never hand-edited — by a deterministic, idempotent **join** of two single-sourced inputs (ADR-015). Run by the main/orchestrator session and at `chief-of-staff` Show/Sync; worktrees never write it. Procedure:
266
- 0. **Completed-stream auto-close sweep (source write, main checkout only — runs *before* the join).** A milestone-backed stream whose work has completed and landed on main should not linger as a `ready`/`merge_queue` row — that stale readiness is a **false** "ready to merge" nudge (the work is already on main; the stream is *closable, not mergeable*). Before the pure join, glob the stream files and for each with `stream.milestone: m-{id}` where the milestone's derived status (from the freshly-rolled `index.yml`) is `complete`, its stream `status` is **not** already `closed`, **and** it has no live worktree (`runtime.worktree` empty, or the path no longer resolves to a live `git worktree`) → **auto-close it**: set the stream file's `status: closed` and `merge.readiness: merged`, append a `merge.notes` line (*"auto-closed: milestone m-{id} complete + on main"*), refresh `updated_at`. Emit one line — *"auto-closed stale stream {id} — milestone m-{id} complete, already on main."* This is a legitimate source write (stream file = single-owner mutable; the milestone is done, so no live driver contends). **Guards:** a `deferred` linked milestone is **not** swept (its stream should pause, not close — Chief offers that interactively); a `complete` milestone **with a live worktree** is **not** swept here either — the forge-boot "Completed milestone + live worktree → finalize" path (SKILL Step 1) owns teardown, and closes the stream as part of it. Idempotent: an already-`closed` stream is skipped, so re-running the sweep is a no-op. No `streams/` dir, or nothing complete-and-open → the sweep is silent and the join runs unchanged.
267
- 1. Glob `streams/{stream}.yml`. Each → a row carrying its coordination state (`coordination` = the file's `status`), goal, runtime, ownership summary, `merge_readiness` (derived from the stream file's `merge.readiness`), `blocked_by`, `next_action` — all from the stream file.
268
- 2. For a stream with `stream.milestone: m-{id}`, read `phase`/activity from `milestone-{id}.yml` (`current.status`, `last_updated`) — **not** stored in the stream file. A linked milestone that is `deferred`/`complete`/absent → the row's `phase` reflects that.
269
- 3. Glob active milestones (from `index.yml`). Any active milestone with **no** stream file → emit a derived `stream: implicit` row (phase from the milestone, no coordination state) so coverage is guaranteed in the artifact — an active milestone can never be silently missing.
270
- 4. Derive `merge_queue:` — one entry per stream with `merge.readiness: ready`.
271
- 5. Write `active.yml` (`version`, `updated_at`, derived `streams:` sorted by id, derived `merge_queue:`). No hand-edited keys.
272
-
273
- Because each field has exactly one source and coverage is computed, the two-registry drift class (issue #4) cannot occur — this **supersedes** the advisory Registry Drift Check shipped in 0.33.0.
274
- **Format**: YAML for machine state, Markdown for human content.
275
- **`current.status` is authoritative.** Complete only at `current.status == complete`. 100% tasks ≠ done — still needs verifying + reviewing + a recorded human sign-off (`current.human_verified` — see Verification Gates → Human Verification Gate).
189
+ State lives in `.forge/`. One line per artifact; protocol detail lives in the named ADRs and skills:
190
+
191
+ - `project.yml` — vision, stack, design system, verification, constraints (<5 KB)
192
+ - `constitution.md` — active architectural gates
193
+ - `design-system.md` — component mapping table
194
+ - `requirements/m{N}.yml` — per-milestone structured requirements with `[NEEDS CLARIFICATION]` markers. **FR/DEF/NFR ids are globally unique across all milestone files** — reserve via the ID Reservation Protocol before writing. M9 e2e gate fields (`e2e`, `observable_outcome`, `validated`, hash) lazy-migrate; absent ⇒ `false`.
195
+ - `roadmap.yml` — phases, milestones, dependencies
196
+ - `state/index.yml`DERIVED milestone registry, **git-ignored render-on-read cache** (0.53.0): regenerated at every boot by Rollup 1.0 (`forge` SKILL Step 1.0) from the milestone files; never committed, never hand-edited, never written by worktree agents; absent on a fresh clone (the project sentinel is `project.yml`). Rows carry the derived `release_state`.
197
+ - **Derived `release_state`** ([ADR-024](../docs/decisions/ADR-024-merged-validated-fold.md)) — `{unmerged, merged, validated}` computed at rollup by `.claude/hooks/forge-release-fold.sh` (git-only, offline; the fold binary is the only source agent prose never re-derives it), never stored. Validation binding via `forge.validation_event`: `in_session_signoff` (default; absent this) or `promotion_approval` (CI-signed `promotion/{sha}` tag). Inert until a repo opts in; full spec in ADR-024 + the fold header.
198
+ - `state/milestone-{id}.yml`per-milestone cursor (**single source of truth**): position, decisions, blockers. One owner at a time.
199
+ - `state/desire-paths/` — append-only framework-usage observations, one file per observation, `scope: project|framework` (absent ⇒ project); occurrence counts derived by globbing. **`forge` boot is the single review owner** surfaces groups at 3+, persists declines (no re-nag), routes `framework`-scope signals upstream ([ADR-012](../docs/decisions/ADR-012-upstream-desire-path-feedback-channel.md)); `verifying` captures but never surfaces.
200
+ - `context.md` — active locked decisions + deferred ideas (≤12 KB); history archives to `context-archive.md`
201
+ - `streams/active.yml` — DERIVED Project Chief traffic map, git-ignored render-on-read cache see Stream Rollup below ([ADR-015](../docs/decisions/ADR-015-derived-stream-registry.md))
202
+ - `streams/{stream}.yml` (+ `brief.md`, `packages/{id}.yml`) per-stream **source of truth**: coordination lifecycle, ownership, shared surfaces, blockers, merge readiness, optional `stream.milestone` link (milestone-backed streams omit workflow phase the rollup reads it from the milestone)
203
+ - `research/milestone-{id}.md` — dated immutable findings snapshot
204
+ - `phases/milestone-{id}/{phase}-{name}/plan-{NN}.md` — task plans with must_haves frontmatter (`{id}`=milestone, `{phase}`=phase# verbatim, `{name}`=kebab, `{NN}`=seq)
205
+ - `refactor-backlog.yml` — refactoring catalog worked via quick-tasking; status vocab `pending | in_progress | done | dismissed | deferred`; terminal items auto-archive to `refactor-backlog-archive.yml` on the next reviewing/quick-tasking write
206
+ - `releases.yml` — append-only version-reservation registry (Version Reservation Protocol)
207
+ - `reservations.yml` — append-only id-reservation audit trail + cross-machine floor (ID Reservation Protocol)
208
+ - `archive/milestone-{id}/`archived milestone artifacts (archive-delete)
209
+ - `prototypes/{slug}.md` — resumable disposable-mockup state (`exploring | parked | graduated | discarded`); terminal `prototypes/archive/`. Single-owner, one driver. See `Skill(prototyping)`.
210
+
211
+ **Milestones** group phases into concurrent streams — own state file, no conflicts across sessions; can be deferred (frozen in place) or archive-deleted. Registry status vocab: `not_started | active | deferred | complete`. **`current.status` is authoritative** complete only at `current.status == complete`; 100% tasks ≠ done (verifying + reviewing + the recorded human sign-off still gate).
212
+
213
+ **Format:** YAML for machine state, Markdown for human content.
214
+
215
+ ### Stream Rollup
216
+
217
+ `active.yml` is a pure projection regenerated, never hand-edited — by a deterministic, idempotent **join**: per-stream files contribute coordination state; active milestones contribute `phase` (any active milestone with no stream file gets a derived `implicit` row — coverage is computed, not maintained); `merge_queue` derives from `merge.readiness: ready`. A **step-0 completed-stream auto-close sweep** runs first: a milestone-backed stream whose milestone is `complete`, not yet `closed`, with no live worktree is auto-closed — a done-and-merged milestone can never leave a zombie "ready to merge" row. Run by the main/orchestrator session at `forge` boot and `chief-of-staff` Show/Sync; worktrees never write it; milestone Rollup 1.0 runs **first** (the join reads the fresh `index.yml`). **Numbered procedure: the ADR-015 addendum.** Because each field has exactly one source and coverage is computed, two-registry drift cannot occur — supersedes the old advisory Registry Drift Check.
276
218
 
277
219
  ### State Commit Protocol
278
220
 
279
- `.forge/` durable state is **committed**, not just written to disk so project state survives machine loss and is pullable from any clone. At every phase **Handoff**, after writing state, the completing skill runs one scoped state-sync commit:
221
+ `.forge/` durable state is **committed**, not just written — project state survives machine loss and pulls from any clone. At every phase **Handoff**, after writing state, the completing skill runs one scoped state-sync commit:
280
222
 
281
223
  ```
282
224
  git add .forge/ # scoped — respects .gitignore; never `git add .`
283
225
  git commit -m "chore(forge): sync state after {phase} — m{N} {phase-name}"
284
226
  ```
285
227
 
286
- **In a worktree session, pin these with the recorded path** — `git -C {worktree_path} add .forge/` then `git -C {worktree_path} commit …` (`{worktree_path}` = `lifecycle.worktree_path`, authoritative over cwd). The process cwd can silently reset to the launch (main) checkout across a turn boundary; a bare `git add .forge/…` then hits the wrong checkout (worktree-only content fails to stage) and a bare `git push origin HEAD:main` can even **exit 0** against a stale local `main` HEAD a silent wrong-tree commit/push. Cheap guard before the first write: compare `git rev-parse --show-toplevel` to the recorded path; mismatch use `-C` (or `cd` back).
287
-
288
- State-sync commits are separate from per-task code commits (which stay atomic during executing).
228
+ **In a worktree session, pin with the recorded path** — `git -C {worktree_path} add/commit` (`lifecycle.worktree_path` is authoritative over cwd; the process cwd can silently reset to the launch checkout across turns, and a wrong-cwd git op can even exit 0). Guard: compare `git rev-parse --show-toplevel` to the recorded path before the first writefull discipline in `executing` (Worktree cwd discipline) and `verifying` (Worktree cwd guard). State-sync commits are separate from per-task code commits (which stay atomic during executing).
289
229
 
290
230
  ### State Ownership (multi-worktree safety)
291
231
 
292
- `.forge/` is code-like: it branches with the repo, syncs via git, and commits
293
- with the work it describes. Every artifact has a sharing class:
232
+ `.forge/` is code-like: it branches with the repo, syncs via git, and commits with the work it describes. Every artifact has a sharing class (rationale: [ADR-011](../docs/decisions/ADR-011-shared-state-taxonomy.md) + addendum):
294
233
 
295
234
  | Class | Files | Write rule |
296
235
  |---|---|---|
297
- | **Single-owner mutable** | `state/milestone-{id}.yml`, `phases/milestone-{id}/`, `research/milestone-{id}.md` | Exactly one writer at a time — the worktree (or main session) currently driving that milestone. **Other worktrees never touch it**, not even to read-then-write — they pull from main if they need it. |
298
- | **Single-owner mutable (per stream)** | `streams/{stream}.yml`, `streams/{stream}/brief.md`, `streams/{stream}/packages/*.yml` | The stream's **current driver** writes them one writer at a time, like the milestone file. Distinct streams own distinct files (no cross-stream contention). `active.yml` is **derived** from them: a worktree driving a stream may write its own stream file but **never** `active.yml` or a peer stream's file. |
299
- | **Derived (git-ignored render-on-read cache)** | `state/index.yml`, `streams/active.yml`, the **`release_state`** column rendered into `index.yml` (ADR-024) | Never hand-edited, **never committed** — git-ignored local caches (0.53.0), regenerated by rollup from their sources (`index.yml` ← `milestone-*.yml` via Rollup 1.0; `active.yml` ← per-stream files + active milestones via the Stream Rollup; `release_state` ← `forge-release-fold.sh` over git truth) at every boot. Because the value is computed on read and never stored in git, a committed projection cannot drift stale from its source, and **any** session (not just the orchestrator) may render them locally without a `main` write. Absent on a fresh clone until the first boot; readers must render-then-read and must **not** use their absence as a "not a Forge project" sentinel (that is `project.yml`). |
300
- | **Append-only shared** | `releases.yml` (version reservations), `reservations.yml` (ADR/DEF/FR/NFR id **audit trail + cross-machine floor**), `state/desire-paths/*` (one file per observation) | Many writers OK; structure prevents collision. `releases.yml` uses the Version Reservation Protocol (append + commit + push). `reservations.yml` is written by `forge-reserve` (ADR-021) and committed with the caller's work — it is no longer the id *coordination* point (the machine-local ledger is), just the durable committed shadow. Desire-paths use distinct filenames so two writers never touch the same file. |
301
- | **Machine-local runtime** | `.git/forge/id-reservations` (id-reservation ledger), `.git/forge/integration-pending` (integration flag) | In the git common dir, shared across a repo's worktrees on one machine, **not** git-tracked. `forge-reserve` writes the ledger under a `mkdir` lock; excluded from framework context. Machine-local by design (cross-machine falls back to the `main:reservations.yml` floor). |
302
- | **Shared mutable** | `context.md`, `refactor-backlog.yml`, `requirements/m{N}.yml` (ID space `FR-`/`DEF-`/`NFR-` is globally shared even though each milestone owns its file) | Write only to your milestone/stream block. Within a block, append-only; strike through instead of rewriting. |
303
- | **Stable shared** | `project.yml`, `constitution.md`, `design-system.md`, `roadmap.yml`, `FORGE.md`, `.claude/skills/`, `.claude/agents/` | Rarely changes except via `/upgrading`. Canonical on main; worktrees lag until they rebase. An upgrade run touches **only the checkout it runs in**, so after upgrading in main, live worktrees keep their branch-point framework files — `upgrading` **Step 8** enumerates live `forge/m-*` worktrees and offers to rebase each (never auto), and the opt-in `forge.worktree_rebase_check` watches these files as a boot-time safety net. Gitignored carve-outs (`.mcp.json`, experimental hooks) don't rebase — re-run the experimental installer if the upgrade changed them. |
304
-
305
- Cross-tree edits land on the current branch and are invisible to other worktrees
306
- until they pull/rebase. `forge` surfaces live worktrees at boot **and enforces
307
- the Live-Worktree Ownership Gate** (forge SKILL 1.1a): when invoked from main for
308
- a milestone that has a live worktree, milestone-owned writes are **blocked**
309
- until the operator enters the worktree, syncs it, retires it, or records an
310
- explicit `lifecycle.ownership_override`. `discussing` and `reviewing` warn before
311
- touching shared-mutable blocks; optional `forge.worktree_rebase_check` detects
312
- stale shared files inside worktrees. See
313
- [ADR-011](../docs/decisions/ADR-011-shared-state-taxonomy.md) for rationale.
314
-
315
- ### State Ownership rules (quick reference)
316
-
317
- - `state/milestone-{id}.yml` is the **single source of truth**; exactly one agent owns it at a time. **Other worktrees never write it** — and from a main checkout this is **enforced**, not just advised: the Live-Worktree Ownership Gate (forge SKILL 1.1a) blocks milestone-owned writes from main while a live worktree owns the milestone, with a recorded `lifecycle.ownership_override` as the only (never-silent) bypass.
318
- - Worktree / parallel agents write **only** their own milestone file and **append** desire-path files. They **never** write `index.yml`.
319
- - `index.yml` is **regenerated by rollup** (read every `milestone-*.yml` → rewrite the registry) by the main/orchestrator session — on `forge` resume and at `orchestrating` teardown. The rollup is deterministic + idempotent, so it **is** the reconcile step — never a hand-merge.
320
- - For shared-mutable files: write only your milestone's block; within a block, append-only (strike through, don't rewrite).
236
+ | **Single-owner mutable** | `state/milestone-{id}.yml`, `phases/milestone-{id}/`, `research/milestone-{id}.md` | Exactly one writer at a time — the checkout currently driving that milestone. Other worktrees never touch it (not even read-then-write; pull from main instead). |
237
+ | **Single-owner mutable (per stream)** | `streams/{stream}.yml`, `streams/{stream}/brief.md`, `streams/{stream}/packages/*.yml` | The stream's current driver writes them; distinct streams own distinct files no cross-stream contention. |
238
+ | **Derived (git-ignored render-on-read cache)** | `state/index.yml`, `streams/active.yml`, the rendered `release_state` column | Never hand-edited, **never committed** — regenerated by rollup from sources at every boot. Any session may render its own copy; absence on a fresh clone is normal (render-then-read; the sentinel is `project.yml`). |
239
+ | **Append-only shared** | `releases.yml`, `reservations.yml`, `state/desire-paths/*`, `deferred-issues/*` | Many writers OK; structure prevents collision (append-only entries / distinct filenames). |
240
+ | **Machine-local runtime** | `.git/forge/id-reservations`, `.git/forge/integration-pending` | Git common dir shared across a machine's worktrees, never git-tracked, excluded from framework context. |
241
+ | **Shared mutable** | `context.md`, `refactor-backlog.yml`, `requirements/m{N}.yml` | Write only your milestone/stream block; within a block, append-only strike through instead of rewriting. |
242
+ | **Stable shared** | `project.yml`, `constitution.md`, `design-system.md`, `roadmap.yml`, `FORGE.md`, `.claude/skills/`, `.claude/agents/` | Rarely changes except via `/upgrading` (registry default the npm bin is the sync engine; local dev sync only via explicit `/upgrading dev`). Canonical on main; worktrees lag until they rebase. An upgrade touches only its own checkout — `upgrading` Step 8 offers live-worktree rebases (never auto); opt-in `forge.worktree_rebase_check` is the boot-time net. Gitignored carve-outs (`.mcp.json`, experimental hooks) propagate via the experimental installer, not git. |
243
+
244
+ Ownership rules (quick reference):
245
+
246
+ - The milestone cursor has exactly one owner. From a main checkout this is **enforced**: the Live-Worktree Ownership Gate (`forge` SKILL 1.1a) blocks milestone-owned writes from main while a live worktree owns the milestone; a recorded `lifecycle.ownership_override` is the only — never-silent — bypass.
247
+ - Worktree/parallel agents write only their own milestone file and append desire-path files; they never write `index.yml` or `active.yml` — the rollup regenerates both and **is** the reconcile step, never a hand-merge.
248
+ - Cross-tree edits land on the current branch and are invisible to other worktrees until they pull/rebase; `forge` surfaces live worktrees at boot, and `discussing`/`reviewing` warn before touching shared-mutable blocks.
321
249
  - Same-milestone parallel work needs Chief/Streams contracts; M10 file claims are optional defense-in-depth.
322
250
 
323
251
  ### Version Reservation Protocol
324
252
 
325
- The project version + CHANGELOG slot are **shared resources**when two milestones run in parallel sessions, each independently bumping `package.json`/version and adding a CHANGELOG entry collides. `.forge/releases.yml` removes the number from per-milestone scope.
326
-
327
- - **Reserve early, at planning.** When a milestone's delivery will bump the version, the `planning` skill appends ONE entry to `.forge/releases.yml`: `{milestone, version, bump, reserved_at, summary}`. The reserved version = highest `version:` in the file bumped by the change's semver level (capability → minor; fix/doc → patch — see version-bump criteria below).
328
- - **Append-only — never edit prior entries.** Distinct lines = no cross-session conflict. Commit + push the reservation BEFORE editing the version file, so a parallel session pulls and sees the number taken.
329
- - **Delivery never invents a number.** The `executing`/delivery step writes only the version reserved in `releases.yml`, then its CHANGELOG entry. If no reservation exists (milestone planned before this file), it reserves at delivery: pull, take `max() + bump`, append, push, then write.
330
- - **Race resolution.** Two near-simultaneous reservations: the second push rebases onto the first (append-only → clean), re-reads `max()`, takes the next number.
331
-
332
- **Version-bump criteria (0.x projects):** patch (`0.x.y`) = bug fix, doc tweak, sync-only, refinement. Minor (`0.x.0`) = new skill/agent/routing-row/auto-trigger/state-artifact/capability. Major (`x.0.0`) = post-1.0 breaking change. Default to minor when in doubt — a capability addition shipped as a patch drifts the version away from truth.
253
+ The project version + CHANGELOG slot are shared resources — `.forge/releases.yml` (append-only) removes the number from per-milestone scope. **Reserve early, at planning**: append ONE `{milestone, version, bump, reserved_at, summary}` entry — the highest reserved version bumped by this change's semver level — and **commit + push the reservation BEFORE editing the version file** so a parallel session sees the number taken. Never edit prior entries. **Delivery never invents a number** — write only the reserved version; no reservation → reserve at delivery (pull, `max() + bump`, append, push, then write). **Race:** the second push rebases onto the first (append-only → clean), re-reads `max()`, takes the next number. **Bump criteria (0.x):** patch = bug fix/doc/sync/refinement; minor = new skill/agent/routing-row/auto-trigger/state-artifact/capability; major = post-1.0 breaking. Default to minor when in doubt — a capability shipped as a patch drifts the version away from truth.
333
254
 
334
255
  ### ID Reservation Protocol
335
256
 
336
- Sequential IDs — `ADR-NNN` (decision records), `DEF-NNN` (deferred requirements), `FR-NNN`/`NFR-NNN` (requirements), plus milestone ids (`M-NN`) and refactor-backlog ids (`R0NN`) — are **shared cross-worktree resources** the same way the version number is. "Scan the tree for the highest and increment" only sees *committed* state, so two worktrees branched from the same baseline each claim the same next number and collide **silently until merge** a costly multi-file renumber pass. [ADR-016](../docs/decisions/ADR-016-id-reservation-protocol.md) tried to fix this by reserving in the branch-tracked `reservations.yml` and *committing + pushing before allocating*, but a reservation on an unmerged branch is invisible to every sibling worktree (they share `.git`, not branches) — so collisions continued. [ADR-021](../docs/decisions/ADR-021-id-reservation-ledger-git-common-dir.md) (**supersedes ADR-016**) moves the coordination point to a **machine-local ledger in the git common dir**, the same primitive as the integration flag: every sibling worktree of the repo on a machine sees it the moment it is written no push, no pull, no merge.
337
-
338
- - **Reserve with the helper.** `forge-reserve <kind> --milestone <id> [--summary <text>]` (`.claude/hooks/forge-reserve.sh`, `kind ∈ {adr, def, fr, nfr, milestone, refactor}`) allocates the next number under a portable `mkdir` lock and prints it on stdout. Id formats differ per kind (ADR-023): `adr/def/fr/nfr` → `PREFIX-0NN` (hyphen, zero-padded); `milestone` → `M-NN` (hyphen, **unpadded** — ids are used bare, `milestone-26.yml`/`m-26`); `refactor` → `R0NN` (**no hyphen**, zero-padded — matches the backlog convention). It **dual-writes**: one TSV line to `.git/forge/id-reservations` (the machine-local coordination ledger) and one `{kind, id, milestone, reserved_at, summary}` block to the tracked `.forge/reservations.yml`. Neither is committed by the helper — **the caller commits `reservations.yml` with its work** (unchanged handoff). Reserve *before* creating the artifact; the printed id is the one to use.
339
- - **Next number = `max(ledger ∪ in-tree ∪ main:reservations.yml) + 1` per kind.** Three inputs, unioned: the **ledger** (same-machine siblings, *including uncommitted* — the input ADR-016 could not see), the **in-tree** landed ids, and **`main:reservations.yml`** (the cross-machine / cold-start floor). The in-tree scan is per-kind: `adr` → `docs/decisions/ADR-NNN*`; `fr/nfr/def` → `.forge/requirements/*.yml`; `milestone` → live `state/milestone-*.yml` **∪ archived** `.forge/archive/milestone-*/`; `refactor` → `refactor-backlog.yml` **∪** `refactor-backlog-archive.yml` (ADR-023 — reading archives means a compacted/archived id is never reallocated). Taking all three inputs keeps it backward-compatible (landed & pre-ledger IDs respected) while giving the ledger authority for the same-machine hot path.
340
- - **`reservations.yml` is now the durable audit trail + cross-machine floor**, not the coordination mechanism. Append-only, distinct lines → it unions cleanly at merge (it stops being a merge-conflict source). An optional `forge-reserve --verify` can diff ledger vs. `reservations.yml`.
341
- - **Reserve points.** `architecting` reserves an `adr` before authoring it; `planning` reserves `fr`/`nfr`/`def` before writing them into requirements; the three milestone-id sites (`forge` Rollup, `discussing`, `prototyping`) reserve `milestone`; `reviewing` reserves `refactor` for a new backlog id — all via `forge-reserve` (ADR-023).
342
- - **DI-NNN eliminated, not reserved (ADR-023).** `executing`'s deferred-*issue* ids used to be a scan-and-increment `DI-NNN` counter in a single `deferred-issues.md` — the same cross-worktree collision in kind. Rather than reserve them, deferred issues are now **counter-free per-issue files** under `.forge/deferred-issues/` (`{date}-{milestone}-{slug}.md`, the desire-path pattern): distinct filenames, no shared counter, nothing to collide on. Nothing cross-references a deferred issue by number, so the id density reservation buys is worthless here. Legacy `deferred-issues.md` is still read until migrated.
343
- - **Cross-machine gap (accepted).** The ledger is machine-local (like `integration-pending`). Two *concurrent* worktrees on *different* laptops, both reserving before either merges, still fall back to merge-time renumber — bounded by the `main:reservations.yml` floor, so no worse than ADR-016.
344
- - **Lazy migration.** No ledger ⇒ the helper creates it on first reserve, seeded by the `max()` (which reads in-tree + `main:reservations.yml`). Existing `reservations.yml` is untouched and still respected. Projects that never run concurrent worktrees see no behavior change.
345
-
346
- This is the cross-worktree mechanism the FR/DEF/NFR "globally unique" rule (State Management, above) previously lacked, now made collision-safe for same-machine worktrees. Versions stay in `releases.yml` (separate semver/CHANGELOG semantics); everything else reserves through `forge-reserve`.
257
+ Sequential ids — `ADR-NNN`, `DEF-NNN`, `FR-`/`NFR-NNN`, milestone `M-NN`, refactor `R0NN` — are shared cross-worktree resources; scan-and-increment sees only committed state, so concurrent worktrees claim the same number and collide silently until merge. **Reserve with the helper before creating the artifact**: `forge-reserve <kind> --milestone <id> [--summary <text>]` (`.claude/hooks/forge-reserve.sh`, kinds `adr|def|fr|nfr|milestone|refactor`; id formats per [ADR-023](../docs/decisions/ADR-023-extend-id-reservation-to-milestone-refactor-ids.md)) prints the id and dual-writes the **machine-local ledger** (`.git/forge/id-reservations`, git common dir — the same-machine coordination point, written under a `mkdir` lock) plus the tracked `.forge/reservations.yml` (durable audit trail + cross-machine floor; the caller commits it with the work). **Next number = `max(ledger in-tree main:reservations.yml) + 1`** per kindthe in-tree scan includes archives, so a compacted id is never reallocated. Reserve points: `architecting` (adr), `planning` (fr/nfr/def), `forge` Rollup / `discussing` / `prototyping` (milestone), `reviewing` (refactor). Deferred issues are counter-free per-issue files (`.forge/deferred-issues/{date}-{milestone}-{slug}.md`) no DI-NNN, nothing to collide on. Accepted gap: concurrent reserves on *different machines* fall back to merge-time renumber, bounded by the floor. On any residual collision (legacy/un-reserved ids), **keep the older milestone's id and renumber the newer**. Lazy migration — the ledger self-creates on first reserve. Full rationale: [ADR-021](../docs/decisions/ADR-021-id-reservation-ledger-git-common-dir.md) (supersedes ADR-016) + ADR-023. Versions stay in `releases.yml` (separate semver/CHANGELOG semantics).
347
258
 
348
259
  ## Deviation Rules
349
260
 
@@ -373,34 +284,22 @@ verification:
373
284
  max_retries: 2 # max attempts per command
374
285
  ```
375
286
 
376
- - Auto-detected from `package.json` scripts during init
377
- - Advisory mode: pre-existing failures warn, don't block
378
- - Auto-fix loop: read output → fix → amend → re-run (up to max_retries)
379
- - 3-strike: retries count toward task limit
380
- - Empty commands = no gate (opt-out)
381
- - `verification.e2e_soft_cap` (default 10) — advisory cap on `e2e:true` stories per milestone surfaced by the `reviewing` skill. Soft — never blocks.
287
+ Auto-detected from `package.json` at init. Advisory mode warns, never blocks. Auto-fix loop: read output → fix → amend → re-run (≤ `max_retries`; retries count toward the 3-strike task limit). Empty commands = no gate (opt-out). `verification.e2e_soft_cap` (default 10) — advisory per-milestone cap on `e2e:true` stories, surfaced by `reviewing`, never blocks.
382
288
 
383
289
  ### Truth checks (executable must_haves)
384
290
 
385
- Plans MAY declare a per-truth `check:` shell command in `must_haves.truths` (exit 0 = pass; authored goal-backward at planning, before code exists; linted by planning Step 8 dimension 10). `executing` runs declared checks once at plan completion (early fix-loop signal, never a verdict); `verifying` re-executes them and applies the **executed-evidence rule**: VERIFIED only with a recorded command + exit code + output excerpt — no executed evidence → UNCERTAIN or human-route, never VERIFIED. Legacy bare-string truths stay valid; details live in the planning/executing/verifying skills + plan template.
291
+ Plans MAY declare a per-truth `check:` shell command in `must_haves.truths` (exit 0 = pass; authored goal-backward at planning, before code exists; linted by planning Step 8). `executing` runs declared checks once at plan completion (early fix-loop signal, never a verdict); `verifying` re-executes them and applies the **executed-evidence rule**: VERIFIED only with a recorded command + exit code + output excerpt — no executed evidence → UNCERTAIN or human-route, never VERIFIED. Legacy bare-string truths stay valid.
386
292
 
387
293
  ### Human Verification Gate (close precondition)
388
294
 
389
- **No milestone reaches `complete` and no orchestration worktree is torn down until a human has explicitly signed off** — recorded as `current.human_verified` in `milestone-{id}.yml`. Code-level verification (tests, lint, type-check, the 3-level goal-backward pass) is necessary but **never sufficient** to close a milestone. A human must confirm the work in whatever form fits the milestone — device session, visual check, e2e walk, smoke test ("of some sorts").
390
-
391
- - **Captured** by `verifying` — after the verdict it prompts for explicit sign-off and writes `current.human_verified: {at, method, notes}`. If the human can't verify yet (e.g. a device session is still pending), the field stays unset and downstream close blocks.
392
- - **Enforced (hard block)** at both close points — `reviewing` refuses to set `current.status: complete`, and `orchestrating` Step 5 refuses teardown of **un-merged** work (see the teardown split below), unless `current.human_verified` is present.
393
- - **Recorded override** is the only bypass. A human may explicitly close without verifying, but the skill writes `human_verified: {method: override, override: true, reason}` and surfaces it in the report. Silent close is impossible — an agent must **never** present milestone close / orchestration teardown as a peer alternative to "do the verification". The verification is a precondition, not an option.
394
-
395
- Lazy migration: milestones with no `human_verified` field (pre-0.27.0) simply hit the prompt on their next close transition; already-`complete` milestones are never re-gated.
396
-
397
- **Per-binding relocation (B5, operator-ratified 2026-07-15).** The gate above is the **`in_session_signoff`** binding — the default (`forge.validation_event` absent ⇒ this), preserved exactly. A repo that opts into **`validation_event: promotion_approval`** relocates the human gate to the **deploy boundary**: `complete` becomes the machine/code-verified state (`reviewing` closes without in-session sign-off, its health report noting *"human gate: at promotion (B5)"*), and the derived `release_state: validated` — computed by `forge-release-fold.sh` when a CI-signed promotion tag covers the unit — **is** the human gate (the full release_state ladder lands in State Management with phase 52). The mode is **not agent-flippable**: `validation_event`/`project.yml` sits on the step-2 **protected-paths** hold (F4/F5), so a diff flipping it blocks auto-merge for operator review.
398
-
399
- **Teardown splits on merged-ness (operator ruling 2026-07-16 — binding-independent).** Worktree teardown auto-proceeds when the unit renders `merged`/`validated` via `forge-release-fold.sh` — the work is on main; removing the worktree loses nothing. The human gate applies only to **un-merged** teardown. The close gate is unaffected by this split — it keeps the per-binding rule above.
400
-
401
- **Grandfather (legacy-complete marker).** A milestone already stored `current.status: complete` with **no** `signoff/<wu-id>` tag (the pre-M0 history — 26 milestones as of 0.53.0) is **grandfathered**: readers honor it as complete and it is **never re-gated** by any later sign-off convention. "Complete with no signoff tag" **is** the legacy-complete marker — no field is stamped onto those files. Only *new* completions going forward can be asked to carry a signature (that forward-gate is autonomous-lane and is **not** wired in the attended lane — see below).
295
+ **No milestone reaches `complete` and no un-merged orchestration worktree is torn down until a human has explicitly signed off** — recorded as `current.human_verified` in `milestone-{id}.yml`. Code-level verification (tests, lint, the 3-level goal-backward pass) is necessary but **never sufficient**.
402
296
 
403
- **Where the Contract M0 sign-off convention is adopted, `human_verified` is a derived echo, not the source of truth.** The authoritative predicate becomes `verify-signoff <wu-id>` exiting 0 an SSH-signed `signoff/<wu-id>` tag an agent cannot forge (see `docs/sign-off-convention.md` and `.claude/hooks/{verify-signoff,wu-done}.sh`). `current.human_verified` may still be written for human-readable display, but treat it as a cache of the signature check, never the gate itself. Core does not yet wire this predicate into `verifying`/`reviewing`'s own hard-block logic automatically — that remains a flagged follow-up (Contract M0 §D2 scoped to a minimal fold stub, not the full skill wiring).
297
+ - **Captured** by `verifying` — prompts for explicit sign-off after the verdict; if the human can't verify yet, the field stays unset and downstream close blocks.
298
+ - **Enforced (hard block)** at both close points — `reviewing` refuses `current.status: complete`, and `orchestrating` refuses teardown of un-merged work — unless the field is present.
299
+ - **Recorded override** is the only bypass (`human_verified: {method: override, override: true, reason}`), echoed in the report. Silent close is impossible; an agent must never present override as a peer alternative to doing the verification.
300
+ - **Teardown splits on merged-ness** (binding-independent): teardown auto-proceeds when the unit renders `merged`/`validated` via the fold — the work is on main, removal loses nothing; the human gate applies to **un-merged** teardown only. The close gate is unaffected by this split.
301
+ - **Bindings ([ADR-024](../docs/decisions/ADR-024-merged-validated-fold.md)):** default `in_session_signoff` preserves this gate exactly. `promotion_approval` relocates the human gate to the deploy boundary — `complete` becomes the machine-verified state and the derived `validated` (CI-signed promotion tag, verified offline) **is** the human gate. The mode is not agent-flippable (`validation_event` sits on protected paths).
302
+ - **Migration:** lazy — pre-gate milestones simply hit the prompt on their next close; milestones already `complete` with no `signoff/<wu-id>` tag are grandfathered, never re-gated. Where the M0 sign-off convention is adopted (`docs/sign-off-convention.md`), the authoritative predicate is `verify-signoff <wu-id>` exiting 0 — an SSH-signed tag an agent cannot forge; `current.human_verified` is then a derived echo, never the gate itself.
404
303
 
405
304
  ## Beads Integration (Optional)
406
305
 
@@ -408,7 +307,4 @@ With Beads installed: `bd prime` (session context), `bd ready` (unblocked tasks)
408
307
 
409
308
  ## Atomic Commits
410
309
 
411
- One commit per task. Format: `{type}({scope}): {description}`
412
- Types: `feat`, `fix`, `test`, `refactor`, `chore`, `docs`
413
- Never `git add .` or `git add -A` — stage individually.
414
- Phase handoffs additionally emit one scoped `chore(forge): sync state …` commit (see State Commit Protocol) so `.forge/` state never drifts out of git.
310
+ One commit per task. Format: `{type}({scope}): {description}` — types `feat fix test refactor chore docs`. Never `git add .` or `git add -A` — stage individually. Phase handoffs additionally emit one scoped `chore(forge): sync state …` commit (State Commit Protocol) so `.forge/` state never drifts out of git.