feat(strategy): speckit v0.20 scope emission + GA docs/glossary/issue:ingest (#436, #432, #433, #457, #429, #454)#475
Conversation
…436) - Rewrite strategies/speckit.md Phase 4: emit one scope vBRIEF per IP to vbrief/pending/YYYY-MM-DD-ip<NNN>-<slug>.vbrief.json (3-digit padded) with canonical Description/Acceptance/Traces narratives, x-vbrief/plan reference back to specification.vbrief.json, and plan.metadata.dependencies (plan-level) - plan.vbrief.json reverts to session-todo role; carries planRef to active scope - scripts/migrate_vbrief.py: add migrate_speckit_plan() and --speckit-plan CLI flag with bilingual edge reader (from/to preferred, source/target fallback) covering #458 - vbrief/vbrief.md: document ip<NNN> 3-digit padded filename (Risk 5), plan.metadata.dependencies plan-level placement (Risk 6), canonical narrative keys (Risk 7) - Add tests/content/test_speckit_phase4.py and migrator tests in tests/cli/test_migrate_vbrief.py - CHANGELOG entry under [Unreleased]
…#432) - Restructure strategies/speckit.md Post-Phase 3 section from prose into a numbered transition gate (5 steps: run task spec:render, confirm SPECIFICATION.md exists, confirm hash match vs vbrief narratives, describe rendered-view semantics, human approval) - Add Phase 3 -> Phase 4 transition criterion requiring SPECIFICATION.md exists AND hash matches rendered output of specification.vbrief.json narratives - Add End-of-Phase-3 Export Prompt and Render Gate to skills/deft-directive-setup/SKILL.md that invokes task spec:render at the speckit Phase 3 -> 4 boundary (mandatory for speckit-strategy projects) - tests/content/test_speckit_phase3_gate.py: new content tests - CHANGELOG entry under [Unreleased]
…433) - Add 3c. Render PRD row to strategies/speckit.md Artifacts Summary alongside the existing 3b. Render SPECIFICATION row (landed with #436 Artifacts Summary refactor, dedicated coverage here) - End-of-Phase-3 Export Prompt in skills/deft-directive-setup/SKILL.md asks whether to generate SPECIFICATION.md and/or PRD.md with 4 numbered choices (both/spec-only/PRD-only/skip) before handoff to deft-directive-build - tests/content/test_phase3_export_prompt.py: new content tests - CHANGELOG entry under [Unreleased]
- Create glossary.md with RFC2119 legend + 13 required v0.20 terms (Scope vBRIEF, Lifecycle folder, Plan-level narrative, Item-level narrative, Filename stem, Cross-scope dependency, Exit Commands, Origin provenance, Canonical narrative key, Preparatory strategy, Spec-generating strategy, Rendered export, Source of truth) - File stays under 150 lines per scope cap - Cross-refs from vbrief/vbrief.md See-also banner, README Glossary section, UPGRADING v0.20 References - tests/content/test_glossary.py asserts existence, <150 lines, RFC2119 legend, all 13 term labels present with cross-links, cross-ref coverage - CHANGELOG entry under [Unreleased]
- Remove the v0.20.0 release-candidate safety banner from README.md (line 23 block that directed testers to run migrate:vbrief against a fork/copy and mentioned we are still refining) - Move a distilled, version-agnostic test-on-fork-first paragraph to UPGRADING.md under a new Upgrade safety subsection so advice is preserved without RC-specific wording (Option C from the issue) - README no longer contains RC-specific or in-progress refining language ahead of the v0.20.0 final tag - CHANGELOG entry under [Unreleased]
…tion (#454) - scripts/issue_ingest.py single-issue + bulk modes with gh api/list, dedup via reconcile_issues.scan_vbrief_dir, writes vbrief/<status>/YYYY-MM-DD-<N>-<slug>.vbrief.json with origin provenance - Exit codes: 0 success, 1 duplicate (single), 2 gh/API error - Extract shared slugify + create_scope_vbrief helpers into scripts/_vbrief_build.py; migrate_vbrief.py re-exports legacy underscore aliases for backward compat - tasks/issue.yml wires task issue:ingest - tests/cli/test_issue_ingest.py: single-issue happy path, dedup hit + CLI exit 1, bulk summary, label filter, dry-run (single+bulk), gh API error CLI exit 2, --help subprocess - Doc cross-refs: vbrief/vbrief.md Quick Reference, README Document Generation table + new Ingesting GitHub issues subsection, UPGRADING.md v0.20 section - CHANGELOG entry under [Unreleased]
|
| Filename | Overview |
|---|---|
| scripts/_vbrief_build.py | New shared helper module with slugify (underscore fix applied), TODAY, and create_scope_vbrief; minor inconsistency: Phase key is unconditionally included while Tier is conditional |
| scripts/issue_ingest.py | New GitHub issue → scope vBRIEF ingestion script; return type annotation and summary dict type annotation (flagged in prior review) now correctly reflect actual types; dedup, bulk, and dry-run paths look correct |
| scripts/migrate_vbrief.py | Adds migrate_speckit_plan() and bilingual edge reader; plan.vbrief.json always rewritten to session-todo scaffold unconditionally — safe on first run, but accidental re-run after adding session items could silently consume them as new IPs |
| tasks/issue.yml | Clean Taskfile entry for task issue:ingest wiring; --repo is left to CLI_ARGS or auto-detection, which is the documented pattern |
| tests/cli/test_issue_ingest.py | Thorough tests covering happy path, dedup, bulk, dry-run, and gh CLI error paths; no issues found |
| tests/cli/test_migrate_vbrief.py | New speckit-plan section (TestMigrateSpeckitPlan) covers IP emission, 3-digit padding, bilingual edge translation, spec-ref linking, and session-scaffold rewrite; comprehensive |
| glossary.md | New RFC2119 glossary with 13 required v0.20 terms; all cross-reference links verified as present; stays well under 150 lines |
| tests/content/test_speckit_phase4.py | Content tests validating Phase 4 emission conventions against speckit.md and vbrief.md; no issues |
| tests/content/test_glossary.py | Content tests verifying glossary.md has all 13 required terms and RFC2119 legend; no issues |
| tests/content/test_phase3_export_prompt.py | Tests for end-of-Phase-3 export prompt in SKILL.md; no issues |
| tests/content/test_speckit_phase3_gate.py | Tests for Phase 3→4 transition gate in speckit.md; no issues |
Sequence Diagram
sequenceDiagram
participant User
participant Taskfile
participant issue_ingest
participant reconcile_issues
participant _vbrief_build
participant vbrief_dir
User->>Taskfile: task issue:ingest N / --all
Taskfile->>issue_ingest: uv run issue_ingest.py --vbrief-dir ...
issue_ingest->>reconcile_issues: scan_vbrief_dir(vbrief_dir)
reconcile_issues-->>issue_ingest: existing refs {number -> [paths]}
alt single-issue mode
issue_ingest->>issue_ingest: _fetch_single_issue(repo, N) via gh api
issue_ingest->>issue_ingest: ingest_one(issue, ...)
else bulk mode
issue_ingest->>reconcile_issues: fetch_open_issues(repo)
reconcile_issues-->>issue_ingest: [issue dicts]
issue_ingest->>issue_ingest: ingest_bulk(issues, ...)
end
issue_ingest->>_vbrief_build: slugify(title)
_vbrief_build-->>issue_ingest: slug
issue_ingest->>vbrief_dir: write pending|proposed|active/YYYY-MM-DD-N-slug.vbrief.json
issue_ingest-->>User: exit 0 (created) / 1 (duplicate) / 2 (error)
Prompt To Fix All With AI
This is a comment left during a code review.
Path: scripts/_vbrief_build.py
Line: 82-85
Comment:
**`Phase` key unconditionally included even when empty**
`"Phase": phase` is always written to `narratives` even when `phase` is `""`. This is inconsistent with the `Tier` key which is only added if non-empty (`if tier: narratives["Tier"] = tier`). Any caller that provides an item with no `phase` field will get a spurious `"Phase": ""` in the emitted vBRIEF's narratives dict.
```suggestion
narratives: dict[str, str] = {
"Description": title,
}
if phase:
narratives["Phase"] = phase
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: scripts/migrate_vbrief.py
Line: 978-992
Comment:
**`migrate_speckit_plan` re-migration can silently treat session-todo items as new IPs**
After a successful first run, `plan.vbrief.json` is rewritten to an empty session-todo scaffold (`items: []`). The early-exit guard (`if not items: return False, [error]`) prevents a clean re-run on a fully-empty plan. However, if a user adds session-level `items` to `plan.vbrief.json` after migration and then runs `--speckit-plan` again, those items would be parsed as new IP entries — generating spurious scope vBRIEF files — and the plan would be wiped again.
Consider adding a sentinel key (e.g. `"migrated": true` in `vBRIEFInfo`) checked at the top of the function so accidental re-runs on a partially-populated session-todo fail loudly rather than quietly consuming its items.
How can I resolve this? If you propose a fix, please make it concise.Reviews (3): Last reviewed commit: "Merge phase2/vbrief-cutover into agent3 ..." | Re-trigger Greptile
- _vbrief_build.py: fix slugify underscore handling (P1) - issue_ingest.py: annotate _build_issue_vbrief and summary (P2 x2) - tests: regression test for slugify underscore bug
|
Merged phase2/vbrief-cutover HEAD (710a09c) into this branch to sync with #472 and #474 merges. Only conflict was CHANGELOG.md -- resolved by combining all six agent3 Added entries with the interim #435 entry and the three new Fixed entries (#431, #458, #434). No logic changes in any .py/.md source. task check green (1802 passed, 1 xfailed). |
speckit v0.20 scope emission + GA docs / glossary / issue:ingest
This PR lands six GA-blocker items for the v0.20.0 release, split one commit per issue:
speckit Phase 4 collides with plan.vbrief.json definition (no scope vBRIEFs emitted) #436 (Task A) — speckit Phase 4 emits scope vBRIEFs per implementation phase
strategies/speckit.mdPhase 4 now writes one scope vBRIEF per IP tovbrief/pending/YYYY-MM-DD-ip<NNN>-<slug>.vbrief.json(3-digit padded) with canonicalDescription/Acceptance/Tracesnarratives, areferencesentry linking back tovbrief/specification.vbrief.jsonviax-vbrief/plan, and cross-scope dependencies inplan.metadata.dependencies(plan-level).plan.vbrief.jsonreverts to its canonical session-todo role.scripts/migrate_vbrief.pygainsmigrate_speckit_plan()and a--speckit-plan <path>CLI flag that converts an existing speckit-shapedplan.vbrief.jsoninto N scope vBRIEFs using a bilingual edge reader (from/topreferred, fall back tosource/target) so both legacy and canonicaledges[].blocksdialects translate correctly (covers the v0.20.0 GA blocker: align plan.edges[] field names (from/to vs source/target) #458 migrate_vbrief.py touchpoint).vbrief/vbrief.mddocuments theip<NNN>3-digit padded convention (Risk 5), plan-levelplan.metadata.dependenciesplacement (Risk 6), and canonical narrative keys (Risk 7).speckit Phase 3 -> Phase 4 advances without enforcing ! task spec:render #432 (Task B) — enforce
task spec:renderas Phase 3 → 4 transition gateSPECIFICATION.mdMUST exist AND its hash MUST match the rendered output ofvbrief/specification.vbrief.jsonnarratives.skills/deft-directive-setup/SKILL.mdinvokestask spec:renderat the boundary (mandatory for speckit-strategy projects even if the user declines the prompt).Greenfield projects can complete speckit with no PRD/SPECIFICATION export and no prompt #433 (Task C) — prompt to render PRD/SPECIFICATION at end of Phase 3
strategies/speckit.mdArtifacts Summary gains a 3c. Render PRD row alongside the existing 3b.skills/deft-directive-setup/SKILL.mdadds an End-of-Phase-3 Export Prompt with four numbered choices (both / spec-only / PRD-only / skip) before handoff todeft-directive-build.v0.20.0 GA blocker: add deft/glossary.md with v0.20 canonical vocabulary #457 (Task D) —
glossary.mdcanonical v0.20 vocabularyglossary.mdat the repo root with the RFC2119 legend and exactly 13 required terms (Scope vBRIEF, Lifecycle folder, Plan-level narrative, Item-level narrative, Filename stem, Cross-scope dependency, Exit Commands, Origin provenance, Canonical narrative key, Preparatory strategy, Spec-generating strategy, Rendered export, Source of truth). File stays well under 150 lines.vbrief/vbrief.mdSee-also banner,README.md(new "Glossary" section), andUPGRADING.mdv0.20 References.release(v0.20.0): remove or revise RC testing safety banner from README before cutting final #429 (Task E) — remove v0.20.0 RC testing safety banner
README.md.UPGRADING.mdunder a new "Upgrade safety" subsection (Option C).v0.20.0 GA blocker: add task issue:ingest for GitHub issue -> vBRIEF ingestion #454 (Task F) —
task issue:ingestfor GitHub issue → vBRIEF ingestionscripts/issue_ingest.pywith single-issue (<N> [--status]) and bulk (--all [--label] [--status] [--dry-run]) modes.references[type=github-issue]viascripts/reconcile_issues.py::scan_vbrief_dir. Exit codes:0success /1duplicate (single) /2gh or API error.slugifyandcreate_scope_vbriefextracted into newscripts/_vbrief_build.py;scripts/migrate_vbrief.pyre-exports the legacy underscore-prefixed aliases for backward compatibility.tasks/issue.yml. Documented invbrief/vbrief.mdQuick Reference,README.md(new "Ingesting GitHub issues" subsection + two Document Generation rows), andUPGRADING.mdv0.20 expectations.Tests
tests/content/test_speckit_phase4.py,tests/content/test_speckit_phase3_gate.py,tests/content/test_phase3_export_prompt.py,tests/content/test_glossary.py,tests/cli/test_issue_ingest.py(+ expandedtests/cli/test_migrate_vbrief.pyfor the speckit-plan translator).task checkgreen on final commit (1763 passed, 1 xfailed).Closes
Closes #436, closes #432, closes #433, closes #457, closes #429, closes #454.