@@ -68,69 +68,76 @@ pull request. They are not retroactively certified under today's evidence
6868contract. Incomplete foundations—including the live entity, collision, random,
6969and dispatch paths formerly hidden by closed issue #14 —remain open leaves.
7070
71- ## Recording delivery after a slice merges
72-
73- Merging a slice's pull request closes its leaf issues on GitHub, but nothing
74- back-propagates into the manifest — the manifest is the source of truth, and a
75- merge never edits it. Until you record the delivery, those leaves still read
76- ` status: "planned" ` , so ` reconcile ` reports drift (a closed issue whose manifest
77- status is not ` history ` ) and — critically — the next ` apply ` would force those
78- merged issues ** back open** and reset their board cards to Backlog.
79-
80- After a slice PR merges, record it and re-project:
81-
82- ``` bash
83- python3 tools/roadmap.py deliver --pr < PR#> # manifest: its leaves → history + delivered_by
84- python3 tools/roadmap.py apply # GitHub: keep issues closed, board Status → Done
85- python3 tools/roadmap.py reconcile # verify live state matches the manifest
86- ```
87-
88- Then commit the changed ` manifest.json ` and ` migration.json ` .
89-
90- ` deliver ` reads the pull request's computed closing issues, maps each to a leaf
91- through the journal, and sets that leaf ` status: "history" ` with
92- ` delivered_by: <PR#> ` — a minimal per-line edit that preserves the manifest's
93- style. It refuses a pull request that is not merged, skips leaves already
94- recorded, and re-validates before writing.
95-
96- ** Order matters: record delivery first.** Running ` apply ` while a merged leaf is
97- still ` planned ` reopens its issue. Always ` deliver ` before ` apply ` .
98-
99- ## Migration and recovery
100-
101- [ ` migration.json ` ] ( migration.json ) is the resumable journal. The migration:
102-
103- 1 . validates the manifest and stops before writes on any mismatch;
104- 2 . snapshots milestones, Project fields/items/views, and every protected field
105- of active PR #34 ;
106- 3 . creates or converts parents and leaves by stable ` roadmap-key ` , journaling
107- each returned issue and Project identity;
108- 4 . attaches native parent relationships, milestones, and derived Project
109- fields in separate passes;
110- 5 . closes imported-history leaves only after their evidence and relationships
111- exist;
112- 6 . reads the complete live state back and proves exact parentage, milestones,
113- state, uniqueness, and that PR #34 did not change.
114-
115- An interrupted migration is resumed by rerunning ` apply ` ; it rolls forward from
116- stable keys and journaled IDs. Issue deletion or silent closure is never used as
117- rollback because GitHub history and notifications cannot be undone. If PR #36
118- is abandoned, the journal and ` roadmap-migration: PR #36 ` markers identify the
119- incomplete projection to resume or explicitly supersede.
120-
121- Useful commands:
71+ ## Recording delivery: the slice PR carries it
72+
73+ ` manifest.json ` is the source of truth and GitHub is a projection, so a slice's
74+ delivery is recorded ** in the same pull request that delivers it** — the manifest
75+ can never lag ` main ` .
76+
77+ 1 . In the slice PR, once it closes its leaf issues (one ` Closes #N ` per delivered
78+ leaf), record the delivery and commit the edit into the PR:
79+
80+ ``` bash
81+ python3 tools/roadmap.py deliver --pr < this PR#>
82+ ```
83+
84+ This flips each closed leaf from ` status: "planned" ` to ` "history" ` with
85+ ` delivered_by: <PR#> ` — a minimal per-line manifest edit. ` deliver ` accepts an
86+ ** open** PR precisely so this rides the same PR; the required closure check then
87+ refuses the merge unless the manifest at the PR head records every leaf the PR
88+ closes. At merge, GitHub closes the issues and the same merge lands the manifest
89+ that records them, so the two always agree.
90+
91+ 2 . After it merges, project the manifest onto GitHub from an updated ` main ` :
92+
93+ ``` bash
94+ python3 tools/roadmap.py apply # keep the delivered issues closed, board Status → Done
95+ python3 tools/roadmap.py reconcile # verify the live projection matches the manifest
96+ ```
97+
98+ This second step is ** manual by design** : GitHub Actions' own token cannot read
99+ or write the org Project board and no personal-access token is provisioned, so
100+ nothing pushes the board automatically. If you forget it nothing breaks and no
101+ issue reopens — the next ` reconcile ` simply reports the drift and names the leaf,
102+ and running ` apply ` fixes it. A converged ` apply ` writes nothing
103+ (` patched 0 issues, 0 board fields ` ). If ` apply ` changes the ` migration.json `
104+ journal, land that change on ` main ` through a small pull request, like any other
105+ change (nothing reaches ` main ` except by pull request).
106+
107+ ** Dropping a leaf.** There is no ` dropped ` status yet, and the manifest has no field
108+ that expresses a cancelled leaf, so there is no clean edit to make one stick. Until the
109+ ` dropped ` status is added (tracked as its own roadmap issue), ** leave the leaf's issue
110+ open** — the closure guard reopens a hand-closed ` planned ` leaf — and record the
111+ cancellation as a comment on that issue. Do not delete the leaf's manifest line either:
112+ its criteria are part of the exact criterion roster ` validate ` enforces, so removing it
113+ would need the roster updated in the same edit and is a change to make deliberately under
114+ review, not a quick cancellation.
115+
116+ ## Archived board cards
117+
118+ GitHub auto-archives a card about two weeks after its issue closes, so most
119+ delivered leaves' cards are archived. The tooling is archive-aware: ` apply ` and
120+ ` reconcile ` read archived cards too and accept an archived Done card as correct, so
121+ a delivered leaf never reads as a missing or drifted card.
122+
123+ ## Commands
122124
123125``` bash
124- python3 tools/roadmap.py validate
125- python3 tools/roadmap.py plan
126- python3 tools/roadmap.py snapshot
127- python3 tools/roadmap.py apply
128- python3 tools/roadmap.py reconcile
129- python3 tools/roadmap.py deliver --pr < PR#>
130- python3 tools/roadmap.py handoff
126+ python3 tools/roadmap.py validate # the manifest is internally consistent
127+ python3 tools/roadmap.py plan [--live] # counts; --live adds a read-only GitHub diff
128+ python3 tools/roadmap.py deliver --pr N # record a PR's leaves delivered (run in the slice PR)
129+ python3 tools/roadmap.py apply # project the manifest onto Issues + the board
130+ python3 tools/roadmap.py reconcile # verify the live projection matches the manifest
131131```
132132
133- Existing Project views and the Engine-owned summary fields are immutable to the
134- migration. It adds manifest-owned views for delivery leaves, capability
135- parents, and imported history, plus the derived ` Roadmap role ` , `Delivery
136- slice` , and ` Proof level` fields.
133+ ` apply ` is safe to re-run: it writes the journal incrementally and skips any issue or
134+ board field already correct, so if a run dies partway (a network blip or a rate limit)
135+ just run it again — it rolls forward from the journal and the stable ` roadmap-key ` s
136+ rather than duplicating issues or cards.
137+
138+ [ ` migration.json ` ] ( migration.json ) is the identity journal: it caches the GitHub
139+ issue and card ids for each stable ` roadmap-key ` plus the project header ` apply `
140+ bootstraps from. Existing Project views and the engine-owned summary fields are the
141+ operator's, not the manifest's; the tool owns only the delivery-leaf,
142+ capability-parent, and imported-history views and the derived ` Roadmap role ` ,
143+ ` Delivery slice ` , and ` Proof level ` fields.
0 commit comments