Skip to content

feat(scripts): spec_render + roadmap_render v0.20 GA blockers (#458, #434, #435)#474

Merged
MScottAdams merged 3 commits intophase2/vbrief-cutoverfrom
agent2/ga-renderers/458-434-435-spec-render-edges
Apr 20, 2026
Merged

feat(scripts): spec_render + roadmap_render v0.20 GA blockers (#458, #434, #435)#474
MScottAdams merged 3 commits intophase2/vbrief-cutoverfrom
agent2/ga-renderers/458-434-435-spec-render-edges

Conversation

@MScottAdams
Copy link
Copy Markdown
Collaborator

Summary

Three v0.20 GA blockers for the spec / roadmap renderers, delivered as one
PR against phase2/vbrief-cutover. Each task ships as its own commit with a
matching CHANGELOG.md entry under [Unreleased].

Closes #458, closes #434, closes #435.

Changes

Task A (#458) — bilingual edge reader

scripts/roadmap_render._build_edge_map now reads both the schema-canonical
{from,to} and legacy {source,target} edge conventions via a new
_read_edge_endpoints helper. When both forms are present on a single edge,
canonical from/to wins. The primary test fixture in
tests/cli/test_roadmap_render.py is switched to {from,to}; legacy
regression and mixed-keys-within-single-plan fixtures are added, with direct
_build_edge_map assertions plus a topological-ordering regression test.
strategies/speckit.md Phase 4 edge example already uses {from,to}.

Task B (#434) — narrative-ordered spec_render

scripts/spec_render.py now mirrors the narrative-centric model from
prd_render.py. A new SPECIFICATION_NARRATIVE_KEY_ORDER covers both the
interview/light and speckit key sets (Overview, ProblemStatement, Goals,
UserStories, Requirements, SuccessMetrics, EdgeCases, Architecture,
TechDecisions, ImplementationPhases, PreImplementationGates). Present
narratives render in declared order first, then remaining keys alphabetically,
then plan.items for hybrid/legacy specs. Eliminates the 44-byte H1-only
failure mode for speckit-shaped specs.

New tests/cli/test_spec_render.py adds:

  • speckit-shaped fixture asserting ## ProblemStatement, ## Goals,
    ## Requirements headings with non-empty bodies
  • declared-order regression (reversed-JSON input still renders in order)
  • alphabetical-remaining-keys regression
  • legacy interview-shaped fixture asserting Overview + items still render

Task C (#435) — lifecycle-scope aggregator

scripts/spec_render.py gains a --include-scopes flag (default on) that
walks vbrief/pending/, vbrief/active/, and vbrief/completed/ relative to
the spec file and emits an ## Implementation Plan section grouped into
### Pending, ### Active, ### Completed sub-buckets. Each scope renders
as ### <filename-stem>: <title> with status code-span, its summary
narrative (resolved Overview -> Summary -> Description -> ProblemStatement ->
Problem -> Outcome -> first non-empty string narrative), and an
**Acceptance** bullet list of plan.items. The Completed bucket is
status-pinned, so misfiled pending/active scopes in completed/ do not leak.

Cross-scope ordering uses the same bilingual edge reader pattern from Task A
(replicated inline as spec_render._read_edge_endpoints), so {from,to} and
{source,target} edges between scope IDs (plan.id or filename stem) both
drive topological ordering. --include-scopes=off falls back to the
pre-aggregator output.

Tests added: full aggregator fixture test, --include-scopes=off regression,
CLI default-on smoke test, CLI --include-scopes=off smoke test, cross-scope
bilingual-edge ordering test, and a no-lifecycle-folders graceful-skip test.

Scope

Touches only:

  • scripts/roadmap_render.py
  • scripts/spec_render.py
  • tests/cli/test_roadmap_render.py
  • tests/cli/test_spec_render.py
  • CHANGELOG.md

Does not touch any files owned by other agents in this swarm
(migrate_vbrief.py, issue_ingest.py, speckit.md, vbrief.md,
glossary.md, README, UPGRADING.md, Taskfile.yml, or any skill
documents).

Validation

task check was run before each of the three commits. Final run on the
pushed HEAD: 212 markdown files validated; 1692 tests passed, 1 xfailed;
verify:stubs clean; toolchain:check green; vBRIEF validation passes
(42 scope vBRIEFs, 4 pre-existing warnings unrelated to this PR).

Commits

  • fix(scripts): roadmap_render._build_edge_map reads both {from,to} and {source,target} (#458)
  • fix(scripts): spec_render renders narratives in declared order (#434)
  • feat(scripts): spec_render aggregates scope vBRIEFs from lifecycle folders (#435)

Checklist

  • Feature branch (agent2/ga-renderers/458-434-435-spec-render-edges)
  • CHANGELOG entry under [Unreleased] for every commit
  • task check passed before each commit
  • New source paths have forward test coverage in the same PR
  • No files outside the declared scope are touched
  • Conventional commit messages

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 20, 2026

Greptile Summary

This PR resolves three v0.20 GA blockers: roadmap_render._build_edge_map now reads both {from,to} and {source,target} edge conventions via a new _read_edge_endpoints helper; spec_render renders narratives in a declared key order (mirroring prd_render); and spec_render gains a --include-scopes flag that aggregates scope vBRIEFs from vbrief/{pending,active,completed} into an ## Implementation Plan section with status-pinned Completed filtering and cross-scope topo-sort. All three changes ship with targeted regression tests.

Confidence Score: 5/5

Safe to merge; all findings are P2 style suggestions that do not affect correctness or data integrity.

No P0 or P1 defects found. The bilingual edge reader, narrative ordering, and lifecycle aggregator are all logically correct. The memoized topo-sort correctly handles cycles and diamond-shaped DAGs. Tests cover the primary paths, regressions, CLI flags, and edge cases. The one comment is a heading-level style suggestion that is deliberate by design.

No files require special attention; the P2 heading-hierarchy note in spec_render.py is optional to address.

Important Files Changed

Filename Overview
scripts/roadmap_render.py Adds _read_edge_endpoints helper and updates _build_edge_map to support both {from,to} and {source,target} edge conventions; logic is correct and the or-chain correctly treats empty-string canonical keys the same as absent ones.
scripts/spec_render.py Adds SPECIFICATION_NARRATIVE_KEY_ORDER, narrative-ordered rendering, lifecycle-scope aggregator (--include-scopes), and bilingual edge reader; the heading level collision between ### Pending bucket headers and ### stem: title scope entries is a readability P2.
tests/cli/test_spec_render.py Comprehensive test suite covering narrative ordering, alphabetical-remaining-keys, legacy interview shape, aggregator with status-pin filter, --include-scopes=off regression, CLI smoke tests, bilingual edge ordering, and graceful-skip for missing folders.
tests/cli/test_roadmap_render.py Switches primary edge fixture to canonical {from,to}, adds legacy {source,target} regression fixture, mixed-keys fixture with canonical-wins assertion, and a topo-ordering regression test for legacy edges; all well-scoped.
CHANGELOG.md Three [Unreleased] entries added, one per commit; format is consistent with existing entries.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[spec_render.main] --> B{--include-scopes?}
    B -- "on (default)" --> C[render_spec include_scopes=True]
    B -- "off" --> D[render_spec include_scopes=False]
    C --> E[validate_spec]
    D --> E
    E --> F[Render H1 title]
    F --> G[Render narratives in SPECIFICATION_NARRATIVE_KEY_ORDER]
    G --> H[Render remaining keys alphabetically]
    H --> I[Render plan.items]
    I --> J{include_scopes?}
    J -- yes --> K[_aggregate_scope_section vbrief_dir]
    J -- no --> M[Write output file]
    K --> L1[_load_scope_vbriefs pending/]
    K --> L2[_load_scope_vbriefs active/]
    K --> L3[_load_scope_vbriefs completed/ status-pin filter]
    L1 --> N[Per-bucket: _cross_scope_dep_map]
    L2 --> N
    L3 --> N
    N --> O[_topo_sort_scopes bilingual _read_edge_endpoints]
    O --> P[_render_scope_block stem: title + summary + Acceptance]
    P --> M
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: scripts/spec_render.py
Line: 248-254

Comment:
**Same heading level for bucket headers and scope entries**

Both `### Pending` / `### Active` / `### Completed` bucket headers and the per-scope `### stem: title` headings use H3. In the rendered output they are visually indistinguishable, so a reader scanning the document (or a TOC) cannot tell bucket labels apart from individual scope entries without reading the text.

Consider bumping scope headings to H4 (`#### {stem}: {title}`) so the hierarchy maps cleanly: `## Implementation Plan``### Pending``#### scope: title`.

(Change requires also updating `_render_scope_block` to emit `####` and updating matching test assertions.)

How can I resolve this? If you propose a fix, please make it concise.

Reviews (2): Last reviewed commit: "feat(scripts): spec_render aggregates sc..." | Re-trigger Greptile

@MScottAdams MScottAdams force-pushed the agent2/ga-renderers/458-434-435-spec-render-edges branch from e27ab54 to c6d8929 Compare April 20, 2026 18:20
@MScottAdams
Copy link
Copy Markdown
Collaborator Author

Rebased onto phase2/vbrief-cutover HEAD (4b60313). Only change is CHANGELOG.md reordering to accommodate the #431 entry from PR #472 that landed ahead; no logic changes in Python code or tests. task check green (1715 passed, 1 xfailed).

@MScottAdams MScottAdams merged commit 710a09c into phase2/vbrief-cutover Apr 20, 2026
3 checks passed
MScottAdams added a commit that referenced this pull request Apr 20, 2026
MScottAdams added a commit that referenced this pull request Apr 20, 2026
Housekeeping: 10 GA-blocker vBRIEFs for issues #429, #431, #432, #433, #434, #435, #436, #454, #457, #458 moved to completed/ with status: completed. All work is landed on this branch via PRs #472, #474, #475. Origin issues remain OPEN and will auto-close when PR #403 merges to master.
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.

1 participant