Fix: record slice delivery in the roadmap manifest, with a deliver helper - #114
Merged
Conversation
The roadmap board and issues are a forward projection of the manifest: a leaf's `status` drives its issue open/closed state and board Status (`history` -> Done/closed, else Backlog/open). Recording a delivery was an undocumented manual manifest edit, so it was never done — the first live-delivered slices drifted (closed issues still `status:"planned"`), and a future `apply` would reopen them. Add a `deliver --pr N` subcommand: read the PR's computed closing issues, map each to a leaf via the journal, and set that leaf `status:"history"` + `delivered_by:N`. It refuses an unmerged PR, skips parents and already-recorded leaves, and re-validates before writing. The edit is a targeted per-line text substitution so it preserves the manifest's hand-authored one-line-per-leaf style (a JSON round-trip would reflow the whole file). Document the post-merge step (deliver -> apply -> reconcile, in that order) in docs/roadmap/README.md, with the ordering rule that recording delivery must precede apply. Add DeliverTests covering the flip, the parent/already-history skips, the unmerged refusal, and the validate-abort-before-write guard. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Flip the ten already-merged leaves from status:"planned" to status:"history" with their delivering PR: difficulty.models-live-state (#56, PR #34) and the nine slice-8 leaves #57-66 except #60 (PR #110). #60 (difficulty.live-pressure) stays planned — it is Part of, deferred to slice 10. Produced with `roadmap.py deliver --pr 34` / `--pr 110`. This clears the reconcile drift for those leaves and removes the hazard that a future `apply` would reopen the merged issues. proof and titles are left unchanged (truthful — these were playtested; validation only requires delivered_by on a history leaf). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
StarshipSuperjam
force-pushed
the
claude/roadmap-delivery-fix
branch
from
September 3, 2026 16:11
9d369f8 to
d88900b
Compare
StarshipSuperjam
marked this pull request as ready for review
September 3, 2026 16:12
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Purpose
Record slices 7 & 8 as delivered in the roadmap manifest, and add a helper so this bookkeeping never drifts again.
docs/roadmap/manifest.json: a leaf'sstatusdrives its issue open/closed state and board Status (history→ Done/closed, else Backlog/open). Recording a delivery is a manual manifest edit (planned→history+delivered_by) that was never documented or automated, so it was never performed — slices 7 (PR Feature: difficulty director and normal flying formations, live #34) and 8 (PR Feature: Toroid vertical slice — first live flying enemy (slice 8) #110) merged with their leaves stillplanned.reconciledrift, and it is a latent hazard: a futureroadmap.py applywould force those merged issues back open and reset the board to Backlog.Impact:
reconcilebecomes clean,applycan no longer reopen merged work, and delivery-recording stops being a step that gets forgotten.Scope
A
deliver --pr Nhelper + doc, and the manifest edit recording the ten merged leaves delivered.tools/roadmap.py— newdeliver --pr Nsubcommand.docs/roadmap/manifest.json— ten leaves flippedplanned→history+delivered_by.docs/roadmap/README.md— the post-merge step, with the ordering rule.tests/test_roadmap.py—DeliverTests.Change profile — the shape of this pull request at a glance:
Impact: the roadmap's delivered state matches reality, and the recording is now a single reliable command.
Behaviors
What this delivers, each with the check that exercises it.
deliver --pr Nflips only the PR's planned leaves tohistory+delivered_by—tests/test_roadmap.py::DeliverTests.test_flips_only_the_prs_planned_leaves.test_skips_parents_and_already_delivered.test_refuses_a_pr_that_is_not_merged.test_an_invalid_result_aborts_the_write.test_committed_manifest_is_complete_and_acyclic/roadmap.py validate.Out of scope
Projecting the manifest to the live GitHub board — deliberately staged as a separate, gated step.
roadmap.py apply/reconcile(which set the board Status → Done, rebuild the board's lost cards, and correct the stale board slice tag on issue 60) is a broad live GitHub mutation. It runs after this merges, previewed and on the operator's go-ahead — not inside this PR.#60(difficulty.live-pressure) is leftplanned— it isPart of #60, deferred to slice 10, not delivered.Impact: the safety fix (manifest recording) lands now; the broad board resync stays a deliberate, reviewable action.
Risk
Low. Project data + one self-contained helper; no gameplay, specs, or engine machinery touched.
roadmap.py validateand the test suite; fully reversible..engine/**file is touched.Impact: a wrong edit would be caught by validation/tests before merge, and the change is trivially revertible.
Validation
Full test suite green; manifest validates; minimal diff confirmed.
python3 -m unittest discover tests— 234 tests pass (5 newDeliverTests).python3 tools/roadmap.py validate— manifest valid (13 parents, 66 leaves).Impact: an approver can rely on the helper's behavior and the manifest's validity being exercised.
Review
I made this contained, reversible change at a quick check — I looked it over myself and ran the automatic checks plus the roadmap tests; no extra review passes.
tools/roadmap.pyanddocs/roadmap/*are project-owned, not engine surfaces).Impact: this records the chosen review depth; your review at merge is the binding gate.
Demonstration
Run the helper and the validator against this branch.
python3 tools/roadmap.py validate→ prints "roadmap manifest valid: 13 parents, 66 leaves"; a malformed manifest prints the failures and exits non-zero.python3 tools/roadmap.py deliver --pr 34on an already-recorded manifest → prints "skip … already recorded delivered" and refuses to write (nothing to record), showing the idempotence guard; on an unmerged PR it refuses with a clear message.python3 -m unittest tests.test_roadmap→ theDeliverTestspass, and fail if the flip/skip/refuse logic breaks.Impact: the operator can watch the recording and its guards work, and see validation reject a bad manifest.
Files of interest
The helper and the manifest edit.
tools/roadmap.py— thedeliversubcommand (reuses the existing dispatch,ghwrapper, andvalidate_manifest).docs/roadmap/manifest.json— the tenplanned→history+delivered_byedits.docs/roadmap/README.md— the post-merge "record delivery" step and ordering rule.tests/test_roadmap.py—DeliverTests.Impact: the helper and the manifest edit most determine whether this is sound.
AI involvement
Claude Code (Opus) diagnosed the drift, designed and wrote the helper + tests + doc, and produced the manifest edit by running the helper.
Impact: AI judgment is load-bearing on the helper design and the diagnosis; the operator's review and merge are the binding checks.
🤖 Generated with Claude Code