forge-orkes 0.36.0 → 0.37.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forge-orkes",
3
- "version": "0.36.0",
3
+ "version": "0.37.0",
4
4
  "description": "Set up the Forge meta-prompting framework for Claude Code in your project",
5
5
  "bin": {
6
6
  "create-forge": "./bin/create-forge.js"
@@ -41,12 +41,13 @@ questions return to the Chief before work continues.
41
41
 
42
42
  ## Context Loading
43
43
 
44
- 1. Read `.forge/streams/active.yml` first.
45
- 2. If missing, create it from `.forge/templates/streams/active.yml`.
46
- 3. Load only the selected stream's `.forge/streams/{stream}.yml`.
47
- 4. Load the selected stream's `brief.md` when the user needs status, handoff,
44
+ `active.yml` is **derived** (ADR-015) — regenerate it, don't read a possibly-stale copy and never hand-edit it.
45
+
46
+ 1. **Run the Stream Rollup** (below) to regenerate `.forge/streams/active.yml` from the per-stream files + active milestones, then read it. No `streams/` dir and no active milestones → nothing to roll up.
47
+ 2. The per-stream files `.forge/streams/{stream}.yml` are the **source of truth** — load the selected stream's file for detail.
48
+ 3. Load the selected stream's `brief.md` when the user needs status, handoff,
48
49
  conflict context, or resume context.
49
- 5. Load work packages only when delegating, checking worker status, or closing
50
+ 4. Load work packages only when delegating, checking worker status, or closing
50
51
  a stream.
51
52
 
52
53
  Keep summaries in the registry short. Deep history belongs in stream briefs,
@@ -56,54 +57,50 @@ packages, plans, verification reports, commits, and archived artifacts.
56
57
 
57
58
  | Intent | Examples | Action |
58
59
  |--------|----------|--------|
59
- | Show | "show streams", "active streams", "what is running?" | Run Registry Drift Check + Merge Cadence Check, then summarize registry without loading all deep history |
60
+ | Show | "show streams", "active streams", "what is running?" | Run Stream Rollup + Merge Cadence Check, then summarize the derived registry without loading all deep history |
60
61
  | Start | "start stream X", "new stream for billing" | Snapshot current stream, create stream files, register stream |
61
62
  | Pause | "pause stream X" | Update brief, mark paused, keep next action explicit |
62
63
  | Resume | "resume stream X" | Load stream context, set active, surface blockers and ownership |
63
64
  | Delegate | "delegate stream X", "farm this out" | Create or update a work package and handoff prompt |
64
65
  | Adopt M10 | "adopt existing M10 worktrees", "migrate active orchestrating sessions" | Wrap live M10 worktrees as streams without teardown |
65
- | Sync | "sync streams" | Run Registry Drift Check + Merge Cadence Check, then refresh registry summaries from active stream briefs |
66
+ | Sync | "sync streams" | Update per-stream files from briefs, run Stream Rollup + Merge Cadence Check to regenerate the derived registry |
66
67
  | Detect Conflicts | "detect conflicts", "check stream conflicts" | Compare ownership and dependencies |
67
68
  | Merge Safe | "merge safe?", "what can land?" | Identify ready streams with no blocking conflicts |
68
69
  | Close | "close stream X" | Record final status, archive/mark closed, clear active pointer if needed |
69
70
 
70
- ## Registry Drift Check
71
-
72
- Forge keeps two registries that both describe "what work is active," with no
73
- automatic reconciliation: `.forge/state/index.yml` (milestones, owned by the
74
- `forge` skill) and `.forge/streams/active.yml` (streams, owned by the Chief).
75
- `/forge` and `/chief-of-staff` can therefore present different pictures of the
76
- project. Run this check at the **start of the Show and Sync intents** so the
77
- divergence is surfaced instead of silently left to the operator.
78
-
79
- This is **advisory — it never blocks, never auto-creates a milestone, and never
80
- auto-writes a stream.** It reports, and offers.
81
-
82
- 1. Read active milestones from `.forge/state/index.yml` (those with
83
- `status: active`). If the file is absent, skip the check silently — a
84
- streams-only project has nothing to reconcile.
85
- - Note: invoking `/chief-of-staff` directly bypasses `forge`'s boot preflight,
86
- so `index.yml` may be stale (it is regenerated by `forge`'s Rollup, not by
87
- the Chief). Read it as-is; do not run Rollup from the Chief. If it looks
88
- stale, say so and suggest a `/forge` pass.
89
- 2. Read the stream registry from `.forge/streams/active.yml`.
90
- 3. Map each active milestone to a stream by id, trying these forms in order:
91
- `m-{id}`, `milestone-{id}`, bare `{id}`, and any stream whose
92
- `context.milestone` points at `.forge/state/milestone-{id}.yml`.
93
- 4. Report each mismatch:
94
- - **Active milestone with no stream** → offer to add it as a `paused` stream
95
- (do not create it automatically). Quick-fix milestones legitimately may not
96
- warrant a stream let the operator decide.
97
- - **Stream pointing at a `deferred`, `complete`, or absent milestone** → the
98
- stream's status should follow its milestone; offer to update it (pause a
99
- stream whose milestone deferred, close one whose milestone completed).
100
- - **Stream with no milestone counterpart** informational only. Quick-fix
101
- streams are valid; never auto-create a milestone for them.
102
- 5. If everything maps cleanly, say so in one line (`registries aligned`) and
103
- continue to the intent.
104
-
105
- Keep the output compact — a few lines under a `Registry drift:` header, then
106
- proceed with the requested Show/Sync.
71
+ ## Stream Rollup (active.yml is derived)
72
+
73
+ `active.yml` is a **derived projection**, not a hand-maintained registry it is
74
+ regenerated by joining the per-stream files with active milestones (ADR-015,
75
+ FORGE.md Stream Rollup). This **replaces** the old advisory Registry Drift Check:
76
+ drift between the milestone view and the stream view can no longer occur, because
77
+ every field has one source and coverage is computed into the artifact. Run the
78
+ rollup at the **start of Show and Sync**, and after any Start/Resume/Pause/Close
79
+ edit to a stream file.
80
+
81
+ Procedure (deterministic + idempotent never hand-edit `active.yml`):
82
+
83
+ 1. Glob `.forge/streams/{stream}.yml`. Each → a row: `coordination` = the file's
84
+ `status`; plus goal, runtime (branch/worktree), ownership summary,
85
+ `merge_readiness` (from `merge.readiness`), `blocked_by`, `next_action`.
86
+ 2. For a stream with `stream.milestone: m-{id}`, read `phase` + activity from
87
+ `.forge/state/milestone-{id}.yml` (`current.status`, `last_updated`) do not
88
+ store workflow phase in the stream file. Linked milestone `deferred`/`complete`/
89
+ absent `phase` reflects that (and surface it: a deferred milestone's stream
90
+ should likely pause; offer it).
91
+ 3. Glob active milestones (`index.yml` `status: active`). Any with **no** stream
92
+ file → emit a derived `stream: implicit` row (phase from the milestone, no
93
+ coordination) so coverage is guaranteed — an active milestone is never silently
94
+ missing. Offer to materialize a stream file if it needs coordination (never
95
+ auto-create).
96
+ 4. Derive `merge_queue:` one entry per stream with `merge.readiness: ready`.
97
+ 5. Write `active.yml` (`version`, `updated_at`, derived `streams:` sorted by id,
98
+ derived `merge_queue:`). No hand-edited keys.
99
+
100
+ Note: invoked directly, `/chief-of-staff` does not run `forge`'s milestone Rollup,
101
+ so `index.yml` may be slightly stale; read it as-is for step 3 and suggest a
102
+ `/forge` pass if it looks off. The Chief writes `active.yml` (derived class); it
103
+ never writes `index.yml` or any milestone file.
107
104
 
108
105
  ## Start Stream Flow
109
106
 
@@ -117,7 +114,7 @@ proceed with the requested Show/Sync.
117
114
  - `.forge/streams/{id}.yml` from `.forge/templates/streams/stream.yml`
118
115
  - `.forge/streams/{id}/brief.md` from `.forge/templates/streams/brief.md`
119
116
  - `.forge/streams/{id}/packages/`
120
- 5. Add a compact entry to `.forge/streams/active.yml`.
117
+ 5. Set the new stream file's `stream.milestone` link if it backs a milestone (else leave null for a standalone stream), then **regenerate `active.yml` via the Stream Rollup** — do not hand-write a registry entry.
121
118
  6. Declare ownership:
122
119
  - `owned_surfaces` for files or areas the stream may edit
123
120
  - `shared_surfaces` for contracts, APIs, schemas, or docs touched with care
@@ -133,7 +130,7 @@ user asks to move to Chief/Streams. Do not teardown, merge, rebase, or remove
133
130
  worktrees as part of adoption. Adoption only creates stream metadata around
134
131
  existing M10 state.
135
132
 
136
- 1. Read or create `.forge/streams/active.yml`.
133
+ 1. Ensure the `.forge/streams/` dir exists (`active.yml` is derived — it will be regenerated by the rollup in step 8, not hand-created).
137
134
  2. Discover live M10 worktrees from both sources:
138
135
  - `git worktree list --porcelain` branches matching `refs/heads/forge/m-*`
139
136
  - `.forge/state/milestone-*.yml` with
@@ -174,7 +171,7 @@ existing M10 state.
174
171
  - known blockers
175
172
  - unknown ownership surfaces marked as needing declaration
176
173
  - next action from milestone state or "declare ownership and sync"
177
- 8. Add or update the compact entry in `.forge/streams/active.yml`.
174
+ 8. **Regenerate `active.yml` via the Stream Rollup** (do not hand-write the entry); set the adopted stream's `stream.milestone` link so its phase derives from milestone state.
178
175
  9. Run conflict detection. Missing ownership is a conflict until clarified, but
179
176
  it does not block adoption.
180
177
  10. Ask before changing `.forge/project.yml`:
@@ -190,14 +187,14 @@ or path, update its summary and brief instead of creating a duplicate stream.
190
187
  Pause:
191
188
  1. Update the stream brief with current state, decisions, blockers, and next
192
189
  action.
193
- 2. Set registry status to `paused`, unless work was handed to another session
194
- and should be `delegated`.
190
+ 2. Set the **stream file's** `status` to `paused` (or `delegated` if handed off),
191
+ then regenerate `active.yml` via the Stream Rollup.
195
192
  3. Clear `current_stream` only if no stream remains active in this session.
196
193
 
197
194
  Resume:
198
- 1. Load registry, stream file, and brief.
195
+ 1. Run the Stream Rollup, then load the stream file and brief.
199
196
  2. Surface status, blockers, owned surfaces, shared surfaces, and next action.
200
- 3. Set the stream to `active`.
197
+ 3. Set the **stream file's** `status` to `active`, then regenerate `active.yml`.
201
198
  4. Run conflict detection before continuing.
202
199
 
203
200
  ## Delegate Flow
@@ -262,7 +259,7 @@ reason it cannot merge yet.
262
259
  drifts from main, staleness accrues on shared surfaces, and the eventual merge is
263
260
  larger and riskier. This check makes the cadence visible so integration happens
264
261
  when work is ready — not at milestone end. Run it at the **start of the Show and
265
- Sync intents**, after the Registry Drift Check.
262
+ Sync intents**, after the Stream Rollup (which gives it a fresh derived registry).
266
263
 
267
264
  **Advisory — it surfaces and recommends. It never merges, never rebases, and
268
265
  never blocks.** Merging and rebasing stay human decisions (conflicts need
@@ -304,7 +301,8 @@ line (`merge cadence: nothing ready, no rebases needed`) and continue.
304
301
 
305
302
  1. Confirm final status: merged, intentionally abandoned, superseded, or split.
306
303
  2. Record final outcome in the stream brief.
307
- 3. Update registry status to `closed`.
304
+ 3. Set the **stream file's** `status` to `closed`, then regenerate `active.yml`
305
+ via the Stream Rollup.
308
306
  4. Clear `current_stream` if this was the active stream.
309
307
  5. Keep closed stream history available until a later archive/compaction pass.
310
308
 
@@ -45,7 +45,9 @@ git worktree list --porcelain 2>/dev/null \
45
45
 
46
46
  Cross-machine note: the flag file is machine-local, so a worktree on another laptop relies on the opt-in `forge.worktree_rebase_check` / a periodic fetch instead — eventual, not instant.
47
47
 
48
- **Ready-to-merge nudge (main checkout / streams without checkpoints).** If `.forge/streams/active.yml` exists, scan for streams with `status: ready` or a non-empty `merge_queue` **that are not auto-publishing via checkpoints**. Any present one line: *"{N} stream(s) ready to merge run `/chief-of-staff` (merge safe) to integrate."* Pointer only the cadence logic lives in the Chief's Merge Cadence Check; `forge` never merges. Nothing pending silent.
48
+ **Stream Rollup (active.yml is derived).** If `.forge/streams/` has any stream files, regenerate `.forge/streams/active.yml` from them + active milestones per FORGE.md Stream Rollup, the same way step 1.0 regenerates `index.yml`. `active.yml` is derived never read it as authoritative without rolling up first, and never hand-edit it. Runs in the main checkout (worktrees never write `active.yml`). No `streams/` dirskip.
49
+
50
+ **Ready-to-merge nudge (main checkout / streams without checkpoints).** From the just-regenerated `active.yml`, scan for streams with `coordination: ready` or a non-empty `merge_queue` **that are not auto-publishing via checkpoints**. Any present → one line: *"{N} stream(s) ready to merge — run `/chief-of-staff` (merge safe) to integrate."* Pointer only — the cadence logic lives in the Chief's Merge Cadence Check; `forge` never merges. Nothing pending → silent.
49
51
 
50
52
  ### 1.0 State Rollup (index.yml is derived)
51
53
 
@@ -202,8 +202,8 @@ State lives in `.forge/`:
202
202
  - `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).
203
203
  - `context.md` — Active locked decisions + deferred ideas (target <=12KB)
204
204
  - `context-archive.md` — Historical locked decisions; load only when relevant
205
- - `streams/active.yml` — Compact Project Chief traffic map: active stream summaries only.
206
- - `streams/{stream}.yml` — Per-stream state: lifecycle, ownership, shared surfaces, blockers, merge readiness.
205
+ - `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`. 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).
206
+ - `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).
207
207
  - `streams/{stream}/brief.md` — Human-readable stream context packet loaded when resuming that stream.
208
208
  - `streams/{stream}/packages/{id}.yml` — Work package contract for delegated workers or manual sessions.
209
209
  - `research/milestone-{id}.md` — Research findings snapshot (dated, immutable)
@@ -215,6 +215,15 @@ State lives in `.forge/`:
215
215
 
216
216
  **Milestones** group phases into concurrent streams. Own state file — no conflicts across sessions. Can be deferred (frozen in place) or archive-deleted.
217
217
  `index.yml status` gates routing: `not_started | active | deferred | complete`.
218
+
219
+ **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:
220
+ 1. Glob `streams/{stream}.yml`. Each → a row carrying its coordination state (`coordination` = the file's `status`), goal, runtime, ownership summary, `merge.readiness`, blockers, next action — all from the stream file.
221
+ 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.
222
+ 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.
223
+ 4. Derive `merge_queue:` — one entry per stream with `merge.readiness: ready`.
224
+ 5. Write `active.yml` (`version`, `updated_at`, derived `streams:` sorted by id, derived `merge_queue:`). No hand-edited keys.
225
+
226
+ 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.
218
227
  **Format**: YAML for machine state, Markdown for human content.
219
228
  **`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).
220
229
 
@@ -237,7 +246,7 @@ with the work it describes. Every artifact has a sharing class:
237
246
  | Class | Files | Write rule |
238
247
  |---|---|---|
239
248
  | **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. |
240
- | **Derived** | `state/index.yml` | Never hand-edited. Regenerated by Rollup 1.0 from `milestone-*.yml`. Only the main/orchestrator session runs rollup. |
249
+ | **Derived** | `state/index.yml`, `streams/active.yml` | Never hand-edited. 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). Only the main/orchestrator session (and `chief-of-staff` for `active.yml`) runs rollup. |
241
250
  | **Append-only shared** | `releases.yml` (version reservations), `state/desire-paths/*` (one file per observation) | Many writers OK; structure prevents collision. `releases.yml` uses the Version Reservation Protocol (append + commit + push before depending on the slot); desire-paths use distinct filenames so two writers never touch the same file. |
242
251
  | **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. |
243
252
  | **Stable shared** | `project.yml`, `constitution.md`, `design-system.md`, `roadmap.yml`, `FORGE.md` | Rarely changes after init. Canonical on main. Worktrees lag and pull on rebase. No special protocol — git handles it because the conflict surface is tiny. |
@@ -0,0 +1,78 @@
1
+ # Migration Guide: Derived stream registry / Stream Rollup (Forge 0.37.0)
2
+
3
+ Applies to projects using Chief/Streams that have a **hand-maintained
4
+ `.forge/streams/active.yml` with stream entries**. `active.yml` becomes a
5
+ **derived projection** (ADR-015) — regenerated by the Stream Rollup from the
6
+ per-stream files + active milestones, never hand-edited. This is the durable fix
7
+ for issue [#4](https://github.com/Attuned-Media/forge/issues/4) and supersedes
8
+ the 0.33.0 Registry Drift Check.
9
+
10
+ The only thing that needs migrating is **data that lives only in `active.yml`**:
11
+ if a stream was tracked as a registry row but has no `.forge/streams/{stream}.yml`
12
+ source file, the rollup (which reads per-stream files) would drop it. The
13
+ migration materializes those files first, then lets the rollup regenerate
14
+ `active.yml`.
15
+
16
+ Projects with no streams, or whose `active.yml` is the empty stub, need nothing —
17
+ the next `forge` boot / `chief-of-staff` Show simply regenerates it in the derived
18
+ shape. (That is why Detection only fires when there are real stream rows.)
19
+
20
+ ## Prerequisites
21
+
22
+ 1. On the new version's framework files (`npx forge-orkes upgrade`, or the
23
+ `upgrading` skill).
24
+ 2. Working tree clean or changes committed — the migration writes per-stream
25
+ files and rewrites `active.yml`.
26
+
27
+ ## Detection
28
+
29
+ Fires only when `active.yml` is the **old hand-maintained shape** (no derived
30
+ marker) **and** carries real stream rows. Silent otherwise — already derived, no
31
+ streams, or no file:
32
+
33
+ ```bash
34
+ F=.forge/streams/active.yml
35
+ [ -f "$F" ] || exit 0
36
+ grep -q 'DO NOT HAND-EDIT' "$F" && exit 0 # already derived (new template marker)
37
+ if grep -qE '^[[:space:]]*-?[[:space:]]*id:[[:space:]]*\S' "$F"; then
38
+ echo "MIGRATE — active.yml is hand-maintained with stream entries (pre-ADR-015); materialize per-stream files, then it becomes derived"
39
+ fi
40
+ ```
41
+
42
+ ## Migration steps
43
+
44
+ ### 1. Ensure every registry stream has a source file
45
+
46
+ For each stream row in the current `active.yml`, confirm a
47
+ `.forge/streams/{id}.yml` exists. For any that don't, create one from
48
+ `.forge/templates/streams/stream.yml` and copy the row's data into it:
49
+
50
+ - `stream.status` ← the row's status (coordination lifecycle);
51
+ - `stream.milestone` ← `m-{id}` if the stream backs a milestone, else leave
52
+ `null` (standalone / quick-fix stream);
53
+ - `runtime.branch` / `runtime.worktree`, `ownership.*`, `merge.readiness`,
54
+ `blockers`, `next_action` ← from the row.
55
+
56
+ Do **not** copy a workflow phase into the stream file — that derives from the
57
+ linked milestone.
58
+
59
+ ### 2. Regenerate `active.yml` (derived)
60
+
61
+ Run `chief-of-staff` Show (or `/forge` boot) — it runs the Stream Rollup and
62
+ rewrites `active.yml` in the derived shape (header marker, `phase` + `coordination`
63
+ per row, derived `merge_queue`, plus `implicit` rows for active milestones with no
64
+ stream file). From here `active.yml` is regenerated, never hand-edited.
65
+
66
+ <!-- Lossy step (materializing files from registry rows) — confirm with the user
67
+ before writing if any row's data is ambiguous. Runs via quick-tasking. -->
68
+
69
+ ## Validation
70
+
71
+ - `head -5 .forge/streams/active.yml` shows the `DERIVED — DO NOT HAND-EDIT`
72
+ marker.
73
+ - Every stream that was in the old registry has a `.forge/streams/{id}.yml`
74
+ source file.
75
+ - Re-running `chief-of-staff` Show produces byte-identical `active.yml` (the
76
+ rollup is idempotent).
77
+ - No active milestone is missing from the map (active milestones with no stream
78
+ file appear as `stream: implicit` rows).
@@ -112,6 +112,11 @@ releases:
112
112
  bump: minor
113
113
  reserved_at: "2026-06-21"
114
114
  summary: "Stream Integration Checkpoints — event-driven continuous integration, the producer/flag/consumer follow-up to #8's polling-based cadence check. (1) planning marks integration_checkpoint phases in plan frontmatter (advisory; default = last phase + depended-on phases; the mark is the opt-in so unmarked/existing work is unaffected). (2) Producer: verifying, on a PASSED + human-verified checkpoint phase in a worktree, fast-forward-only publishes to main (git push origin HEAD:main — git rejects non-ff, which is the safety; diverged main is surfaced, never forced) and sets an integration flag in .git/forge/integration-pending (git common dir, shared across a machine's worktrees). (3) Consumer: forge boot in a worktree reads the flag cheaply — set + no divergence → auto git merge --ff-only main (conflict-free); diverged → surface a rebase prompt; not set → skip (no fetch, no scan). Supersedes the 0.35.0 forge-boot polling pointer with event-driven detection. Cross-machine falls back to opt-in worktree_rebase_check. Never force-pushes, auto-resolves a conflict, or auto-rebases."
115
+ - milestone: 16
116
+ version: "0.37.0"
117
+ bump: minor
118
+ reserved_at: "2026-06-22"
119
+ summary: "Derived stream registry / Stream Rollup (ADR-015) — the durable structural fix for issue #4's registry drift, superseding the 0.33.0 advisory Registry Drift Check. streams/active.yml becomes a DERIVED projection (like state/index.yml), never hand-edited, regenerated by a deterministic join-rollup over two single-sourced inputs: per-stream files streams/{stream}.yml (coordination lifecycle + ownership/runtime/merge/blockers) and active milestone files (workflow phase). Resolves the not-1:1 milestone↔stream relationship by keeping workflow phase and coordination status as orthogonal dimensions side by side in each derived row (phase from milestone, coordination from stream file) rather than collapsing one into the other; coverage is computed (active milestone with no stream file → derived 'implicit' row) so #4's exact symptom is structurally impossible. Adds stream.milestone link field (lazy; absent ⇒ standalone). forge boot + chief-of-staff Show/Sync run the Stream Rollup; chief Start/Pause/Resume/Close/Adopt write per-stream files then regenerate. Registry Drift Check removed. active.yml put in the derived state-ownership class (ADR-011); worktrees never write it. Migration: materialize per-stream files from a hand-maintained active.yml, then regenerate."
115
120
 
116
121
  # Note on the 15 / 0.24.0 ordering: reserved as max(0.23.0)+minor. origin/main was
117
122
  # already at 0.23.0 when this shipped (M10/M12/M13/M14 all merged), so 0.24.0 is a
@@ -1,32 +1,45 @@
1
1
  # Forge Streams — Active Project Map
2
- # Size gate: keep this file <= 20 KB. It is the Project Chief's default context.
3
- # Store summaries only. Deep stream history belongs in streams/{stream}/.
2
+ #
3
+ # DERIVED DO NOT HAND-EDIT. This file is a projection regenerated by the
4
+ # Stream Rollup (FORGE.md → Stream Rollup) from two sources:
5
+ # - per-stream files .forge/streams/{stream}.yml (coordination + stream-only state)
6
+ # - active milestones .forge/state/milestone-*.yml (workflow phase)
7
+ # Edit those sources, then let `forge` boot or `chief-of-staff` Show/Sync
8
+ # regenerate this file. Hand edits are overwritten on the next rollup.
9
+ #
10
+ # Size gate: keep this file <= 20 KB. Summaries only; deep history lives in
11
+ # streams/{stream}/. See ADR-015.
4
12
 
5
13
  version: 1
6
- updated_at: null
14
+ updated_at: null # set by the rollup
7
15
 
8
16
  project_chief:
9
17
  current_stream: null
10
18
  merge_policy: "chief-owned"
11
19
  notes: ""
12
20
 
21
+ # Each row is DERIVED. `phase` comes from the linked milestone (milestone-backed
22
+ # rows); `coordination` comes from the stream file. `stream: implicit` marks an
23
+ # active milestone that has no stream file yet (coverage — materialize a stream
24
+ # file if it needs coordination).
13
25
  streams:
14
26
  # - id: "billing-retries"
15
- # status: active # draft | active | paused | delegated | blocked | ready | merged | closed
27
+ # stream: explicit # explicit (has a stream file) | implicit (milestone-only)
28
+ # milestone: "m-12" # link, if milestone-backed; absent ⇒ standalone
29
+ # phase: executing # DERIVED from milestone current.status (backed rows only)
30
+ # coordination: active # DERIVED from stream file status: draft|active|paused|delegated|blocked|ready|merged|closed
16
31
  # goal: "Fix checkout retry handling"
17
32
  # branch: "forge/stream-billing-retries"
18
33
  # worktree: "../app-worktrees/billing-retries"
19
- # owner: "" # session/thread/user label
20
- # owned_surfaces:
21
- # - "src/billing/**"
22
- # shared_surfaces:
23
- # - "src/lib/events.ts"
34
+ # owned_surfaces: ["src/billing/**"]
35
+ # shared_surfaces: ["src/lib/events.ts"]
36
+ # merge_readiness: not_ready # not_ready | ready | blocked | merged
24
37
  # risk: medium # low | medium | high | unknown
25
38
  # blocked_by: []
26
39
  # next_action: "Review event contract before editing shared surface"
27
- # last_sync: null
28
40
  []
29
41
 
42
+ # DERIVED — one entry per stream whose stream file has merge.readiness: ready.
30
43
  merge_queue:
31
44
  # - stream: "billing-retries"
32
45
  # status: waiting # waiting | merging | blocked | merged
@@ -7,7 +7,10 @@ version: 1
7
7
  stream:
8
8
  id: ""
9
9
  goal: ""
10
- status: draft # draft | active | paused | delegated | blocked | ready | merged | closed
10
+ status: draft # COORDINATION lifecycle: draft | active | paused | delegated | blocked | ready | merged | closed
11
+ milestone: null # link to a milestone (e.g. "m-12"); null ⇒ standalone (quick-fix) stream.
12
+ # Set → Stream Rollup derives workflow `phase` from the milestone; do NOT
13
+ # duplicate workflow status here. This `status` stays the coordination dimension.
11
14
  tier: null # quick | standard | full | null until known
12
15
  created_at: null
13
16
  updated_at: null