Skip to content

feat(scripts): roadmap settle is code — writer call sites, check gate, unit-cycle settle - #323

Merged
gtrabanco merged 16 commits into
mainfrom
fix-316-roadmap-writer-call-sites
Oct 27, 2026
Merged

gtrabanco merged 16 commits into
mainfrom
fix-316-roadmap-writer-call-sites

Conversation

@gtrabanco

@gtrabanco gtrabanco commented Oct 26, 2026 •

Copy link
Copy Markdown
Owner

Issue #316 — the roadmap's done settle is code

Closes #316

Problem

The roadmap row's done settle — the status-machine write done + PR link at PR open — had a deterministic detector (unit-route refuses close-out while not done) and a deterministic writer (the crate's roadmap rowUpsert), but zero call sites. The transition was assigned to free-form prose, and near-identical misses were caught late at audit-pr (units 77 and 79).

What changed

  1. feat(runner): roadmap check — agentic-workflow roadmap check <doc-path> — cross-document settle check. Compares a unit doc's own facts (NN, slug, PR URLs from ## Next, ## Log, ## Evidence, and References - PR:) against its index row. Closed code set (ROADMAP_CHECK_CODES): row-missing, slug-mismatch, pr-url-unsettled. Exit contract: 0 consistent · 1 violations · 2 usage. The writer's separator rule also accepts the repo's real |----|------|… shape.

  2. feat(scripts): roadmap-settle gate — scripts/roadmap-settle.mjs — the root-level offline gate. Scans every unit doc, checks each against its index row through the crate's own grammar, reports violations with named codes, fails closed.

  3. feat(scripts): unit-cycle writes the roadmap settle itself — settleRoadmapRow() / parsePrUrl() and a settle-roadmap action between release and the receipt chain, via the crate's rowUpsert, every cell preserved.

  4. docs(skills): the writer's call sites — execute-phase close-out, unit-lane references/RELEASE.md and references/PLAN.md (release-settle task P<n+1>), README, LANE_FLOW.md, budgets, CHANGELOG rows.

  5. The audit-pr blockers folded — the settle call sites now name a form that runs: a bare roadmap rowUpsert resolved the subcommand word as the table path (ENOENT on a file named rowUpsert), so both call sites carry the index path and the JSON, and stop at the kind boundary (rowUpsert is the roadmap's writer; a fix index has no NN column). unit-cycle grades the settle through the crate's checkUnitDoc instead of a second, weaker rule. roadmap-settle --root with no value exits 2 with usage. scripts/unit-lineage.mjs stops a section at the nearest ##/### heading — it used to swallow the following ## sections, so an obligation ledger parsed the Findings table as its own rows.

Verification (at a2f0d096)

  • node --test scripts/*.test.mjs → 922/922
  • bun run test (crate) → 254/254
  • bun scripts/roadmap-settle.mjs → PASS, 0 violations over 110 unit docs
  • bun scripts/check-skill-context.mjs and --routes → exit 0 (28 skills, 14 routes)
  • bun scripts/unit-lineage.mjs --unit 316-roadmap-settle → LINEAGE OK, obligations closed (6)

Versions

Automated written using AI

@gtrabanco

Copy link
Copy Markdown
Owner Author

review-change: REVIEW-PASS

  • Reviewed head: e62512022f7f6092d8dd4f5b4973231e9ff35da3
  • Scope manifest: sha256:816c871a3e04e03714d3533976681d16acd494b3fc57cfdfe71a128e2f92a0cb
  • Scope and applicable axes: branch diff vs main: crate roadmap check (packages/agentic-workflow Roadmap.mjs + bin + roadmap-check tests), root gate scripts/roadmap-settle.mjs + frozen-failure corpus, scripts/unit-cycle.mjs settle act, unit-lane/execute-phase writer call sites, unit docs (fix/316 + fixture corpus + live row repairs)
  • Acceptance coverage: S1: settleRoadmapRow/settleCommitArgs + rowUpsert call sites, 45 unit-cycle tests | S2: scripts/roadmap-settle.mjs named codes + frozen corpus, 7 tests | S3: release-settle task in unit-lane PLAN.md | S4: crate checkUnitDoc/ROADMAP_CHECK_CODES, crate tests - all validators green at reviewed head
  • Architectural invariants: n/a
  • Current-unit findings open: 0
  • Future-capability proposals: 0
  • Manual verification: none

…316)

agentic-workflow roadmap check compares a unit doc's own facts (NN, slug,
PR URLs from its own lifecycle surfaces) with its index row and fails closed
with the closed code set ROADMAP_CHECK_CODES (row-missing, slug-mismatch,
pr-url-unsettled). Exit contract: 0 consistent, 1 violations, 2 usage.

The invariant mechanized: a unit doc that carries a PR URL must have its row
reading done · [#N](<same url>). findRow is exported so the settle writer's
callers re-emit rows without clobbering untouched cells.

The separator rule now accepts any pipes/dashes/colons rule (>=3 dashes): the
old literal |---| match refused this repository's own |----|------| separator,
so the writer could not write the repo's real roadmap. rowUpsert/annotate
receipts are byte-identical (behavior-hold test).

Tests: the issue's frozen-failure corpus (units 77 and 79) as reproducers,
false-positive guards (cross-references, removed fix rows), CLI exit contract,
writer behavior hold. Version 0.4.0 -> 0.5.0 + CHANGELOG companion row.
…line (issue #316)

scripts/roadmap-settle.mjs walks every unit doc (features and fixes), compares
its own facts with its index row through the crate's checkUnitDoc — this
script is wiring, it carries no second copy of the grammar — and exits 1 with
named codes (row-missing, slug-mismatch, pr-url-unsettled) when a doc carries
its PR URL without the row reading done · [#N](<same url>).

The fixture corpus carries the issue's frozen failures: the 77-shaped
reproducer (PR #309 merged, row in-progress on main) and the 79-shaped one
(PR open, row in-progress until the audit blocked), plus the false-positive
guards (cross-referenced settled PR, no-PR unit, removed fix row).

Same-PR live repairs the gate demands to be green at this head:
- roadmap row 77 settles as done · [#309](...pull/309) (the live case)
- fix-index row 244's topic re-points to the folder slug
  freeze-batch-planner-consumer — born mismatched in d1bb61c (day-one
  unit-identity drift, the F48 class)

Root-suite case keeps the live drift red, same wiring as promise-coherence.
Between the release and the receipt chain, the loop runs a deterministic
settle-roadmap act: the row is written through the crate's rowUpsert with
every cell the write does not own preserved verbatim, then committed and
pushed — a skipped settle can never reach review, and the release step's
prompt no longer asks the model to set the row.

roadmapSettled is sensed, never assumed: token done + the References PR URL
as the settle link. Fix units are exempt in-code — the fix index removes
merged rows by its own convention and its table grammar is not the roadmap's,
so the writer fails closed there and the settle stays the release step's
documented duty.

Tests (red-first): the new transition, its precedence over the receipt chain,
the settled no-op (previous behavior holds for every existing transition),
the fix-kind exemption, parsePrUrl, and the settle write's cell preservation.
… (issue #316)

- unit-lane RELEASE.md: the checklist's prose "Roadmap row updated to done"
  becomes the agentic-workflow roadmap rowUpsert call (cells preserved,
  scripts/roadmap-settle.mjs exits 0 as the validator).
- unit-lane PLAN.md: the Tasks contract emits the release settle as the
  P<n+1> task for units that open a PR — the sole exception to "no
  docs/release tasks" — so the executor owns the transition and a skipped
  write is a failed task, not a missing courtesy.
- execute-phase §7: the whole-unit close-out performs the settle through the
  crate's writer before the terminal block.
- LANE_FLOW.md: agentic-workflow roadmap check joins the SDK command table.

Bumps (bump-skill contract): unit-lane 2.4.3 -> 2.5.0, execute-phase
6.2.2 -> 6.3.0, CHANGELOG rows, README execute-phase cell. Budgets re-based
at a declared source (issue #316): execute-phase main 3744 est / 294 lines
-> ceilings 4119/324, and the eight execute-phase:* routes. pi package
0.34.1 -> 0.35.0 with its companion row (content half of the parity gate).
… grader, exit-2 usage

The writer the skills name could not run. `roadmap rowUpsert` without a table
path resolved the subcommand word as that path, so every bare invocation opened
a file literally named `rowUpsert` and refused with ENOENT — a missing-table
error for what is a missing-argument mistake. The close-out and release call
sites named exactly that form.

- roadmap <table-path> rowUpsert|annotate requires the path; a bare subcommand
  is a usage error (exit 2), never a filename.
- Both call sites (execute-phase close-out, unit-lane RELEASE) name the
  executable form with the index path and the JSON, conditioned on unit kind:
  a fix index has no NN column, so rowUpsert is the roadmap's writer only.
- unit-cycle reuses the crate's checkUnitDoc instead of its own weaker grader,
  so the loop and scripts/roadmap-settle.mjs compare the same exact PR URL.
- roadmap-settle --root with no value is a usage error, not a stack trace.

Refs #316
…t version

The audit-pr pass over #323 returned six blockers; this range clears the ones
that are code and record, and leaves the receipt to /review-change.

- The obligation ledger the lineage gate demands exists (`### Planning evidence`
  + `### Obligations`, O1-O6 verified by the commands that ran), so
  `unit-lineage` answers LINEAGE OK instead of BLOCKED.
- `scripts/unit-lineage.mjs`: a section ends at the nearest `##`/`###` heading.
  Preferring any `###` found later sliced through the following `##` sections,
  so the obligation ledger parsed the Findings table and reported its ids as
  open obligations — every unit doc carrying a findings table failed lineage.
- The pi package re-cuts to 0.35.1: main published 0.35.0 (#321) while this
  branch was open, so 0.35.0 would publish nothing. execute-phase 6.3.1 and
  unit-lane 2.5.1 carry the corrected call sites; the execute-phase:* route
  ceilings are re-based with their growth source declared.
- The unit doc's Next names this head's real state and the cycle-3 verdict is
  recorded; F7-F12 move to the Log as folded lines.

Refs #316
@gtrabanco
gtrabanco force-pushed the fix-316-roadmap-writer-call-sites branch from e625120 to a2f0d09 Compare October 27, 2026 09:26
@gtrabanco
gtrabanco merged commit 064cbe9 into main Oct 27, 2026
3 checks passed
@gtrabanco
gtrabanco deleted the fix-316-roadmap-writer-call-sites branch October 27, 2026 09:44
gtrabanco added a commit that referenced this pull request Oct 27, 2026
The active-fixes index carried `#316 · done · [#323]` after issue #316 closed
(2026-10-27) and PR #323 merged — the index's own legend removes a row only after
the merge, so the row had outlived its rule. With no fix in flight the table now
carries an explicit `none` row instead of a stale one: `parseFixIndex` requires a
number in the issue cell, so the placeholder is invisible to the sensor and the
router, and "empty" stops reading as a parser miss.

Gate: `node --test scripts/*.test.mjs` → exit 0, 929 pass / 0 fail ·
`node scripts/roadmap-settle.mjs` → ok, 0 violations.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ISSUE: the roadmap row's done settle is prose-only — the crate's roadmap writer has zero call sites and nothing verifies doc↔row

1 participant