From 1194548d619976a946763e33bf1a190c9fb3998e Mon Sep 17 00:00:00 2001 From: Lex Christopherson Date: Mon, 23 Mar 2026 13:42:38 -0600 Subject: [PATCH] fix(gsd): wrap plan-task DB writes in transaction + untrack .gsd/ artifacts plan-task.ts was the only planning tool handler not wrapping its insertTask/upsertTaskPlanning calls in a transaction(), risking partial DB state if the upsert failed after insert. Matches the pattern used by plan-slice, replan-slice, reassess-roadmap, and plan-milestone. Also removes 80 .gsd/ working artifacts that were force-added despite being in .gitignore. Co-Authored-By: Claude Opus 4.6 (1M context) --- .gsd/milestones/.DS_Store | Bin 6148 -> 0 bytes .gsd/milestones/M001/M001-CONTEXT.md | 122 ------------- .gsd/milestones/M001/M001-ROADMAP.md | 158 ----------------- .gsd/milestones/M001/slices/S01/S01-PLAN.md | 85 --------- .../M001/slices/S01/S01-RESEARCH.md | 80 --------- .../milestones/M001/slices/S01/S01-SUMMARY.md | 131 -------------- .gsd/milestones/M001/slices/S01/S01-UAT.md | 101 ----------- .../M001/slices/S01/tasks/T01-PLAN.md | 60 ------- .../M001/slices/S01/tasks/T01-SUMMARY.md | 60 ------- .../M001/slices/S01/tasks/T01-VERIFY.json | 18 -- .../M001/slices/S01/tasks/T02-PLAN.md | 60 ------- .../M001/slices/S01/tasks/T02-SUMMARY.md | 64 ------- .../M001/slices/S01/tasks/T02-VERIFY.json | 18 -- .../M001/slices/S01/tasks/T03-PLAN.md | 65 ------- .../M001/slices/S01/tasks/T03-SUMMARY.md | 73 -------- .../M001/slices/S01/tasks/T03-VERIFY.json | 18 -- .../M001/slices/S01/tasks/T04-PLAN.md | 57 ------ .../M001/slices/S01/tasks/T04-SUMMARY.md | 60 ------- .../M001/slices/S01/tasks/T04-VERIFY.json | 18 -- .gsd/milestones/M001/slices/S02/S02-PLAN.md | 74 -------- .../M001/slices/S02/S02-RESEARCH.md | 84 --------- .../milestones/M001/slices/S02/S02-SUMMARY.md | 132 -------------- .gsd/milestones/M001/slices/S02/S02-UAT.md | 126 -------------- .../M001/slices/S02/tasks/T01-PLAN.md | 58 ------- .../M001/slices/S02/tasks/T01-SUMMARY.md | 66 ------- .../M001/slices/S02/tasks/T01-VERIFY.json | 18 -- .../M001/slices/S02/tasks/T02-PLAN.md | 60 ------- .../M001/slices/S02/tasks/T02-SUMMARY.md | 72 -------- .../M001/slices/S02/tasks/T02-VERIFY.json | 18 -- .../M001/slices/S02/tasks/T03-PLAN.md | 53 ------ .../M001/slices/S02/tasks/T03-SUMMARY.md | 69 -------- .../M001/slices/S02/tasks/T03-VERIFY.json | 18 -- .gsd/milestones/M001/slices/S03/S03-PLAN.md | 91 ---------- .../M001/slices/S03/S03-RESEARCH.md | 111 ------------ .../milestones/M001/slices/S03/S03-SUMMARY.md | 131 -------------- .gsd/milestones/M001/slices/S03/S03-UAT.md | 70 -------- .../M001/slices/S03/tasks/T01-PLAN.md | 88 ---------- .../M001/slices/S03/tasks/T01-SUMMARY.md | 77 --------- .../M001/slices/S03/tasks/T01-VERIFY.json | 18 -- .../M001/slices/S03/tasks/T02-PLAN.md | 75 -------- .../M001/slices/S03/tasks/T02-SUMMARY.md | 70 -------- .../M001/slices/S03/tasks/T02-VERIFY.json | 18 -- .../M001/slices/S03/tasks/T03-PLAN.md | 78 --------- .../M001/slices/S03/tasks/T03-SUMMARY.md | 84 --------- .../M001/slices/S03/tasks/T03-VERIFY.json | 18 -- .gsd/milestones/M001/slices/S04/S04-PLAN.md | 83 --------- .../M001/slices/S04/S04-RESEARCH.md | 73 -------- .../milestones/M001/slices/S04/S04-SUMMARY.md | 139 --------------- .gsd/milestones/M001/slices/S04/S04-UAT.md | 94 ---------- .../M001/slices/S04/tasks/T01-PLAN.md | 64 ------- .../M001/slices/S04/tasks/T01-SUMMARY.md | 72 -------- .../M001/slices/S04/tasks/T01-VERIFY.json | 18 -- .../M001/slices/S04/tasks/T02-PLAN.md | 60 ------- .../M001/slices/S04/tasks/T02-SUMMARY.md | 82 --------- .../M001/slices/S04/tasks/T02-VERIFY.json | 18 -- .../M001/slices/S04/tasks/T03-PLAN.md | 75 -------- .../M001/slices/S04/tasks/T03-SUMMARY.md | 98 ----------- .../M001/slices/S04/tasks/T03-VERIFY.json | 18 -- .../M001/slices/S04/tasks/T04-PLAN.md | 54 ------ .../M001/slices/S04/tasks/T04-SUMMARY.md | 78 --------- .../M001/slices/S04/tasks/T04-VERIFY.json | 18 -- .gsd/milestones/M001/slices/S05/S05-PLAN.md | 94 ---------- .../M001/slices/S05/S05-RESEARCH.md | 114 ------------ .../milestones/M001/slices/S05/S05-SUMMARY.md | 162 ------------------ .gsd/milestones/M001/slices/S05/S05-UAT.md | 117 ------------- .../M001/slices/S05/tasks/T01-PLAN.md | 98 ----------- .../M001/slices/S05/tasks/T01-SUMMARY.md | 99 ----------- .../M001/slices/S05/tasks/T01-VERIFY.json | 18 -- .../M001/slices/S05/tasks/T02-PLAN.md | 73 -------- .../M001/slices/S05/tasks/T02-SUMMARY.md | 73 -------- .../M001/slices/S05/tasks/T02-VERIFY.json | 18 -- .../M001/slices/S05/tasks/T03-PLAN.md | 129 -------------- .../M001/slices/S05/tasks/T03-SUMMARY.md | 97 ----------- .../M001/slices/S05/tasks/T03-VERIFY.json | 18 -- .../M001/slices/S05/tasks/T04-PLAN.md | 131 -------------- .../M001/slices/S05/tasks/T04-SUMMARY.md | 116 ------------- .../M001/slices/S05/tasks/T04-VERIFY.json | 18 -- .gsd/milestones/M001/slices/S06/S06-PLAN.md | 126 -------------- .../M001/slices/S06/S06-RESEARCH.md | 133 -------------- .../M001/slices/S06/tasks/T01-PLAN.md | 106 ------------ .../M001/slices/S06/tasks/T02-PLAN.md | 143 ---------------- .../extensions/gsd/tools/plan-task.ts | 36 ++-- 82 files changed, 19 insertions(+), 5969 deletions(-) delete mode 100644 .gsd/milestones/.DS_Store delete mode 100644 .gsd/milestones/M001/M001-CONTEXT.md delete mode 100644 .gsd/milestones/M001/M001-ROADMAP.md delete mode 100644 .gsd/milestones/M001/slices/S01/S01-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S01/S01-RESEARCH.md delete mode 100644 .gsd/milestones/M001/slices/S01/S01-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S01/S01-UAT.md delete mode 100644 .gsd/milestones/M001/slices/S01/tasks/T01-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S01/tasks/T01-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S01/tasks/T01-VERIFY.json delete mode 100644 .gsd/milestones/M001/slices/S01/tasks/T02-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S01/tasks/T02-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S01/tasks/T02-VERIFY.json delete mode 100644 .gsd/milestones/M001/slices/S01/tasks/T03-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S01/tasks/T03-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S01/tasks/T03-VERIFY.json delete mode 100644 .gsd/milestones/M001/slices/S01/tasks/T04-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S01/tasks/T04-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S01/tasks/T04-VERIFY.json delete mode 100644 .gsd/milestones/M001/slices/S02/S02-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S02/S02-RESEARCH.md delete mode 100644 .gsd/milestones/M001/slices/S02/S02-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S02/S02-UAT.md delete mode 100644 .gsd/milestones/M001/slices/S02/tasks/T01-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S02/tasks/T01-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S02/tasks/T01-VERIFY.json delete mode 100644 .gsd/milestones/M001/slices/S02/tasks/T02-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S02/tasks/T02-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S02/tasks/T02-VERIFY.json delete mode 100644 .gsd/milestones/M001/slices/S02/tasks/T03-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S02/tasks/T03-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S02/tasks/T03-VERIFY.json delete mode 100644 .gsd/milestones/M001/slices/S03/S03-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S03/S03-RESEARCH.md delete mode 100644 .gsd/milestones/M001/slices/S03/S03-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S03/S03-UAT.md delete mode 100644 .gsd/milestones/M001/slices/S03/tasks/T01-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S03/tasks/T01-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S03/tasks/T01-VERIFY.json delete mode 100644 .gsd/milestones/M001/slices/S03/tasks/T02-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S03/tasks/T02-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S03/tasks/T02-VERIFY.json delete mode 100644 .gsd/milestones/M001/slices/S03/tasks/T03-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S03/tasks/T03-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S03/tasks/T03-VERIFY.json delete mode 100644 .gsd/milestones/M001/slices/S04/S04-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S04/S04-RESEARCH.md delete mode 100644 .gsd/milestones/M001/slices/S04/S04-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S04/S04-UAT.md delete mode 100644 .gsd/milestones/M001/slices/S04/tasks/T01-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S04/tasks/T01-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S04/tasks/T01-VERIFY.json delete mode 100644 .gsd/milestones/M001/slices/S04/tasks/T02-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S04/tasks/T02-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S04/tasks/T02-VERIFY.json delete mode 100644 .gsd/milestones/M001/slices/S04/tasks/T03-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S04/tasks/T03-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S04/tasks/T03-VERIFY.json delete mode 100644 .gsd/milestones/M001/slices/S04/tasks/T04-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S04/tasks/T04-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S04/tasks/T04-VERIFY.json delete mode 100644 .gsd/milestones/M001/slices/S05/S05-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S05/S05-RESEARCH.md delete mode 100644 .gsd/milestones/M001/slices/S05/S05-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S05/S05-UAT.md delete mode 100644 .gsd/milestones/M001/slices/S05/tasks/T01-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S05/tasks/T01-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S05/tasks/T01-VERIFY.json delete mode 100644 .gsd/milestones/M001/slices/S05/tasks/T02-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S05/tasks/T02-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S05/tasks/T02-VERIFY.json delete mode 100644 .gsd/milestones/M001/slices/S05/tasks/T03-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S05/tasks/T03-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S05/tasks/T03-VERIFY.json delete mode 100644 .gsd/milestones/M001/slices/S05/tasks/T04-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S05/tasks/T04-SUMMARY.md delete mode 100644 .gsd/milestones/M001/slices/S05/tasks/T04-VERIFY.json delete mode 100644 .gsd/milestones/M001/slices/S06/S06-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S06/S06-RESEARCH.md delete mode 100644 .gsd/milestones/M001/slices/S06/tasks/T01-PLAN.md delete mode 100644 .gsd/milestones/M001/slices/S06/tasks/T02-PLAN.md diff --git a/.gsd/milestones/.DS_Store b/.gsd/milestones/.DS_Store deleted file mode 100644 index 2c5d28252c83cec23ecd95f3f849f85a061472b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKF;2r!47DLc5DXm|{}IRu_*7v;Lh1!jsRTo-bm<;-=|Q*zH|Pnt56|`oC5p<( z0MC{E^8Nktn>WO`#8QI@5cM9ANRMf!~gaODvb(I0V+TRsKCEe06p8R zz6@lf0#twsd@Eq@hXgmw1^YmMbs+c%0JP6|H(dKH0Zf(v=7N17GB6D)FsNEa3=KN+ zsnq3yePGZ<{bbyyoUCO+Q9m8|dfw2PTv7A}|zlWcg|HmY*r~noCQwnI+ zF4{RBsr1&#!&$FQ@F)0}q1MY0ycGkz6=Pwo_>B&IU?1po See `.gsd/DECISIONS.md` for all architectural and pattern decisions — it is an append-only register; read it during planning, append to it during execution. - -## Relevant Requirements - -- R001–R008 — Schema and tool implementations (S01–S03) -- R009–R010 — Caller migration (S04–S05) -- R011 — Flag file migration (S05) -- R012 — Parser deprecation (S06) -- R013–R019 — Cross-cutting concerns (prompts, validation, caching, migration) - -## Scope - -### In Scope - -- Schema v7→v8 migration with new columns and tables -- 5 new planning tools: gsd_plan_milestone, gsd_plan_slice, gsd_plan_task, gsd_replan_slice, gsd_reassess_roadmap -- Full markdown renderers (ROADMAP.md, PLAN.md, T##-PLAN.md) from DB state -- Hot-path and warm/cold caller migration from parsers to DB queries -- Flag file → DB column migration (REPLAN, ASSESSMENT, CONTINUE, CONTEXT-DRAFT, REPLAN-TRIGGER) -- Prompt migration for 4 planning prompts -- Cross-validation tests for the transition window -- Pre-M002 project migration via extended migrateHierarchyToDb() -- Rogue file detection for PLAN/ROADMAP writes - -### Out of Scope / Non-Goals - -- CQRS/event-sourcing architecture (R023) -- Perfect round-trip recovery for tool-only fields (R024) -- StateEngine abstraction layer (R021 — deferred) -- parseSummary() migration (R020 — deferred) -- Native Rust parser bridge removal (R022 — deferred, low risk follow-up) - -## Technical Constraints - -- Flat tool schemas (locked decision #1) — separate calls per entity, not deeply nested -- No StateEngine abstraction (locked decision #2) — query functions added to gsd-db.ts -- CONTINUE.md and CONTEXT-DRAFT migrate in M002 (locked decision #3) -- Recovery accepts fidelity loss for tool-only fields (locked decision #4) -- T##-PLAN.md files must remain a runtime contract — DB rows don't replace file existence checks -- Sequence columns must propagate to query ORDER BY — otherwise reordering is a no-op -- cachedParse() TTL cache must be invalidated alongside state cache in all tool handlers - -## Integration Points - -- `auto-dispatch.ts` dispatch rules — migrate 4 rules from disk I/O to DB queries -- `dispatch-guard.ts` — migrate from parseRoadmapSlices() to getMilestoneSlices() -- `auto-prompts.ts` — context injection pipeline (loads ROADMAP/PLAN from disk → could use artifacts table) -- `deriveStateFromDb()` — flag file checks currently use existsSync, migrate to DB columns -- `bootstrap/register-hooks.ts` — CONTINUE.md hook writers must migrate to DB writes -- `guided-resume-task.md` prompt — reads CONTINUE.md, must read from DB column instead -- `md-importer.ts` — migrateHierarchyToDb() extended for v8 columns - -## Open Questions - -- None — all design decisions locked in issue #2228 comments diff --git a/.gsd/milestones/M001/M001-ROADMAP.md b/.gsd/milestones/M001/M001-ROADMAP.md deleted file mode 100644 index f4be1eccf..000000000 --- a/.gsd/milestones/M001/M001-ROADMAP.md +++ /dev/null @@ -1,158 +0,0 @@ -# M001: Tool-Driven Planning State Capture - -**Vision:** Complete the markdown→DB migration for planning state, eliminating 57+ parseRoadmap() callers, 42+ parsePlan() callers, and the 12-variant regex cascade. The LLM produces creative planning work via structured tool calls. TypeScript owns all state transitions. Markdown files become rendered views, not sources of truth. - -## Success Criteria - -- Auto-mode completes a full planning cycle (plan milestone → plan slice → execute → replan → reassess) using tool calls with zero parseRoadmap/parsePlan calls in the dispatch loop -- Replan that references a completed task is structurally rejected by the tool handler -- Pre-M002 project with existing ROADMAP.md and PLAN.md auto-migrates to DB on first open -- deriveStateFromDb() resolves planning state without filesystem scanning for flag files - -## Key Risks / Unknowns - -- LLM compliance with multi-tool planning sequence — mitigated by flat schemas, TypeBox validation, clear errors -- Renderer fidelity during transition window — mitigated by cross-validation tests -- CONTINUE.md is a structured resume contract, not a flag — migration must preserve hook writers, prompt construction, cleanup semantics -- Prompt migration complexity — planning prompts are more complex than execution prompts - -## Proof Strategy - -- LLM schema compliance → retire in S01/S02 by proving the tools accept valid input and reject invalid input via unit tests -- Renderer fidelity → retire in S04 by proving DB state matches rendered-then-parsed state via cross-validation tests -- CONTINUE.md complexity → retire in S05 by proving auto-mode resume flow works after flag file migration -- Prompt quality → retire in S01/S02/S03 by verifying prompts produce valid tool calls in integration tests - -## Verification Classes - -- Contract verification: unit tests for tool handlers (validation, DB writes, rendering), cross-validation tests (DB↔parsed parity), parser removal doesn't break test suite -- Integration verification: auto-mode dispatch loop uses DB queries, planning prompts produce valid tool calls -- Operational verification: pre-M002 project migration, gsd recover handles v8 columns -- UAT / human verification: auto-mode runs a real milestone end-to-end using new tools - -## Milestone Definition of Done - -This milestone is complete only when all are true: - -- All 5 planning tools are registered and functional (plan_milestone, plan_slice, plan_task, replan_slice, reassess_roadmap) -- Zero parseRoadmap()/parsePlan()/parseRoadmapSlices() calls in the dispatch loop hot path -- Replan and reassess structurally enforce preservation of completed tasks/slices -- deriveStateFromDb() covers planning data — flag file checks moved to DB columns -- Cross-validation tests prove DB state matches rendered-then-parsed state -- All existing tests pass (no regressions) -- Pre-M002 projects auto-migrate via migrateHierarchyToDb() with best-effort v8 column population -- Planning prompts produce valid tool calls (not direct file writes) - -## Requirement Coverage - -- Covers: R001, R002, R003, R004, R005, R006, R007, R008, R009, R010, R011, R012, R013, R014, R015, R016, R017, R018, R019 -- Partially covers: none -- Leaves for later: R020 (parseSummary), R021 (StateEngine), R022 (native parser bridge) -- Orphan risks: none - -## Slices - -- [x] **S01: Schema v8 + plan_milestone tool + ROADMAP renderer** `risk:high` `depends:[]` - > After this: gsd_plan_milestone tool accepts structured params, writes to DB, renders ROADMAP.md from DB state. Parsers still work as fallback. Schema v8 migration runs on existing DBs. Rogue detection extended for ROADMAP writes. - -- [x] **S02: plan_slice + plan_task tools + PLAN/task-plan renderers** `risk:high` `depends:[S01]` - > After this: gsd_plan_slice and gsd_plan_task tools accept structured params, write to DB, render S##-PLAN.md and T##-PLAN.md from DB. Task plan files pass existence checks. Prompt migration for plan-slice.md complete. - -- [x] **S03: replan_slice + reassess_roadmap with structural enforcement** `risk:medium` `depends:[S01,S02]` - > After this: gsd_replan_slice rejects mutations to completed tasks, gsd_reassess_roadmap rejects mutations to completed slices. replan_history and assessments tables populated. REPLAN.md and ASSESSMENT.md rendered from DB. - -- [x] **S04: Hot-path caller migration + cross-validation tests** `risk:medium` `depends:[S01,S02]` - > After this: dispatch-guard.ts, auto-dispatch.ts (4 rules), auto-verification.ts, parallel-eligibility.ts read from DB. Cross-validation tests prove DB↔rendered parity. Sequence-aware query ordering in getMilestoneSlices/getSliceTasks. - -- [x] **S05: Warm/cold callers + flag files + pre-M002 migration** `risk:medium` `depends:[S03,S04]` - > After this: doctor, visualizer, github-sync, workspace-index, dashboard-overlay, guided-flow, reactive-graph, auto-recovery use DB queries. REPLAN/ASSESSMENT/CONTINUE/CONTEXT-DRAFT/REPLAN-TRIGGER tracked in DB. migrateHierarchyToDb() populates v8 columns. gsd recover upgraded. - -- [x] **S06: Parser deprecation + cleanup** `risk:low` `depends:[S05]` - > After this: parseRoadmapSlices() removed from hot paths (~271 lines). parsePlan() task parsing removed (~120 lines). parseRoadmap() slice extraction removed (~85 lines). Parsers kept only in md-importer for migration. Zero parseRoadmap/parsePlan calls in dispatch loop. Test suite passes with parsers removed from hot paths. - -## Boundary Map - -### S01 → S02 - -Produces: -- `gsd-db.ts` → schema v8 migration (new columns on milestones, slices, tasks tables; replan_history, assessments tables) -- `gsd-db.ts` → `insertMilestonePlanning()`, `getMilestonePlanning()` query functions -- `gsd-db.ts` → `insertSlicePlanning()`, `getSlicePlanning()` query functions (columns only — S02 populates them) -- `tools/plan-milestone.ts` → `gsd_plan_milestone` tool handler pattern (validate → transaction → render → invalidate) -- `markdown-renderer.ts` → `renderRoadmapFromDb(basePath, milestoneId)` — full ROADMAP.md generation from DB -- `auto-post-unit.ts` → rogue detection for ROADMAP.md writes - -Consumes: -- nothing (first slice) - -### S01 → S03 - -Produces: -- Schema v8 tables: `replan_history`, `assessments` (created in S01 migration, populated in S03) -- Tool handler pattern established in `tools/plan-milestone.ts` -- `renderRoadmapFromDb()` — reused by reassess for re-rendering after modification - -Consumes: -- nothing (first slice) - -### S02 → S03 - -Produces: -- `gsd-db.ts` → `getSliceTasks()`, `getTask()` query functions -- `tools/plan-slice.ts`, `tools/plan-task.ts` → handler patterns -- `markdown-renderer.ts` → `renderPlanFromDb()`, `renderTaskPlanFromDb()` - -Consumes from S01: -- Schema v8 columns on slices and tasks tables -- Tool handler pattern from `tools/plan-milestone.ts` - -### S02 → S04 - -Produces: -- `gsd-db.ts` → `getSliceTasks()`, `getTask()` with `verify_command`, `files`, `steps` columns populated -- `renderPlanFromDb()`, `renderTaskPlanFromDb()` for artifacts table population - -Consumes from S01: -- Schema v8, query functions - -### S01,S02 → S04 - -Produces (from S01+S02 combined): -- All planning data in DB (milestones, slices, tasks with v8 columns) -- All query functions needed by callers -- Rendered markdown in artifacts table - -Consumes: -- S01: schema, milestone query functions, ROADMAP renderer -- S02: slice/task query functions, PLAN/task-plan renderers - -### S03 → S05 - -Produces: -- `replan_history` table populated with actual replan events -- `assessments` table populated with actual assessments -- REPLAN.md and ASSESSMENT.md rendered from DB (flag file equivalents) - -Consumes from S01, S02: -- Schema, query functions, renderers - -### S04 → S05 - -Produces: -- Hot-path callers migrated to DB — dispatch loop no longer parses markdown -- Sequence-aware query ordering proven in getMilestoneSlices/getSliceTasks -- Cross-validation test infrastructure - -Consumes from S01, S02: -- Query functions, renderers, DB-populated planning data - -### S05 → S06 - -Produces: -- All callers migrated to DB queries -- Flag files migrated to DB columns -- migrateHierarchyToDb() populates v8 columns -- No caller depends on parseRoadmap/parsePlan/parseRoadmapSlices except md-importer - -Consumes from S03, S04: -- replan/assessment DB tables, hot-path migration complete, query functions diff --git a/.gsd/milestones/M001/slices/S01/S01-PLAN.md b/.gsd/milestones/M001/slices/S01/S01-PLAN.md deleted file mode 100644 index 5dbfd551b..000000000 --- a/.gsd/milestones/M001/slices/S01/S01-PLAN.md +++ /dev/null @@ -1,85 +0,0 @@ -# S01: Schema v8 + plan_milestone tool + ROADMAP renderer - -**Goal:** Make milestone planning DB-backed by adding schema v8 storage, a `gsd_plan_milestone` write path, full ROADMAP rendering from DB, and prompt/enforcement updates that stop direct roadmap writes from bypassing state. -**Demo:** Running the milestone-planning handler against structured input writes milestone planning fields into SQLite, renders `.gsd/milestones/M001/M001-ROADMAP.md` from DB state, and tests prove prompt contracts plus rogue-write detection cover the transition path. - -## Must-Haves - -- Schema v8 stores milestone-planning data plus downstream slice/task planning columns and creates `replan_history` and `assessments` tables without breaking existing DBs. -- `gsd_plan_milestone` validates flat structured input, writes milestone + slice planning data transactionally, renders ROADMAP.md from DB, and clears state/parse caches after render. -- `renderRoadmapFromDb()` emits a complete parser-compatible roadmap including vision, success criteria, risks, proof strategy, verification classes, definition of done, requirement coverage, slices, and boundary map. -- Planning prompts stop instructing direct roadmap writes and rogue detection flags direct `ROADMAP.md` / `PLAN.md` writes that bypass planning tools. -- Migration and renderer/tool tests prove v7→v8 upgrade, roadmap round-trip fidelity, tool-handler behavior, and prompt/enforcement coverage. - -## Proof Level - -- This slice proves: integration -- Real runtime required: yes -- Human/UAT required: no - -## Verification - -- `node --test src/resources/extensions/gsd/tests/plan-milestone.test.ts` -- `node --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts` -- `node --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts` -- `node --test src/resources/extensions/gsd/tests/rogue-file-detection.test.ts src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts` -- `node --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts --test-name-pattern="stderr warning|stale"` - -## Observability / Diagnostics - -- Runtime signals: tool handler returns structured error details for schema validation / render failures; migration and rogue-detection tests expose fallback-path regressions. -- Inspection surfaces: `src/resources/extensions/gsd/tests/plan-milestone.test.ts`, `src/resources/extensions/gsd/tests/markdown-renderer.test.ts`, `src/resources/extensions/gsd/tests/rogue-file-detection.test.ts`, and SQLite rows in milestone/slice/artifact tables. -- Failure visibility: render failures must surface before cache invalidation completes; rogue detection must name the offending roadmap/plan path; migration tests must show whether v8 columns/tables were created. -- Redaction constraints: none beyond normal repository data; no secrets involved. - -## Integration Closure - -- Upstream surfaces consumed: `src/resources/extensions/gsd/gsd-db.ts`, `src/resources/extensions/gsd/markdown-renderer.ts`, `src/resources/extensions/gsd/bootstrap/db-tools.ts`, `src/resources/extensions/gsd/md-importer.ts`, `src/resources/extensions/gsd/auto-post-unit.ts`, existing parser contracts in `src/resources/extensions/gsd/files.ts`. -- New wiring introduced in this slice: milestone-planning DB accessors, `gsd_plan_milestone` tool registration/handler, full ROADMAP render path, prompt contract migration, and rogue-write detection for planning artifacts. -- What remains before the milestone is truly usable end-to-end: slice/task planning tools, reassess/replan structural enforcement, caller migration to DB reads, and full hot-path parser retirement in later slices. - -## Tasks - -- [x] **T01: Add schema v8 planning storage and roadmap rendering** `est:1h15m` - - Why: S01 cannot write milestone planning through tools until SQLite can hold the fields and ROADMAP.md can be regenerated from DB without relying on an existing file. - - Files: `src/resources/extensions/gsd/gsd-db.ts`, `src/resources/extensions/gsd/markdown-renderer.ts`, `src/resources/extensions/gsd/md-importer.ts`, `src/resources/extensions/gsd/tests/markdown-renderer.test.ts`, `src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts` - - Do: Add the v7→v8 migration for milestone/slice/task planning columns and `replan_history` / `assessments`; add milestone-planning query/upsert helpers needed by the new tool; implement full `renderRoadmapFromDb()` with parser-compatible output and artifact persistence; extend importer coverage so pre-v8 roadmap content backfills new milestone fields best-effort on migration. - - Verify: `node --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts` - - Done when: opening a v7 DB upgrades to v8, roadmap rendering can generate a complete file from DB state, and migration tests prove existing roadmap content still imports cleanly. -- [x] **T02: Wire gsd_plan_milestone through the DB-backed tool path** `est:1h15m` - - Why: The slice promise is a real planning tool, not just storage and renderer primitives. The handler must establish the validate → transaction → render → invalidate pattern downstream slices will reuse. - - Files: `src/resources/extensions/gsd/tools/plan-milestone.ts`, `src/resources/extensions/gsd/bootstrap/db-tools.ts`, `src/resources/extensions/gsd/tests/plan-milestone.test.ts`, `src/resources/extensions/gsd/gsd-db.ts`, `src/resources/extensions/gsd/markdown-renderer.ts` - - Do: Implement the milestone-planning handler using the existing completion-tool pattern; ensure it performs structural validation on flat tool params, upserts milestone and slice planning rows in one transaction, renders/stores ROADMAP.md after commit, and explicitly calls `invalidateStateCache()` and `clearParseCache()` after successful render; register canonical + alias tool definitions in `db-tools.ts`. - - Verify: `node --test src/resources/extensions/gsd/tests/plan-milestone.test.ts` - - Done when: the handler rejects invalid payloads, writes valid planning data to DB, renders the roadmap artifact, stores rendered content, and tests prove cache invalidation and idempotent reruns. -- [x] **T03: Migrate planning prompts and enforce rogue-write detection** `est:50m` - - Why: The tool path is incomplete if prompts still tell the model to write roadmap files directly or if direct writes can bypass DB state silently. - - Files: `src/resources/extensions/gsd/prompts/plan-milestone.md`, `src/resources/extensions/gsd/prompts/guided-plan-milestone.md`, `src/resources/extensions/gsd/prompts/plan-slice.md`, `src/resources/extensions/gsd/prompts/replan-slice.md`, `src/resources/extensions/gsd/prompts/reassess-roadmap.md`, `src/resources/extensions/gsd/auto-post-unit.ts`, `src/resources/extensions/gsd/tests/prompt-contracts.test.ts`, `src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` - - Do: Rewrite planning prompts so they instruct tool calls instead of direct roadmap/plan file writes while preserving existing planning context variables; extend `detectRogueFileWrites()` to flag direct `ROADMAP.md` and `PLAN.md` writes for planning units; add contract tests that prove the new instructions and enforcement paths hold. - - Verify: `node --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` - - Done when: planning prompts name the DB tools, direct file-write instructions are gone, and rogue detection tests fail if roadmap/plan files appear without matching DB state. -- [x] **T04: Close the slice with integrated regression coverage** `est:40m` - - Why: S01 crosses schema migration, tool registration, markdown rendering, prompt contracts, and migration fallback. The slice is only done when those surfaces pass together, not as isolated edits. - - Files: `src/resources/extensions/gsd/tests/plan-milestone.test.ts`, `src/resources/extensions/gsd/tests/markdown-renderer.test.ts`, `src/resources/extensions/gsd/tests/prompt-contracts.test.ts`, `src/resources/extensions/gsd/tests/rogue-file-detection.test.ts`, `src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts` - - Do: Fill remaining regression gaps discovered during implementation, keep test fixtures aligned with the final roadmap format/tool output, and run the full targeted S01 suite so downstream slices inherit a stable baseline. - - Verify: `node --test src/resources/extensions/gsd/tests/plan-milestone.test.ts src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/prompt-contracts.test.ts src/resources/extensions/gsd/tests/rogue-file-detection.test.ts src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts` - - Done when: the combined targeted suite passes against the final implementation and demonstrates the slice demo truthfully. - -## Files Likely Touched - -- `src/resources/extensions/gsd/gsd-db.ts` -- `src/resources/extensions/gsd/markdown-renderer.ts` -- `src/resources/extensions/gsd/tools/plan-milestone.ts` -- `src/resources/extensions/gsd/bootstrap/db-tools.ts` -- `src/resources/extensions/gsd/md-importer.ts` -- `src/resources/extensions/gsd/auto-post-unit.ts` -- `src/resources/extensions/gsd/prompts/plan-milestone.md` -- `src/resources/extensions/gsd/prompts/guided-plan-milestone.md` -- `src/resources/extensions/gsd/prompts/plan-slice.md` -- `src/resources/extensions/gsd/prompts/replan-slice.md` -- `src/resources/extensions/gsd/prompts/reassess-roadmap.md` -- `src/resources/extensions/gsd/tests/plan-milestone.test.ts` -- `src/resources/extensions/gsd/tests/markdown-renderer.test.ts` -- `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` -- `src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` -- `src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts` diff --git a/.gsd/milestones/M001/slices/S01/S01-RESEARCH.md b/.gsd/milestones/M001/slices/S01/S01-RESEARCH.md deleted file mode 100644 index 2b059e6af..000000000 --- a/.gsd/milestones/M001/slices/S01/S01-RESEARCH.md +++ /dev/null @@ -1,80 +0,0 @@ -# S01 — Research - -**Date:** 2026-03-23 - -## Summary - -S01 owns R001, R002, R007, R013, R015, and R018. This slice is targeted research, not deep exploration. The codebase already has the exact handler pattern to copy: `tools/complete-task.ts` and `tools/complete-slice.ts` do validate → DB transaction → render → cache invalidation, and `bootstrap/db-tools.ts` already registers canonical + alias DB-backed tools. The missing pieces are schema v8 expansion in `gsd-db.ts`, a new milestone-planning write path/tool, a full ROADMAP renderer from DB state, prompt migration away from direct file writes, and rogue-write detection extended beyond summaries. - -The main constraint is transition-window fidelity. Existing callers still parse rendered markdown. `markdown-renderer.ts` currently only patches existing checkbox content (`renderRoadmapCheckboxes`, `renderPlanCheckboxes`) and explicitly relies on round-tripping through `parseRoadmap()` / `parsePlan()`. That means S01 cannot get away with partial rendering or a lossy format. `renderRoadmapFromDb()` has to emit the same sections the parser-dependent callers/tests expect: title, vision, success criteria, slices with checkbox/risk/depends/demo lines, proof strategy, verification classes, milestone definition of done, boundary map, and requirement coverage. - -## Recommendation - -Implement S01 in four build steps: (1) schema/query expansion in `gsd-db.ts`, (2) ROADMAP rendering from DB in `markdown-renderer.ts`, (3) `gsd_plan_milestone` handler + tool registration, and (4) prompt/rogue-detection/test coverage. Follow the existing M001 tool pattern exactly rather than inventing a planning-specific abstraction. That matches decision D002 and the established extension rule from the `create-gsd-extension` skill: add capabilities using the existing extension primitives/patterns, don’t build a parallel framework. - -Use a flat tool schema. That is already locked by D001 and is also the least risky shape for TypeBox validation and tool registration. Keep cache invalidation explicit in the handler after DB write + render: `invalidateStateCache()` plus `clearParseCache()` are mandatory for R015 because parser callers still sit on the hot path during the transition. Also extend rogue detection immediately in `auto-post-unit.ts`; otherwise prompt migration has no enforcement surface and direct ROADMAP writes will silently bypass the DB. - -## Implementation Landscape - -### Key Files - -- `src/resources/extensions/gsd/gsd-db.ts` — current schema is `SCHEMA_VERSION = 7`; has v1→v7 incremental migrations, row interfaces, and accessors. Needs v8 columns/tables plus milestone-planning read/write functions. Existing ordering is still `ORDER BY id` in `getMilestoneSlices()` and `getSliceTasks()`; S01 likely adds sequence columns now even though ORDER BY migration is validated in S04. -- `src/resources/extensions/gsd/markdown-renderer.ts` — current renderer is patch-oriented, not full generation. `renderRoadmapCheckboxes()` loads existing artifact content and regex-toggles `[ ]`/`[x]`. S01 needs a new `renderRoadmapFromDb(basePath, milestoneId)` that generates the entire file, writes it, stores artifact content, and invalidates caches. -- `src/resources/extensions/gsd/tools/complete-task.ts` — best concrete reference for a DB-backed tool handler. Pattern: validate params, `transaction(...)`, render file(s) outside transaction, rollback status on render failure, then invalidate `invalidateStateCache()`, `clearPathCache()`, and `clearParseCache()`. -- `src/resources/extensions/gsd/tools/complete-slice.ts` — second reference for handler shape and roadmap rendering callout. Shows how parent rows are ensured before updates and how roadmap rendering is treated as a post-transaction filesystem step. -- `src/resources/extensions/gsd/bootstrap/db-tools.ts` — tool registration seam. Existing DB tools use TypeBox, canonical names plus alias registration, `ensureDbOpen()`, and structured `details`. Add `gsd_plan_milestone` here and keep aliases/prompt guidelines consistent with current style. -- `src/resources/extensions/gsd/md-importer.ts` — `migrateHierarchyToDb()` currently imports milestone title/status/depends_on, slice title/risk/depends/demo, and task title/status from parsed markdown. For S01 it must at minimum tolerate schema v8 and populate new milestone planning columns best-effort from existing ROADMAP content. -- `src/resources/extensions/gsd/files.ts` — parser contract surface. `parseRoadmap()` currently extracts only title, vision, successCriteria, slices, and boundaryMap. Transition-window consumers still depend on this output, so ROADMAP rendering must preserve parser-readable structure even before richer DB-only fields are fully consumed. -- `src/resources/extensions/gsd/auto-post-unit.ts` — `detectRogueFileWrites()` currently only checks task and slice summaries. Extend it for direct `ROADMAP.md`/`PLAN.md` writes so planning tools have the same safety net completion tools already have. -- `src/resources/extensions/gsd/prompts/guided-plan-milestone.md` — still instructs the model to create `{{milestoneId}}-ROADMAP.md` directly. This is the primary prompt migration target for S01. `plan-milestone.md` likely needs the same migration even though only guided prompt text was inspected directly. -- `src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` — existing safety-net tests for summary files. Natural place to add roadmap/plan rogue detection coverage. -- `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` — existing contract-test pattern for prompt migration (`execute-task`, `complete-slice`). Add assertions that milestone-planning prompts reference `gsd_plan_milestone` and stop instructing direct file writes. -- `src/resources/extensions/gsd/tests/markdown-renderer.test.ts` — already validates renderer round-trips via `parseRoadmap()` / `parsePlan()`. Extend with full ROADMAP-from-DB tests rather than inventing a new harness. -- `src/resources/extensions/gsd/tests/derive-state-crossval.test.ts` — model for transition-window parity tests called out in the milestone context. S01 won’t retire R014, but this file shows the test shape downstream slices should follow. - -### Build Order - -1. **Schema first in `gsd-db.ts`.** Add v8 columns/tables and row/interface/query support before touching tools. This unblocks every downstream step and avoids hand-building temporary storage. -2. **Implement `renderRoadmapFromDb()` next.** S01 writes DB first but callers still parse markdown. Until the full ROADMAP renderer exists and round-trips, the tool handler cannot be trusted. -3. **Build `tools/plan-milestone.ts` and register `gsd_plan_milestone`.** Copy the completion-tool pattern: validate → transaction/upserts → render → artifact store/caches. This is the core deliverable for R002/R015. -4. **Then migrate prompts and rogue detection.** Once the tool exists, update `plan-milestone.md` / `guided-plan-milestone.md` to call it, and extend `detectRogueFileWrites()` + tests so direct markdown writes become visible failures instead of silent divergence. -5. **Last, importer/backfill tests.** Best-effort v8 migration/import logic is lower risk than the write path but needs coverage before the slice is declared done. - -### Verification Approach - -- Run targeted node tests around the touched surfaces, starting with: - - `src/resources/extensions/gsd/tests/markdown-renderer.test.ts` - - `src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` - - `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` - - any new `plan-milestone` handler/tool tests added for S01 -- Add/extend schema migration coverage in `src/resources/extensions/gsd/tests/gsd-db.test.ts` or a dedicated `plan-milestone` test file so opening a v7 DB proves v8 migration succeeds. -- Add handler proof similar to `complete-task.test.ts` / `complete-slice.test.ts`: valid input writes DB rows, renders `M###-ROADMAP.md`, stores artifact content, and invalidates caches; invalid input is structurally rejected. -- Add renderer round-trip proof: generated ROADMAP parses via `parseRoadmap()` and preserves slice IDs, checkbox state, risk, dependencies, and boundary map sections. -- Add prompt contract proof that milestone-planning prompts reference `gsd_plan_milestone` and no longer instruct direct `ROADMAP.md` creation. - -## Constraints - -- `gsd-db.ts` is already large and schema changes must follow the existing incremental migration chain. Do not rewrite schema bootstrap logic; add a `v7 → v8` step. -- Transition window is parser-dependent. `markdown-renderer.ts` explicitly states rendered markdown must round-trip through `parseRoadmap()` / `parsePlan()`. -- Existing query ordering is lexicographic by `id`, not sequence. S01 can add sequence columns now, but S04 owns proving all readers order by sequence. -- Tool registration currently uses `@sinclair/typebox` patterns in `bootstrap/db-tools.ts`; keep registration consistent with existing DB tools instead of adding a new registry path. - -## Common Pitfalls - -- **Partial ROADMAP rendering** — `renderRoadmapCheckboxes()` only patches an existing file. Reusing that pattern for S01 will leave DB as source of truth without a full markdown view, breaking parser-era callers. Generate the whole file. -- **Cache invalidation drift** — completion handlers explicitly clear parse and state caches. Missing `clearParseCache()` after milestone planning will create stale parser results during the transition window. -- **INSERT OR IGNORE where upsert is required** — `insertMilestone()` / `insertSlice()` currently ignore later field updates. The planning handler likely needs a real update/upsert path for milestone metadata instead of relying on these helpers unchanged. -- **Prompt migration without enforcement** — if prompts change before rogue detection covers ROADMAP/PLAN writes, noncompliant model output will silently create divergent state on disk. - -## Open Risks - -- The current `parseRoadmap()` surface does not expose all milestone sections S01 wants to store/render. The renderer can emit richer markdown than the parser reads, but importer/backfill for legacy files may be best-effort only until later slices expand parser/import logic. -- `gsd-db.ts` already duplicates some row/accessor sections and is drifting large; S01 should avoid broad refactors while changing schema because this slice is on the critical path. - -## Skills Discovered - -| Technology | Skill | Status | -|------------|-------|--------| -| GSD extension/tooling | `create-gsd-extension` | available | -| Investigation / root-cause discipline | `debug-like-expert` | available | -| Test generation / execution patterns | `test` | available | diff --git a/.gsd/milestones/M001/slices/S01/S01-SUMMARY.md b/.gsd/milestones/M001/slices/S01/S01-SUMMARY.md deleted file mode 100644 index 63e2f32a6..000000000 --- a/.gsd/milestones/M001/slices/S01/S01-SUMMARY.md +++ /dev/null @@ -1,131 +0,0 @@ ---- -id: S01 -parent: M001 -milestone: M001 -provides: - - Schema v8 planning storage on milestones, slices, and tasks, plus `replan_history` and `assessments` tables for later slices. - - `gsd_plan_milestone` tool registration and handler implementation as the reference planning-tool pattern. - - `renderRoadmapFromDb()` as the canonical roadmap regeneration path from DB state. - - Prompt contracts and rogue-write enforcement for milestone-era planning artifacts. - - Integrated regression coverage proving the S01 boundary works together under the repo’s actual test harness. -requires: - [] -affects: - - S02 - - S03 - - S04 - - S05 -key_files: - - src/resources/extensions/gsd/gsd-db.ts - - src/resources/extensions/gsd/markdown-renderer.ts - - src/resources/extensions/gsd/tools/plan-milestone.ts - - src/resources/extensions/gsd/bootstrap/db-tools.ts - - src/resources/extensions/gsd/auto-post-unit.ts - - src/resources/extensions/gsd/prompts/plan-milestone.md - - src/resources/extensions/gsd/tests/plan-milestone.test.ts - - src/resources/extensions/gsd/tests/markdown-renderer.test.ts - - src/resources/extensions/gsd/tests/prompt-contracts.test.ts - - src/resources/extensions/gsd/tests/rogue-file-detection.test.ts - - src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts -key_decisions: - - Use a thin DB-backed planning handler pattern: validate flat params, write in one transaction, render markdown from DB, then invalidate both state and parse caches. - - Treat planning prompts as tool-call orchestration surfaces and markdown templates as output-shaping guidance, not manual write targets. - - Detect rogue planning artifact writes by comparing disk artifacts against durable milestone/slice planning state in DB rather than inventing a separate completion status model. - - Verify cache invalidation through observable parse-visible state instead of monkey-patching imported ESM bindings. - - Use the repository’s resolver-based TypeScript harness as the authoritative proof path for these source tests. -patterns_established: - - Validate → transaction → render → invalidate is the standard planning-tool handler pattern for downstream slices. - - Render markdown from DB state after writes; do not mutate planning markdown directly as the source of truth. - - Tie rogue artifact detection to durable DB state instead of trusting prompt compliance. - - Use resolver-based TypeScript test execution for this repo’s source tests, and verify cache behavior through observable state rather than ESM export mutation. -observability_surfaces: - - `src/resources/extensions/gsd/tests/plan-milestone.test.ts` for handler validation, render failure behavior, idempotence, and cache invalidation proof. - - `src/resources/extensions/gsd/tests/markdown-renderer.test.ts` for full ROADMAP rendering, stale-render detection/repair, and dedicated `stderr warning|stale` diagnostics. - - `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` for prompt regressions that reintroduce direct file-write instructions. - - `src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` and `src/resources/extensions/gsd/auto-post-unit.ts` for enforcement of rogue ROADMAP.md / PLAN.md writes. - - SQLite milestone/slice rows and artifacts rendered by `renderRoadmapFromDb()` for direct inspection of persisted planning state. -drill_down_paths: - - .gsd/milestones/M001/slices/S01/tasks/T01-SUMMARY.md - - .gsd/milestones/M001/slices/S01/tasks/T02-SUMMARY.md - - .gsd/milestones/M001/slices/S01/tasks/T03-SUMMARY.md - - .gsd/milestones/M001/slices/S01/tasks/T04-SUMMARY.md -duration: "" -verification_result: passed -completed_at: 2026-03-23T15:47:31.051Z -blocker_discovered: false ---- - -# S01: Schema v8 + plan_milestone tool + ROADMAP renderer - -**Delivered schema v8 milestone-planning storage, the `gsd_plan_milestone` DB-backed write path, full ROADMAP rendering from DB, and prompt/enforcement coverage that blocks direct planning-file bypasses.** - -## What Happened - -S01 started with a broken intermediate state from early schema work and a stale assumption in the plan’s literal verification commands. The slice finished by establishing the first complete DB-backed planning path for milestones. Schema v8 support was added in `gsd-db.ts`, including new milestone/slice/task planning columns and the downstream `replan_history` and `assessments` tables required by later slices. `markdown-renderer.ts` gained a full `renderRoadmapFromDb()` path so ROADMAP.md can now be regenerated from DB state instead of only patching checkboxes. `tools/plan-milestone.ts` implemented the canonical milestone planning write flow: flat param validation, transactional writes for milestone and slice planning state, roadmap rendering, and explicit `invalidateStateCache()` plus `clearParseCache()` after successful render. `bootstrap/db-tools.ts` registered the canonical tool and alias so prompts can target the DB-backed path. The planning prompts were then rewritten to stop instructing direct roadmap/plan writes, while `auto-post-unit.ts` was extended to flag rogue ROADMAP.md and PLAN.md writes that bypass the new DB state. Regression coverage was expanded across renderer behavior, migration/backfill behavior, prompt contracts, rogue detection, and the tool handler itself. During closeout, the invalid ESM monkey-patching in cache tests was replaced with observable integration assertions that prove the same contract truthfully by checking parse-visible roadmap state before and after handler execution. The slice now provides the milestone-planning foundation the rest of M001 depends on: schema storage, a real planning tool, a full roadmap renderer, prompt enforcement, and durable regression coverage. - -## Verification - -Ran the full slice-level proof under the repository’s actual TypeScript resolver harness. `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/prompt-contracts.test.ts src/resources/extensions/gsd/tests/rogue-file-detection.test.ts src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts` passed, covering the integrated S01 boundary. Separately ran `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts --test-name-pattern="stderr warning|stale"`, which passed and confirmed the renderer’s observability/failure-path diagnostics. Confirmed the documented observability surfaces now exist in all four task summaries by adding missing `observability_surfaces` frontmatter and `## Diagnostics` sections. Updated requirements based on evidence: R001, R002, R007, R013, R015, and R018 are now validated. - -## Requirements Advanced - -- R001 — Added schema v8 planning columns/tables and migration logic that later slices will populate further. -- R002 — Implemented and registered the `gsd_plan_milestone` tool with flat validation, transactional writes, rendering, and cache invalidation. -- R007 — Added full ROADMAP generation from DB state through `renderRoadmapFromDb()`. -- R013 — Rewrote milestone and adjacent planning prompts to use DB-backed tools instead of manual file writes. -- R015 — Established and tested dual cache invalidation as part of the planning handler pattern. -- R018 — Extended rogue planning artifact detection to direct ROADMAP.md and PLAN.md writes. - -## Requirements Validated - -- R001 — `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/prompt-contracts.test.ts src/resources/extensions/gsd/tests/rogue-file-detection.test.ts src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts` passed, covering schema v8 migration/backfill and new planning storage. -- R002 — `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts` passed, proving flat input validation, transactional writes, roadmap render, and idempotent reruns. -- R007 — `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts --test-name-pattern="stderr warning|stale"` passed, alongside the full renderer suite, proving roadmap generation and diagnostics from DB state. -- R013 — `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` passed, proving planning prompts now direct tool usage instead of manual writes. -- R015 — `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts` passed with observable assertions proving parse-visible roadmap state is only updated after successful render and cache clearing. -- R018 — `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` passed, proving direct ROADMAP.md and PLAN.md writes are flagged when DB planning state is absent. - -## New Requirements Surfaced - -None. - -## Requirements Invalidated or Re-scoped - -None. - -## Deviations - -Task execution initially encountered repo-local TypeScript test harness mismatches and an intermediate broken import state in `gsd-db.ts`; the slice closed by adapting verification to the repository’s resolver-based harness and replacing brittle cache tests with observable integration assertions. No remaining scope deviation in the finished slice. - -## Known Limitations - -S01 does not yet provide DB-backed slice/task planning tools, replan/reassess enforcement, caller migration away from markdown parsers, or flag-file migration. Bare `node --test` remains unreliable for some source `.ts` tests in this repo; the resolver-based harness is still required for truthful verification. - -## Follow-ups - -S02 should build `gsd_plan_slice` and `gsd_plan_task` on top of the validate → transaction → render → invalidate pattern established here. S03 should reuse the new roadmap renderer and schema tables for reassessment/replan history writes. S04 still needs the DB↔rendered cross-validation layer and hot-path caller migration that retire markdown parsing from the dispatch loop. - -## Files Created/Modified - -- `src/resources/extensions/gsd/gsd-db.ts` — Added schema v8 migration support, planning storage columns/tables, and milestone/slice planning query and upsert helpers. -- `src/resources/extensions/gsd/markdown-renderer.ts` — Added full ROADMAP rendering from DB state and kept renderer diagnostics/stale detection exercised by tests. -- `src/resources/extensions/gsd/tools/plan-milestone.ts` — Implemented the DB-backed milestone planning tool handler with validation, transactional writes, rendering, and cache invalidation. -- `src/resources/extensions/gsd/bootstrap/db-tools.ts` — Registered `gsd_plan_milestone` plus alias metadata in the DB tool bootstrap. -- `src/resources/extensions/gsd/md-importer.ts` — Extended hierarchy migration/import coverage to backfill new planning fields best-effort from existing roadmap content. -- `src/resources/extensions/gsd/auto-post-unit.ts` — Extended rogue write detection to catch direct ROADMAP.md and PLAN.md planning bypasses. -- `src/resources/extensions/gsd/prompts/plan-milestone.md` — Rewrote milestone and adjacent planning prompts to use tool calls instead of manual roadmap/plan writes. -- `src/resources/extensions/gsd/prompts/guided-plan-milestone.md` — Rewrote guided milestone planning prompt to direct `gsd_plan_milestone` usage and forbid manual roadmap writes. -- `src/resources/extensions/gsd/prompts/plan-slice.md` — Shifted slice planning prompt framing toward DB-backed planning state instead of direct plan files as source of truth. -- `src/resources/extensions/gsd/prompts/replan-slice.md` — Updated replan prompt to preserve the DB-backed planning path and completed-task structural expectations. -- `src/resources/extensions/gsd/prompts/reassess-roadmap.md` — Updated reassess prompt to forbid roadmap-only edits when planning tools exist. -- `src/resources/extensions/gsd/tests/markdown-renderer.test.ts` — Added roadmap renderer coverage for DB-backed milestone planning, artifact persistence, and stale-render diagnostics. -- `src/resources/extensions/gsd/tests/plan-milestone.test.ts` — Replaced unrelated coverage with focused milestone-planning handler tests, including observable cache invalidation behavior. -- `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` — Added prompt contract assertions proving planning prompts reference tools and prohibit manual artifact writes. -- `src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` — Added rogue roadmap/plan detection regression cases tied to DB planning-state presence. -- `src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts` — Extended migration tests to cover v8 planning backfill behavior and schema upgrade paths. -- `.gsd/milestones/M001/slices/S01/tasks/T01-SUMMARY.md` — Filled missing observability metadata and diagnostics sections in all task summaries for downstream debugging. -- `.gsd/milestones/M001/slices/S01/tasks/T02-SUMMARY.md` — Filled missing observability metadata and diagnostics sections in all task summaries for downstream debugging. -- `.gsd/milestones/M001/slices/S01/tasks/T03-SUMMARY.md` — Filled missing observability metadata and diagnostics sections in all task summaries for downstream debugging. -- `.gsd/milestones/M001/slices/S01/tasks/T04-SUMMARY.md` — Filled missing observability metadata and diagnostics sections in all task summaries for downstream debugging. -- `.gsd/PROJECT.md` — Updated project state to reflect that milestone planning is now DB-backed after S01. -- `.gsd/KNOWLEDGE.md` — Recorded durable repo-specific lessons about the resolver harness and ESM-safe cache testing. diff --git a/.gsd/milestones/M001/slices/S01/S01-UAT.md b/.gsd/milestones/M001/slices/S01/S01-UAT.md deleted file mode 100644 index c36c4a2ed..000000000 --- a/.gsd/milestones/M001/slices/S01/S01-UAT.md +++ /dev/null @@ -1,101 +0,0 @@ -# S01: Schema v8 + plan_milestone tool + ROADMAP renderer — UAT - -**Milestone:** M001 -**Written:** 2026-03-23T15:47:31.051Z - -# S01: Schema v8 + plan_milestone tool + ROADMAP renderer — UAT - -**Milestone:** M001 -**Written:** 2026-03-23 - -## UAT Type - -- UAT mode: artifact-driven -- Why this mode is sufficient: S01 delivers backend planning state capture, markdown rendering, and enforcement logic. The authoritative proof is the DB state, rendered artifacts, and regression tests rather than a human-facing UI. - -## Preconditions - -- Working directory is the repo root. -- Node can run the repository’s TypeScript tests with the resolver harness. -- No external services or secrets are required. - -## Smoke Test - -Run: - -`node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts` - -Expected: all handler tests pass, proving a milestone planning payload can be validated, written to DB, rendered to ROADMAP.md, and rerun idempotently. - -## Test Cases - -### 1. Milestone planning writes DB state and renders roadmap - -1. Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts`. -2. Confirm the test `handlePlanMilestone writes milestone and slice planning state and renders roadmap` passes. -3. **Expected:** milestone planning fields and slice rows are persisted, ROADMAP.md is rendered from DB state, and the handler returns success. - -### 2. Invalid milestone planning payloads are rejected structurally - -1. Run the same `plan-milestone.test.ts` suite. -2. Confirm the test `handlePlanMilestone rejects invalid payloads` passes. -3. **Expected:** malformed flat tool params are rejected before any persisted state is accepted as valid planning output. - -### 3. Schema v8 migration and roadmap backfill work on pre-existing data - -1. Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts src/resources/extensions/gsd/tests/markdown-renderer.test.ts`. -2. Confirm the migration scenarios and renderer scenarios pass. -3. **Expected:** a v7-style hierarchy upgrades to schema v8, planning-oriented fields/tables exist, and roadmap rendering/backfill behavior remains parser-compatible. - -### 4. Planning prompts route through tools instead of manual roadmap/plan writes - -1. Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts`. -2. Confirm the milestone/slice/replan/reassess prompt contract tests pass. -3. **Expected:** prompts reference `gsd_plan_milestone` and related DB-backed planning behavior, and explicit manual ROADMAP.md / PLAN.md write instructions are absent or forbidden. - -### 5. Rogue planning artifact writes are detected - -1. Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/rogue-file-detection.test.ts`. -2. Confirm the roadmap and slice-plan rogue detection cases pass. -3. **Expected:** direct ROADMAP.md / PLAN.md files without corresponding DB planning state are flagged as rogue, while DB-backed rendered artifacts are not flagged. - -## Edge Cases - -### Renderer diagnostics on stale or missing planning output - -1. Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts --test-name-pattern="stderr warning|stale"`. -2. **Expected:** the renderer emits the expected stale/missing-content diagnostics without masking failures. - -### Render failure does not leak stale parse-visible roadmap state - -1. Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts`. -2. Inspect the passing test `handlePlanMilestone surfaces render failures and does not clear parse-visible state on failure`. -3. **Expected:** a render failure does not falsely advance parse-visible roadmap state, and a later successful run does. - -## Failure Signals - -- `ERR_MODULE_NOT_FOUND` under bare `node --test` without the resolver import indicates a harness mismatch; use the resolver-based command before diagnosing product regressions. -- `plan-milestone.test.ts` failures indicate broken validation, transactional writes, rendering, or cache invalidation behavior. -- `markdown-renderer.test.ts` stale/diagnostic failures indicate roadmap rendering or artifact synchronization regressions. -- `rogue-file-detection.test.ts` failures indicate planning bypasses may no longer be surfaced. - -## Requirements Proved By This UAT - -- R001 — schema v8 migration and planning storage exist and pass migration coverage. -- R002 — `gsd_plan_milestone` validates, writes DB state, renders ROADMAP.md, and reruns idempotently. -- R007 — full ROADMAP.md rendering from DB and renderer diagnostics are proven. -- R013 — planning prompts route to tools instead of manual planning-file writes. -- R015 — planning handler cache invalidation is proven through observable parse-visible state changes. -- R018 — rogue planning artifact writes are detected against DB state. - -## Not Proven By This UAT - -- R003/R004 — slice/task planning tools are not part of S01. -- R005/R006 — replan/reassess structural enforcement lands in S03. -- R009/R010/R012/R016/R017/R019 — hot-path migration, broader caller migration, parser retirement, sequence-aware ordering, pre-M002 recovery migration, and task-plan runtime contract work remain for later slices. - -## Notes for Tester - -- Use the resolver-based TypeScript harness for authoritative results in this repo. -- If a bare `node --test` command fails while the resolver-based command passes, treat that as known harness behavior unless a resolver-based run also fails. -- The proof here is intentionally regression-test heavy because S01 changes storage, rendering, prompts, and enforcement rather than a visible UI flow. diff --git a/.gsd/milestones/M001/slices/S01/tasks/T01-PLAN.md b/.gsd/milestones/M001/slices/S01/tasks/T01-PLAN.md deleted file mode 100644 index e4c3a9751..000000000 --- a/.gsd/milestones/M001/slices/S01/tasks/T01-PLAN.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -estimated_steps: 5 -estimated_files: 5 -skills_used: - - create-gsd-extension - - debug-like-expert - - test - - best-practices ---- - -# T01: Add schema v8 planning storage and roadmap rendering - -**Slice:** S01 — Schema v8 + plan_milestone tool + ROADMAP renderer -**Milestone:** M001 - -## Description - -Add the schema and renderer foundation S01 depends on. Extend `gsd-db.ts` from schema v7 to v8 with milestone/slice/task planning columns plus the new planning tables, add the read/write helpers the milestone-planning handler will call, implement a full ROADMAP renderer that writes parser-compatible markdown from DB state, and make sure legacy markdown import can backfill milestone planning data well enough for the transition window. - -## Steps - -1. Add the v7→v8 migration in `src/resources/extensions/gsd/gsd-db.ts`, including milestone, slice, and task planning columns plus `replan_history` and `assessments` tables. -2. Add or extend the typed milestone-planning query/upsert helpers in `src/resources/extensions/gsd/gsd-db.ts` so later handlers can write and read roadmap planning data without parsing markdown. -3. Implement `renderRoadmapFromDb()` in `src/resources/extensions/gsd/markdown-renderer.ts` to generate the full roadmap file, persist the artifact content, and keep the output compatible with `parseRoadmap()` callers. -4. Update `src/resources/extensions/gsd/md-importer.ts` so roadmap migration can best-effort populate the new milestone planning fields from existing markdown. -5. Extend renderer and migration tests to prove schema upgrade, roadmap round-trip fidelity, and importer backfill behavior. - -## Must-Haves - -- [ ] Existing DBs upgrade cleanly from schema v7 to v8 without losing existing milestone, slice, task, or artifact data. -- [ ] `renderRoadmapFromDb()` generates a complete roadmap with the sections S01 owns, not just checkbox patches. -- [ ] Rendered roadmap output still parses through the existing parser contract used during the transition window. -- [ ] Import/migration logic backfills the new milestone planning columns best-effort from legacy roadmap markdown. - -## Verification - -- `node --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts` -- Confirm the new tests cover v7→v8 migration and full ROADMAP generation from DB state. - -## Observability Impact - -- Signals added/changed: schema version bump, milestone planning rows/columns, and artifact writes for generated roadmap content. -- How a future agent inspects this: run `node --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts` and inspect the roadmap artifact rows in `src/resources/extensions/gsd/gsd-db.ts` helpers. -- Failure state exposed: migration failure, missing rendered sections, parser round-trip drift, or importer backfill gaps become explicit test failures. - -## Inputs - -- `src/resources/extensions/gsd/gsd-db.ts` — existing schema v7 migrations and accessor patterns to extend -- `src/resources/extensions/gsd/markdown-renderer.ts` — current checkbox-only roadmap renderer to replace with full generation -- `src/resources/extensions/gsd/md-importer.ts` — legacy markdown migration path that must tolerate v8 -- `src/resources/extensions/gsd/tests/markdown-renderer.test.ts` — current renderer test harness and round-trip expectations -- `src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts` — migration coverage to extend for v8 backfill - -## Expected Output - -- `src/resources/extensions/gsd/gsd-db.ts` — schema v8 migration plus milestone planning accessors -- `src/resources/extensions/gsd/markdown-renderer.ts` — full `renderRoadmapFromDb()` implementation and artifact persistence updates -- `src/resources/extensions/gsd/md-importer.ts` — v8-aware roadmap import/backfill behavior -- `src/resources/extensions/gsd/tests/markdown-renderer.test.ts` — regression tests for full roadmap generation and round-trip fidelity -- `src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts` — migration tests covering v7→v8 upgrade and best-effort planning-field import diff --git a/.gsd/milestones/M001/slices/S01/tasks/T01-SUMMARY.md b/.gsd/milestones/M001/slices/S01/tasks/T01-SUMMARY.md deleted file mode 100644 index 085694ddc..000000000 --- a/.gsd/milestones/M001/slices/S01/tasks/T01-SUMMARY.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -id: T01 -parent: S01 -milestone: M001 -key_files: - - .gsd/milestones/M001/slices/S01/S01-PLAN.md - - src/resources/extensions/gsd/gsd-db.ts -key_decisions: - - Applied the required pre-flight diagnostic verification addition to the slice plan before implementation work. - - Stopped execution at the first concrete failing verification signal after the partial DB rewrite instead of attempting speculative recovery under low context. - - Captured the exact root failure for resume: direct test execution now fails because `src/resources/extensions/gsd/gsd-db.ts` imports `./errors.js`, which is not resolvable in the current TypeScript test runtime. -duration: "" -verification_result: mixed -completed_at: 2026-03-23T15:25:30.294Z -blocker_discovered: false -observability_surfaces: - - src/resources/extensions/gsd/tests/markdown-renderer.test.ts - - src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts - - src/resources/extensions/gsd/gsd-db.ts schema v8 migration paths and milestone/slice rows - - ERR_MODULE_NOT_FOUND output when direct node --test bypasses the repo TS resolver ---- - -# T01: Partially advanced schema v8 groundwork and documented the broken intermediate state for T01 resume - -**Partially advanced schema v8 groundwork and documented the broken intermediate state for T01 resume** - -## What Happened - -I followed the execution contract in order until the context budget warning forced wrap-up. First I loaded the required skills, read the slice plan, task plan, and the target implementation files, and verified the current local reality: the codebase was still on schema v7, roadmap rendering only patched checkboxes, and importer migration only backfilled basic hierarchy state. I then fixed the mandatory pre-flight observability gap in the slice plan by adding a targeted verification entry for the inspectable failure-state path in `markdown-renderer.test.ts`. After that I traced the actual roadmap parser contract in `files.ts`, read the roadmap template and migration writer to avoid inventing a new markdown shape, and started the schema work in `src/resources/extensions/gsd/gsd-db.ts`. That partial rewrite introduced schema v8 structures and planning-oriented fields/helpers, but because the context budget warning arrived mid-unit I did not have enough budget left to safely finish the downstream renderer/importer/test changes or to recover from a runtime compatibility issue discovered during verification. I stopped immediately once the smallest concrete verification run showed the local failure mode, rather than making more unverified edits. - -## Verification - -I ran the smallest targeted verification commands for this task after the partial `gsd-db.ts` rewrite. Both targeted test commands failed immediately before exercising T01 behavior because Node could not resolve `src/resources/extensions/gsd/errors.js` from the rewritten `gsd-db.ts`. That gives a precise resume point: fix the rewritten DB module’s runtime-compatible imports/specifiers first, then continue implementing the renderer/importer/test updates and rerun the slice checks. The slice-plan pre-flight observability fix was applied successfully. - -## Verification Evidence - -| # | Command | Exit Code | Verdict | Duration | -|---|---------|-----------|---------|----------| -| 1 | `node --test src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts` | 1 | ❌ fail | 102ms | -| 2 | `node --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts` | 1 | ❌ fail | 111ms | - - -## Deviations - -Stopped early due to context budget warning before completing the planned renderer/importer/test updates. I fixed the pre-flight observability gap in `.gsd/milestones/M001/slices/S01/S01-PLAN.md` and partially rewrote `src/resources/extensions/gsd/gsd-db.ts` toward schema v8/planning helpers, but I did not finish `src/resources/extensions/gsd/markdown-renderer.ts`, `src/resources/extensions/gsd/md-importer.ts`, or the target tests. The attempted `markdown-renderer.ts` full rewrite was interrupted and did not land. - -## Known Issues - -`src/resources/extensions/gsd/gsd-db.ts` is currently in a broken intermediate state. Running the targeted tests fails immediately with `ERR_MODULE_NOT_FOUND` for `src/resources/extensions/gsd/errors.js` imported from `gsd-db.ts`. `src/resources/extensions/gsd/markdown-renderer.ts`, `src/resources/extensions/gsd/md-importer.ts`, `src/resources/extensions/gsd/tests/markdown-renderer.test.ts`, and `src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts` still need the actual T01 implementation work. Resume should start by restoring/fixing `gsd-db.ts` imports/runtime compatibility, then continue the v8 schema + roadmap renderer work. - -## Diagnostics - -- Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts` to verify the schema-v8 migration and roadmap-renderer path under the repository's actual TypeScript harness. -- Inspect `src/resources/extensions/gsd/gsd-db.ts` for schema version `8`, milestone planning upserts, and milestone/slice planning read helpers when checking whether the DB-backed write path exists. -- If a bare `node --test ...` invocation fails before reaching task logic, compare the error against the recorded `ERR_MODULE_NOT_FOUND` symptom first; that indicates harness mismatch rather than a regression in the planning implementation. - -## Files Created/Modified - -- `.gsd/milestones/M001/slices/S01/S01-PLAN.md` -- `src/resources/extensions/gsd/gsd-db.ts` diff --git a/.gsd/milestones/M001/slices/S01/tasks/T01-VERIFY.json b/.gsd/milestones/M001/slices/S01/tasks/T01-VERIFY.json deleted file mode 100644 index b09e9cd2d..000000000 --- a/.gsd/milestones/M001/slices/S01/tasks/T01-VERIFY.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "schemaVersion": 1, - "taskId": "T01", - "unitId": "M001/S01/T01", - "timestamp": 1774279543193, - "passed": false, - "discoverySource": "package-json", - "checks": [ - { - "command": "npm run test", - "exitCode": 1, - "durationMs": 39682, - "verdict": "fail" - } - ], - "retryAttempt": 1, - "maxRetries": 2 -} diff --git a/.gsd/milestones/M001/slices/S01/tasks/T02-PLAN.md b/.gsd/milestones/M001/slices/S01/tasks/T02-PLAN.md deleted file mode 100644 index 8a1d2f128..000000000 --- a/.gsd/milestones/M001/slices/S01/tasks/T02-PLAN.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -estimated_steps: 5 -estimated_files: 5 -skills_used: - - create-gsd-extension - - debug-like-expert - - test - - best-practices ---- - -# T02: Wire gsd_plan_milestone through the DB-backed tool path - -**Slice:** S01 — Schema v8 + plan_milestone tool + ROADMAP renderer -**Milestone:** M001 - -## Description - -Implement the actual milestone-planning tool path using the established DB-backed handler pattern from the completion tools. The result should be a flat-parameter tool that validates input, writes milestone and slice planning state transactionally, renders the roadmap from DB, stores the artifact, and clears parser/state caches so transition-window callers do not see stale content. - -## Steps - -1. Create `src/resources/extensions/gsd/tools/plan-milestone.ts` using the same validate → transaction → render → invalidate structure already used by the completion handlers. -2. Add milestone and slice planning upsert calls inside the transaction using the T01 schema/accessor work. -3. Render the roadmap outside the transaction via `renderRoadmapFromDb()` and treat render failure as a surfaced handler error. -4. Ensure successful execution invalidates both state and parse caches after render to satisfy R015. -5. Register `gsd_plan_milestone` and its alias in `src/resources/extensions/gsd/bootstrap/db-tools.ts`, then add focused handler tests. - -## Must-Haves - -- [ ] Tool parameters stay flat and structurally validate the milestone planning payload S01 owns. -- [ ] Successful calls write milestone and slice planning state in one transaction and render the roadmap from DB. -- [ ] Cache invalidation includes both `invalidateStateCache()` and `clearParseCache()` after successful render. -- [ ] Invalid input, render failure, and rerun/idempotency behavior are covered by tests. - -## Verification - -- `node --test src/resources/extensions/gsd/tests/plan-milestone.test.ts` -- Confirm the test suite covers valid write path, invalid payload rejection, render failure handling, and cache invalidation expectations. - -## Observability Impact - -- Signals added/changed: structured plan-milestone tool results and handler error surfaces for validation or render failures. -- How a future agent inspects this: run `node --test src/resources/extensions/gsd/tests/plan-milestone.test.ts` and inspect the registered tool metadata in `src/resources/extensions/gsd/bootstrap/db-tools.ts`. -- Failure state exposed: invalid payloads, DB write failures, render failures, or stale-cache regressions become explicit handler/test failures. - -## Inputs - -- `src/resources/extensions/gsd/gsd-db.ts` — milestone planning DB helpers added in T01 -- `src/resources/extensions/gsd/markdown-renderer.ts` — roadmap render path added in T01 -- `src/resources/extensions/gsd/tools/complete-task.ts` — reference handler pattern for DB-backed post-transaction rendering -- `src/resources/extensions/gsd/tools/complete-slice.ts` — reference handler pattern for parent-child status writes and roadmap rendering -- `src/resources/extensions/gsd/bootstrap/db-tools.ts` — tool registration seam for DB-backed tools - -## Expected Output - -- `src/resources/extensions/gsd/tools/plan-milestone.ts` — new milestone-planning handler -- `src/resources/extensions/gsd/bootstrap/db-tools.ts` — registered `gsd_plan_milestone` tool and alias -- `src/resources/extensions/gsd/tests/plan-milestone.test.ts` — focused handler/tool regression coverage -- `src/resources/extensions/gsd/gsd-db.ts` — any small support additions needed by the handler -- `src/resources/extensions/gsd/markdown-renderer.ts` — any handler-driven render support adjustments diff --git a/.gsd/milestones/M001/slices/S01/tasks/T02-SUMMARY.md b/.gsd/milestones/M001/slices/S01/tasks/T02-SUMMARY.md deleted file mode 100644 index ba60c709a..000000000 --- a/.gsd/milestones/M001/slices/S01/tasks/T02-SUMMARY.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -id: T02 -parent: S01 -milestone: M001 -key_files: - - src/resources/extensions/gsd/tools/plan-milestone.ts - - src/resources/extensions/gsd/bootstrap/db-tools.ts - - src/resources/extensions/gsd/markdown-renderer.ts - - src/resources/extensions/gsd/tests/plan-milestone.test.ts -key_decisions: - - Implemented `gsd_plan_milestone` using the same validate → transaction → render → invalidate structure as the completion handlers so downstream planning tools can follow one DB-backed pattern. - - Added a minimal `renderRoadmapFromDb()` renderer to generate ROADMAP.md directly from milestone and slice rows instead of only patching existing files. - - Adapted verification to the repository’s actual TypeScript test harness (`resolve-ts.mjs` + `--experimental-strip-types`) because the literal `node --test` plan command does not run this source tree. -duration: "" -verification_result: mixed -completed_at: 2026-03-23T15:31:33.286Z -blocker_discovered: false -observability_surfaces: - - src/resources/extensions/gsd/tests/plan-milestone.test.ts - - src/resources/extensions/gsd/tools/plan-milestone.ts handler return/errors - - src/resources/extensions/gsd/markdown-renderer.ts rendered ROADMAP artifact output - - cache visibility through parseRoadmap()/clearParseCache() behavior in tests ---- - -# T02: Added the DB-backed gsd_plan_milestone handler, tool registration, roadmap rendering path, and focused tests, then stopped at the first concrete repo-local test harness failure. - -**Added the DB-backed gsd_plan_milestone handler, tool registration, roadmap rendering path, and focused tests, then stopped at the first concrete repo-local test harness failure.** - -## What Happened - -I executed the T02 contract against local reality instead of the stale planner snapshot. First I verified the slice-plan pre-flight observability fix was already present and confirmed T01’s previously reported import/runtime issue still affected direct `node --test` runs. I then read the completion handlers, DB accessors, renderer, tool bootstrap, and the existing `plan-milestone.test.ts` file. That test file was unrelated dead coverage for `inlinePriorMilestoneSummary`, so I replaced it with focused `plan-milestone` handler coverage matching the task contract. On the implementation side I created `src/resources/extensions/gsd/tools/plan-milestone.ts` with a validate → transaction → render → invalidate flow. The handler performs flat-parameter validation, inserts/upserts milestone planning state plus slice planning state transactionally, renders roadmap output from DB via a new `renderRoadmapFromDb()` function in `src/resources/extensions/gsd/markdown-renderer.ts`, and then calls both `invalidateStateCache()` and `clearParseCache()` after a successful render. I also registered the canonical `gsd_plan_milestone` tool plus `gsd_milestone_plan` alias in `src/resources/extensions/gsd/bootstrap/db-tools.ts` with flat TypeBox parameters and the same execution style used by the completion tools. For verification, I first ran the literal task-plan command and confirmed it still fails before reaching the new code because this repo’s TypeScript tests require the `resolve-ts.mjs` loader. I then adapted to the project’s actual test harness and reran the new suite with `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts`. That reached the real handler tests: three passed, and two failed immediately because the tests attempted to monkey-patch read-only ESM exports (`invalidateStateCache` / `clearParseCache`) to count calls. Per the wrap-up instruction and debugging discipline, I stopped at that first concrete, understood failure instead of continuing into another test rewrite cycle. The next resume point is narrow: update the two cache-invalidation assertions in `src/resources/extensions/gsd/tests/plan-milestone.test.ts` to verify cache-clearing behavior without assigning to ESM exports, rerun the adapted task-level command, then run the slice-level checks relevant to T02. - -## Verification - -Verification reached the real T02 handler code only when I used the repo’s existing TypeScript test harness (`--import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types`). The stale literal `node --test ...` command still fails at module resolution before exercising the new code because the source tree uses `.js` specifiers resolved by that loader. Under the adapted harness, the new handler suite passed the valid write path, invalid payload rejection, and idempotent rerun checks. It failed on the two cache-related tests because they used an invalid testing approach: assigning to imported ESM bindings. That leaves the production implementation in place and the remaining work constrained to fixing those assertions, then rerunning the adapted command. - -## Verification Evidence - -| # | Command | Exit Code | Verdict | Duration | -|---|---------|-----------|---------|----------| -| 1 | `node --test src/resources/extensions/gsd/tests/plan-milestone.test.ts` | 1 | ❌ fail | 104ms | -| 2 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts` | 1 | ❌ fail | 161ms | - - -## Deviations - -Used the repository’s actual TypeScript test harness (`node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test ...`) instead of the task plan’s literal `node --test ...` command because the local repo cannot run these source `.ts` tests without the resolver. Replaced the pre-existing unrelated `plan-milestone.test.ts` contents with the focused handler tests required by T02. Stopped before rewriting the two failing cache tests due to the context-budget wrap-up instruction. - -## Known Issues - -`src/resources/extensions/gsd/tests/plan-milestone.test.ts` still contains two failing tests that try to assign to read-only ESM exports (`invalidateStateCache` and `clearParseCache`). The correct next step is to verify cache invalidation via observable behavior or another non-mutation seam, then rerun `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts`. Also note that the task-plan verification command is stale for this repo: direct `node --test` still fails at `ERR_MODULE_NOT_FOUND` on `.js` sibling specifiers unless the resolver import is used. - -## Diagnostics - -- Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts` to exercise the authoritative handler proof path. -- Inspect `src/resources/extensions/gsd/tools/plan-milestone.ts` and `src/resources/extensions/gsd/bootstrap/db-tools.ts` to confirm the validate → transaction → render → invalidate pattern and canonical/alias registration remain wired. -- If cache-related regressions are suspected, verify them through parse-visible roadmap behavior in `src/resources/extensions/gsd/tests/plan-milestone.test.ts` rather than trying to monkey-patch ESM exports. - -## Files Created/Modified - -- `src/resources/extensions/gsd/tools/plan-milestone.ts` -- `src/resources/extensions/gsd/bootstrap/db-tools.ts` -- `src/resources/extensions/gsd/markdown-renderer.ts` -- `src/resources/extensions/gsd/tests/plan-milestone.test.ts` diff --git a/.gsd/milestones/M001/slices/S01/tasks/T02-VERIFY.json b/.gsd/milestones/M001/slices/S01/tasks/T02-VERIFY.json deleted file mode 100644 index f6f219b60..000000000 --- a/.gsd/milestones/M001/slices/S01/tasks/T02-VERIFY.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "schemaVersion": 1, - "taskId": "T02", - "unitId": "M001/S01/T02", - "timestamp": 1774279901597, - "passed": false, - "discoverySource": "package-json", - "checks": [ - { - "command": "npm run test", - "exitCode": 1, - "durationMs": 39525, - "verdict": "fail" - } - ], - "retryAttempt": 1, - "maxRetries": 2 -} diff --git a/.gsd/milestones/M001/slices/S01/tasks/T03-PLAN.md b/.gsd/milestones/M001/slices/S01/tasks/T03-PLAN.md deleted file mode 100644 index da7b7104f..000000000 --- a/.gsd/milestones/M001/slices/S01/tasks/T03-PLAN.md +++ /dev/null @@ -1,65 +0,0 @@ ---- -estimated_steps: 4 -estimated_files: 8 -skills_used: - - create-gsd-extension - - debug-like-expert - - test - - best-practices ---- - -# T03: Migrate planning prompts and enforce rogue-write detection - -**Slice:** S01 — Schema v8 + plan_milestone tool + ROADMAP renderer -**Milestone:** M001 - -## Description - -Switch the planning prompts from direct markdown-writing instructions to DB tool usage, then extend the existing rogue-file safety net so roadmap or plan files written directly to disk are detected as prompt contract violations. This closes the loop between tool availability and LLM compliance. - -## Steps - -1. Update the planning prompts to instruct the model to call planning tools instead of writing roadmap/plan files directly, while preserving the existing context variables and planning quality constraints. -2. Extend `detectRogueFileWrites()` in `src/resources/extensions/gsd/auto-post-unit.ts` so plan-milestone / planning flows can flag direct `ROADMAP.md` and `PLAN.md` writes without matching DB state. -3. Add or update prompt contract tests proving the planning prompts reference the tool path and no longer contain direct file-write instructions. -4. Add rogue-detection tests that exercise direct roadmap/plan writes and verify those paths are surfaced immediately. - -## Must-Haves - -- [ ] `plan-milestone` and `guided-plan-milestone` prompts point at the DB tool path instead of direct roadmap writes. -- [ ] `plan-slice`, `replan-slice`, and `reassess-roadmap` prompts are updated consistently for the new planning-tool era, even if their handlers arrive in later slices. -- [ ] Rogue detection flags direct roadmap/plan writes that bypass DB state. -- [ ] Tests fail if prompt text regresses back to manual file-writing instructions. - -## Verification - -- `node --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` -- Confirm the prompt contract tests specifically assert planning-tool references and absence of manual roadmap/plan write instructions. - -## Observability Impact - -- Signals added/changed: prompt-contract failures and rogue-write diagnostics for planning artifacts. -- How a future agent inspects this: run `node --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` and inspect `detectRogueFileWrites()` behavior. -- Failure state exposed: prompt regressions or direct roadmap/plan bypasses surface as explicit test failures and rogue-file diagnostics. - -## Inputs - -- `src/resources/extensions/gsd/prompts/plan-milestone.md` — milestone planning prompt to migrate -- `src/resources/extensions/gsd/prompts/guided-plan-milestone.md` — guided milestone planning prompt to migrate -- `src/resources/extensions/gsd/prompts/plan-slice.md` — adjacent planning prompt that must stay consistent with the tool path -- `src/resources/extensions/gsd/prompts/replan-slice.md` — adjacent planning prompt that must stop implying direct file edits -- `src/resources/extensions/gsd/prompts/reassess-roadmap.md` — adjacent planning prompt that must stay aligned with roadmap rendering rules -- `src/resources/extensions/gsd/auto-post-unit.ts` — existing rogue-write detection logic to extend -- `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` — contract-test harness for prompt migration -- `src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` — regression coverage for rogue writes - -## Expected Output - -- `src/resources/extensions/gsd/prompts/plan-milestone.md` — tool-driven milestone planning instructions -- `src/resources/extensions/gsd/prompts/guided-plan-milestone.md` — tool-driven guided milestone planning instructions -- `src/resources/extensions/gsd/prompts/plan-slice.md` — updated planning-tool language aligned with the new capture model -- `src/resources/extensions/gsd/prompts/replan-slice.md` — updated planning-tool language aligned with the new capture model -- `src/resources/extensions/gsd/prompts/reassess-roadmap.md` — updated planning-tool language aligned with the new capture model -- `src/resources/extensions/gsd/auto-post-unit.ts` — roadmap/plan rogue-write detection -- `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` — assertions for planning-tool prompt migration -- `src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` — rogue detection coverage for roadmap/plan artifacts diff --git a/.gsd/milestones/M001/slices/S01/tasks/T03-SUMMARY.md b/.gsd/milestones/M001/slices/S01/tasks/T03-SUMMARY.md deleted file mode 100644 index 4a2394d94..000000000 --- a/.gsd/milestones/M001/slices/S01/tasks/T03-SUMMARY.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -id: T03 -parent: S01 -milestone: M001 -key_files: - - src/resources/extensions/gsd/prompts/plan-milestone.md - - src/resources/extensions/gsd/prompts/guided-plan-milestone.md - - src/resources/extensions/gsd/prompts/plan-slice.md - - src/resources/extensions/gsd/prompts/replan-slice.md - - src/resources/extensions/gsd/prompts/reassess-roadmap.md - - src/resources/extensions/gsd/auto-post-unit.ts - - src/resources/extensions/gsd/tests/prompt-contracts.test.ts - - src/resources/extensions/gsd/tests/rogue-file-detection.test.ts -key_decisions: - - Treat `gsd_plan_milestone` and future DB-backed planning tools as the planning source of truth in prompts, while preserving markdown templates only as output-shaping guidance rather than manual write instructions. - - Extend rogue-file detection by checking for planning-state presence in milestone and slice DB rows instead of inventing a separate planning completion status model just for enforcement. - - Keep verification honest by recording both the passing repo-local TS harness command and the still-failing bare `node --test` rogue-detection command, since the latter reflects an existing test-runtime mismatch rather than a T03 implementation bug. -duration: "" -verification_result: mixed -completed_at: 2026-03-23T15:39:21.178Z -blocker_discovered: false -observability_surfaces: - - src/resources/extensions/gsd/tests/prompt-contracts.test.ts - - src/resources/extensions/gsd/tests/rogue-file-detection.test.ts - - src/resources/extensions/gsd/auto-post-unit.ts detectRogueFileWrites() results - - direct node --test module-resolution failure showing resolver mismatch on rogue detection ---- - -# T03: Migrate planning prompts to DB-backed tool guidance and extend rogue detection to roadmap/plan artifacts - -**Migrate planning prompts to DB-backed tool guidance and extend rogue detection to roadmap/plan artifacts** - -## What Happened - -I executed the T03 contract against the current repo state instead of the planner snapshot. First I verified the slice plan’s observability section already contained the required failure-path coverage, then read the five planning prompts, `auto-post-unit.ts`, and the existing prompt/rogue test files. The root gap was straightforward: milestone and adjacent planning prompts still contained direct file-writing language, while rogue-file detection only covered execute-task and complete-slice summary artifacts. I updated `plan-milestone.md` and `guided-plan-milestone.md` so they now route milestone planning through `gsd_plan_milestone` and explicitly forbid manual roadmap writes. I also updated `plan-slice.md`, `replan-slice.md`, and `reassess-roadmap.md` so those planning-era prompts consistently treat DB-backed tool state as the source of truth and stop implying that direct roadmap/plan edits are acceptable. On the enforcement side, I extended `detectRogueFileWrites()` in `src/resources/extensions/gsd/auto-post-unit.ts` to flag direct `ROADMAP.md` writes for `plan-milestone` when no milestone planning state exists in DB, and direct slice `PLAN.md` writes for `plan-slice` / `replan-slice` when no matching slice planning state exists. I preserved the existing execute-task and complete-slice logic. I then expanded `prompt-contracts.test.ts` with explicit assertions that the milestone and adjacent planning prompts reference the tool path and forbid manual roadmap/plan writes, and expanded `rogue-file-detection.test.ts` with positive/negative cases for roadmap and slice-plan rogue detection. The first verification run exposed two concrete issues only: my initial prompt assertions were too broad and matched the new explicit prohibition text, and I incorrectly imported a non-existent `updateMilestone` export. I fixed those specific problems by tightening the prompt assertions to test for the explicit prohibition language and switching the DB setup to `upsertMilestonePlanning()`. After that, the adapted task-level test command passed cleanly. - -## Verification - -I ran the task-level verification under the repository’s actual TypeScript harness: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts src/resources/extensions/gsd/tests/rogue-file-detection.test.ts`, and all 32 assertions passed. I also ran the literal slice-plan verification pieces individually. `node --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts` now passes directly. `node --test src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` still fails before reaching the test logic because `auto-post-unit.ts` imports `.js` sibling modules from TypeScript sources and direct `node --test` cannot resolve them without the repo’s resolver import; this is the same repo-local harness mismatch previously documented in T02, not a regression introduced by this task. Observability expectations for T03 are now met: prompt regressions fail explicitly in `prompt-contracts.test.ts`, and rogue roadmap/plan bypasses are surfaced immediately by `detectRogueFileWrites()` and its regression tests. - -## Verification Evidence - -| # | Command | Exit Code | Verdict | Duration | -|---|---------|-----------|---------|----------| -| 1 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` | 0 | ✅ pass | 519ms | -| 2 | `node --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts` | 0 | ✅ pass | 107ms | -| 3 | `node --test src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` | 1 | ❌ fail | 103ms | - - -## Deviations - -Used the repository’s existing TypeScript resolver harness for the authoritative task-level verification because `rogue-file-detection.test.ts` cannot run truthfully under bare `node --test` in this source tree. No functional deviation from the task scope otherwise. - -## Known Issues - -Direct `node --test src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` still fails with `ERR_MODULE_NOT_FOUND` on `.js` sibling imports from TypeScript sources (`auto-post-unit.ts` → `state.js`) unless the repo resolver import is used. This harness mismatch predates this task and remains for T04 to account for when running the integrated slice suite. No T03-specific functional failures remain under the repo’s actual TS harness. - -## Diagnostics - -- Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` to verify prompt migration and rogue-detection behavior together. -- Inspect `src/resources/extensions/gsd/auto-post-unit.ts` for `detectRogueFileWrites()` cases covering `plan-milestone`, `plan-slice`, and `replan-slice` when checking enforcement behavior. -- If only `rogue-file-detection.test.ts` fails under bare `node --test`, treat that first as the known resolver mismatch documented here before assuming the T03 logic regressed. - -## Files Created/Modified - -- `src/resources/extensions/gsd/prompts/plan-milestone.md` -- `src/resources/extensions/gsd/prompts/guided-plan-milestone.md` -- `src/resources/extensions/gsd/prompts/plan-slice.md` -- `src/resources/extensions/gsd/prompts/replan-slice.md` -- `src/resources/extensions/gsd/prompts/reassess-roadmap.md` -- `src/resources/extensions/gsd/auto-post-unit.ts` -- `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` -- `src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` diff --git a/.gsd/milestones/M001/slices/S01/tasks/T03-VERIFY.json b/.gsd/milestones/M001/slices/S01/tasks/T03-VERIFY.json deleted file mode 100644 index dc8b89569..000000000 --- a/.gsd/milestones/M001/slices/S01/tasks/T03-VERIFY.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "schemaVersion": 1, - "taskId": "T03", - "unitId": "M001/S01/T03", - "timestamp": 1774280365186, - "passed": false, - "discoverySource": "package-json", - "checks": [ - { - "command": "npm run test", - "exitCode": 1, - "durationMs": 39574, - "verdict": "fail" - } - ], - "retryAttempt": 1, - "maxRetries": 2 -} diff --git a/.gsd/milestones/M001/slices/S01/tasks/T04-PLAN.md b/.gsd/milestones/M001/slices/S01/tasks/T04-PLAN.md deleted file mode 100644 index 1246d7cb1..000000000 --- a/.gsd/milestones/M001/slices/S01/tasks/T04-PLAN.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -estimated_steps: 3 -estimated_files: 5 -skills_used: - - debug-like-expert - - test - - review ---- - -# T04: Close the slice with integrated regression coverage - -**Slice:** S01 — Schema v8 + plan_milestone tool + ROADMAP renderer -**Milestone:** M001 - -## Description - -Run and tighten the targeted S01 regression suite so the slice closes with real integration confidence instead of a pile of uncoordinated edits. This task exists to catch interface mismatches between schema migration, handler behavior, roadmap rendering, prompt contracts, and rogue detection before S02 builds on top of them. - -## Steps - -1. Review the final S01 test surfaces for gaps introduced by T01-T03 and add any missing assertions needed to keep the slice demo and requirements true. -2. Run the full targeted S01 verification suite and fix test fixtures or expectations that drifted during implementation. -3. Leave the slice with a clean, repeatable targeted proof command set that downstream slices can trust. - -## Must-Haves - -- [ ] The targeted S01 suite runs green against the final implementation. -- [ ] Test fixtures and expectations match the final roadmap format, tool output, and rogue-detection rules. -- [ ] No S01 requirement is left depending on an unverified behavior. - -## Verification - -- `node --test src/resources/extensions/gsd/tests/plan-milestone.test.ts src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/prompt-contracts.test.ts src/resources/extensions/gsd/tests/rogue-file-detection.test.ts src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts` -- Confirm the suite proves schema migration, handler path, roadmap rendering, prompt migration, and rogue detection together. - -## Inputs - -- `src/resources/extensions/gsd/tests/plan-milestone.test.ts` — tool-handler contract coverage from T02 -- `src/resources/extensions/gsd/tests/markdown-renderer.test.ts` — roadmap rendering and parser round-trip coverage from T01 -- `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` — planning prompt contract coverage from T03 -- `src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` — rogue planning artifact coverage from T03 -- `src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts` — migration/backfill coverage from T01 - -## Expected Output - -- `src/resources/extensions/gsd/tests/plan-milestone.test.ts` — finalized integrated handler assertions -- `src/resources/extensions/gsd/tests/markdown-renderer.test.ts` — finalized roadmap renderer assertions -- `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` — finalized planning prompt assertions -- `src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` — finalized planning rogue-detection assertions -- `src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts` — finalized v8 migration/backfill assertions - -## Observability Impact - -- Runtime signals: integrated regressions must expose whether failures come from schema migration, milestone planning writes, roadmap rendering, prompt contracts, or rogue-write enforcement rather than collapsing into an opaque suite failure. -- Inspection surfaces: `plan-milestone.test.ts`, `markdown-renderer.test.ts`, `prompt-contracts.test.ts`, `rogue-file-detection.test.ts`, and `migrate-hierarchy.test.ts` together provide the future inspection path for this slice; the integrated proof command must remain runnable and trustworthy. -- Failure visibility: any failing assertion in this task should name the drifted contract directly (render shape, DB write path, prompt text, or rogue path) so a future agent can resume from the exact broken seam without re-research. -- Redaction constraints: none beyond normal repository data; no secrets involved. diff --git a/.gsd/milestones/M001/slices/S01/tasks/T04-SUMMARY.md b/.gsd/milestones/M001/slices/S01/tasks/T04-SUMMARY.md deleted file mode 100644 index 649beed6f..000000000 --- a/.gsd/milestones/M001/slices/S01/tasks/T04-SUMMARY.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -id: T04 -parent: S01 -milestone: M001 -key_files: - - .gsd/milestones/M001/slices/S01/tasks/T04-PLAN.md - - src/resources/extensions/gsd/tests/plan-milestone.test.ts -key_decisions: - - Replaced invalid ESM export monkey-patching in `plan-milestone.test.ts` with observable integration assertions that verify cache-clearing effects through real roadmap parse state. - - Used the repository’s resolver-based TypeScript harness as the authoritative S01 proof path because it is the only truthful way to execute the targeted source tests in this repo. -duration: "" -verification_result: passed -completed_at: 2026-03-23T15:43:33.011Z -blocker_discovered: false -observability_surfaces: - - src/resources/extensions/gsd/tests/plan-milestone.test.ts - - src/resources/extensions/gsd/tests/markdown-renderer.test.ts - - stderr warning|stale renderer diagnostic test path - - parse-visible roadmap state before/after handler execution in integration assertions ---- - -# T04: Finalize S01 regression coverage and prove the DB-backed planning slice end to end - -**Finalize S01 regression coverage and prove the DB-backed planning slice end to end** - -## What Happened - -I executed the T04 closeout against local repo reality rather than the stale plan snapshot. First I fixed the mandatory pre-flight gap in `.gsd/milestones/M001/slices/S01/tasks/T04-PLAN.md` by adding an `## Observability Impact` section so the task documents how future agents inspect failures. I then read the five target test surfaces and confirmed the remaining real defect was the unfinished T02 cache-invalidation coverage in `src/resources/extensions/gsd/tests/plan-milestone.test.ts`: two tests still attempted to monkey-patch imported ESM bindings, which is not a valid harness seam. I replaced those brittle tests with observable integration assertions that prove the same contract truthfully: render failures do not advance parse-visible roadmap state, and successful milestone planning clears parse-visible roadmap state so subsequent reads reflect the newly rendered DB-backed roadmap. My first replacement hypothesis was wrong because `handlePlanMilestone()` inserts the requested milestone before rendering, so a mismatched milestone ID does not fail render. I corrected that by inducing a real write-path render failure through the fallback roadmap target path and re-ran the focused suite. After that passed, I ran the full targeted S01 regression suite under the repository’s actual TypeScript resolver harness and then ran the slice’s explicit renderer failure-path check (`stderr warning|stale`) separately. Both passed cleanly. The slice now has integrated regression proof across schema migration, handler behavior, roadmap rendering, prompt contracts, and rogue-write detection, with the failure-path renderer diagnostics also exercised directly. - -## Verification - -Verified the final S01 slice proof set under the repository’s real TypeScript test harness (`--import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types`). First ran the focused handler suite to confirm the rewritten plan-milestone cache/renderer assertions passed. Then ran the combined targeted S01 suite covering `plan-milestone.test.ts`, `markdown-renderer.test.ts`, `prompt-contracts.test.ts`, `rogue-file-detection.test.ts`, and `migrate-hierarchy.test.ts`; all tests passed. Finally ran `markdown-renderer.test.ts` again with `--test-name-pattern="stderr warning|stale"` to prove the slice-level diagnostic/failure-path checks pass explicitly. This verifies schema migration/backfill coverage, the DB-backed milestone planning write path, roadmap rendering from DB state, planning prompt migration, rogue detection for roadmap/plan bypasses, and renderer observability surfaces together. - -## Verification Evidence - -| # | Command | Exit Code | Verdict | Duration | -|---|---------|-----------|---------|----------| -| 1 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts` | 0 | ✅ pass | 164ms | -| 2 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/prompt-contracts.test.ts src/resources/extensions/gsd/tests/rogue-file-detection.test.ts src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts` | 0 | ✅ pass | 1650ms | -| 3 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts --test-name-pattern="stderr warning|stale"` | 0 | ✅ pass | 195ms | - - -## Deviations - -Used the repository’s actual resolver-based TypeScript test harness instead of bare `node --test` because this source tree’s `.ts` tests depend on the resolver import for truthful execution. Also adapted the stale T02 cache tests to assert observable behavior rather than illegal ESM export reassignment. No scope deviation beyond those local-reality corrections. - -## Known Issues - -None. - -## Diagnostics - -- Run the integrated slice proof with `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/prompt-contracts.test.ts src/resources/extensions/gsd/tests/rogue-file-detection.test.ts src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts`. -- Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts --test-name-pattern="stderr warning|stale"` to inspect the dedicated failure-path and stale-render diagnostics. -- Use `src/resources/extensions/gsd/tests/plan-milestone.test.ts` as the durable seam for cache-invalidation behavior; it now proves observable state changes instead of relying on illegal ESM export reassignment. - -## Files Created/Modified - -- `.gsd/milestones/M001/slices/S01/tasks/T04-PLAN.md` -- `src/resources/extensions/gsd/tests/plan-milestone.test.ts` diff --git a/.gsd/milestones/M001/slices/S01/tasks/T04-VERIFY.json b/.gsd/milestones/M001/slices/S01/tasks/T04-VERIFY.json deleted file mode 100644 index 8d6f5747e..000000000 --- a/.gsd/milestones/M001/slices/S01/tasks/T04-VERIFY.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "schemaVersion": 1, - "taskId": "T04", - "unitId": "M001/S01/T04", - "timestamp": 1774280619727, - "passed": false, - "discoverySource": "package-json", - "checks": [ - { - "command": "npm run test", - "exitCode": 1, - "durationMs": 39485, - "verdict": "fail" - } - ], - "retryAttempt": 1, - "maxRetries": 2 -} diff --git a/.gsd/milestones/M001/slices/S02/S02-PLAN.md b/.gsd/milestones/M001/slices/S02/S02-PLAN.md deleted file mode 100644 index a5b733992..000000000 --- a/.gsd/milestones/M001/slices/S02/S02-PLAN.md +++ /dev/null @@ -1,74 +0,0 @@ -# S02: plan_slice + plan_task tools + PLAN/task-plan renderers - -**Goal:** Add DB-backed slice and task planning write paths that persist flat planning payloads, render parse-compatible `S##-PLAN.md` and `tasks/T##-PLAN.md` artifacts from DB state, and keep task plan files present on disk so planning/execution recovery continues to work. -**Demo:** Running the S02 planning proof writes slice/task planning data through `gsd_plan_slice` and `gsd_plan_task`, regenerates `S02-PLAN.md` and `tasks/T01-PLAN.md`/`tasks/T02-PLAN.md` from DB, and passes runtime checks that reject missing task plan files. - -## Must-Haves - -- `gsd_plan_slice` validates a flat payload, requires an existing slice, writes slice planning plus task rows transactionally, renders `S##-PLAN.md`, and clears both state and parse caches. (R003) -- `gsd_plan_task` validates a flat payload, requires an existing parent slice, writes task planning fields, renders `tasks/T##-PLAN.md`, and clears both caches. (R004) -- `renderPlanFromDb()` and `renderTaskPlanFromDb()` emit markdown that still round-trips through `parsePlan()` / `parseTaskPlanFile()` and satisfies `auto-recovery.ts` plan-slice artifact checks, including on-disk task plan existence. (R008, R019) -- Prompt and tool registration surfaces expose the new DB-backed planning path instead of leaving slice/task planning as direct file writes. - -## Proof Level - -- This slice proves: integration -- Real runtime required: yes -- Human/UAT required: no - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts` -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/auto-recovery.test.ts src/resources/extensions/gsd/tests/prompt-contracts.test.ts --test-name-pattern="plan-slice|plan-task|renderPlanFromDb|renderTaskPlanFromDb|task plan|DB-backed planning"` -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts --test-name-pattern="validation failed|render failed|cache|missing parent"` - -## Observability / Diagnostics - -- Runtime signals: handler error strings for validation / DB write / render failure, plus stale-render diagnostics from `markdown-renderer.ts` when rendered plan artifacts drift from DB state. -- Inspection surfaces: `src/resources/extensions/gsd/tests/plan-slice.test.ts`, `src/resources/extensions/gsd/tests/plan-task.test.ts`, `src/resources/extensions/gsd/tests/markdown-renderer.test.ts`, `src/resources/extensions/gsd/tests/auto-recovery.test.ts`, and SQLite rows returned by `getSlice()`, `getTask()`, and `getSliceTasks()`. -- Failure visibility: failed handler result payloads, missing `tasks/T##-PLAN.md` artifact assertions, and renderer/parser mismatches surfaced by the resolver-based test harness. -- Redaction constraints: no secrets expected; task-plan frontmatter must expose skill names only, never secret values or environment data. - -## Integration Closure - -- Upstream surfaces consumed: `src/resources/extensions/gsd/tools/plan-milestone.ts`, `src/resources/extensions/gsd/bootstrap/db-tools.ts`, `src/resources/extensions/gsd/gsd-db.ts`, `src/resources/extensions/gsd/markdown-renderer.ts`, `src/resources/extensions/gsd/files.ts`, `src/resources/extensions/gsd/auto-recovery.ts`, and `src/resources/extensions/gsd/prompts/plan-slice.md`. -- New wiring introduced in this slice: canonical tool handlers/registrations for `gsd_plan_slice` and `gsd_plan_task`, DB→markdown renderers for slice and task plans, and prompt-contract coverage that points planning flows at those tools. -- What remains before the milestone is truly usable end-to-end: S03 still needs replan/reassess structural enforcement, and S04 still needs hot-path caller migration plus DB↔rendered cross-validation. - -## Tasks - -I’m splitting this into three tasks because there are three distinct failure boundaries and each needs its own proof. The highest-risk boundary is renderer compatibility: if the generated `PLAN.md` or task-plan markdown drifts from parser/runtime expectations, the rest of the slice is fake progress. That work goes first and includes the runtime contract around `skills_used` frontmatter and task-plan file existence. Once the render target is stable, the handler/registration work becomes straightforward because S01 already established the validation → transaction → render → invalidate pattern. The last task is prompt/tool-surface closure, which is intentionally small but necessary: without it, the system still has a gap between the new DB-backed implementation and the planning instructions/registrations the LLM actually sees. - -- [x] **T01: Add DB-backed slice and task plan renderers with compatibility tests** `est:1.5h` - - Why: This closes the main transition-window risk first: rendered plan artifacts must stay parse-compatible and satisfy runtime recovery checks before any new planning handler can be trusted. - - Files: `src/resources/extensions/gsd/markdown-renderer.ts`, `src/resources/extensions/gsd/tests/markdown-renderer.test.ts`, `src/resources/extensions/gsd/tests/auto-recovery.test.ts`, `src/resources/extensions/gsd/files.ts` - - Do: Implement `renderPlanFromDb()` and `renderTaskPlanFromDb()` using existing DB query helpers, emit slice/task markdown that preserves `parsePlan()` and `parseTaskPlanFile()` expectations, include conservative task-plan frontmatter (`estimated_steps`, `estimated_files`, `skills_used`), and add tests that prove rendered slice plans plus task plan files satisfy `verifyExpectedArtifact("plan-slice", ...)`. - - Verify: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/auto-recovery.test.ts --test-name-pattern="renderPlanFromDb|renderTaskPlanFromDb|plan-slice|task plan"` - - Done when: DB rows can be rendered into `S##-PLAN.md` and `tasks/T##-PLAN.md` files that parse cleanly and pass the existing plan-slice runtime artifact checks. -- [x] **T02: Implement and register gsd_plan_slice and gsd_plan_task** `est:1.5h` - - Why: This delivers the actual S02 capability: flat DB-backed planning tools for slices and tasks that write structured planning state, render truthful markdown, and clear stale caches after success. - - Files: `src/resources/extensions/gsd/tools/plan-slice.ts`, `src/resources/extensions/gsd/tools/plan-task.ts`, `src/resources/extensions/gsd/bootstrap/db-tools.ts`, `src/resources/extensions/gsd/gsd-db.ts`, `src/resources/extensions/gsd/tests/plan-slice.test.ts`, `src/resources/extensions/gsd/tests/plan-task.test.ts` - - Do: Follow the S01 handler pattern exactly for both tools, add any missing DB upsert/query helpers needed to populate task planning fields and retrieve slice/task planning state, register canonical tools plus aliases in `db-tools.ts`, and test validation, missing-parent rejection, transactional DB writes, render-failure handling, idempotent reruns, and observable cache invalidation. - - Verify: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts` - - Done when: `gsd_plan_slice` and `gsd_plan_task` exist as registered DB tools, reject malformed input, render plan artifacts after successful writes, and refresh parse-visible state immediately. -- [x] **T03: Close prompt and contract coverage around DB-backed slice planning** `est:45m` - - Why: The implementation is incomplete until the planning prompt/test surface actually points at the new tools and proves the DB-backed route is the expected contract instead of manual markdown edits. - - Files: `src/resources/extensions/gsd/prompts/plan-slice.md`, `src/resources/extensions/gsd/tests/prompt-contracts.test.ts`, `src/resources/extensions/gsd/bootstrap/db-tools.ts`, `src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts` - - Do: Update the slice planning prompt text to require tool-backed planning state when `gsd_plan_slice` / `gsd_plan_task` are available, tighten prompt-contract assertions for the new tools, and add/adjust prompt template tests so the planning surface stays aligned with the registered tool path. - - Verify: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts --test-name-pattern="plan-slice|plan task|DB-backed"` - - Done when: slice planning prompts and prompt tests explicitly reference the DB-backed slice/task planning tools and no longer leave direct plan-file writes as the intended path. - -## Files Likely Touched - -- `src/resources/extensions/gsd/gsd-db.ts` -- `src/resources/extensions/gsd/markdown-renderer.ts` -- `src/resources/extensions/gsd/tools/plan-slice.ts` -- `src/resources/extensions/gsd/tools/plan-task.ts` -- `src/resources/extensions/gsd/bootstrap/db-tools.ts` -- `src/resources/extensions/gsd/prompts/plan-slice.md` -- `src/resources/extensions/gsd/tests/plan-slice.test.ts` -- `src/resources/extensions/gsd/tests/plan-task.test.ts` -- `src/resources/extensions/gsd/tests/markdown-renderer.test.ts` -- `src/resources/extensions/gsd/tests/auto-recovery.test.ts` -- `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` -- `src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts` diff --git a/.gsd/milestones/M001/slices/S02/S02-RESEARCH.md b/.gsd/milestones/M001/slices/S02/S02-RESEARCH.md deleted file mode 100644 index 4443fa8e7..000000000 --- a/.gsd/milestones/M001/slices/S02/S02-RESEARCH.md +++ /dev/null @@ -1,84 +0,0 @@ -# S02 — Research - -**Date:** 2026-03-23 - -## Summary - -S02 is targeted research, not deep exploration. The slice is straightforward extension of the S01 pattern: add two DB-backed planning handlers (`gsd_plan_slice`, `gsd_plan_task`), add full DB→markdown renderers for `S##-PLAN.md` and `T##-PLAN.md`, register both tools, and cover the runtime contract that task plan files must still exist on disk. The active requirements this slice directly owns are R003, R004, R008, and R019. - -The main constraint is that this is not just “store more planning fields.” The slice plan file and per-task plan files remain part of the runtime. `auto-recovery.ts` explicitly rejects a `plan-slice` artifact when referenced task plan files are missing, `execute-task` prompt flow expects task plans on disk, and `buildSkillActivationBlock()` consumes `skills_used` from task-plan frontmatter. So the implementation must write DB state and also render both artifact layers truthfully from that state. - -## Recommendation - -Follow the S01 handler pattern exactly: validate flat params → one transaction → render markdown from DB → invalidate both state and parse caches. Reuse the existing `insertSlice`/`upsertSlicePlanning` and `insertTask` primitives in `gsd-db.ts`; do not invent a new storage layer. Add minimal new validation/handler modules and renderer functions rather than refactoring shared infrastructure in this slice. - -Treat `S##-PLAN.md` as a slice-level rendered view from `slices` + `tasks` rows, and `T##-PLAN.md` as a task-level rendered view from one `tasks` row plus fixed frontmatter fields. Preserve existing parser/runtime compatibility instead of optimizing schema shape. That lines up with the `create-gsd-extension` skill rule to extend existing GSD extension primitives rather than introducing parallel abstractions, and with the `test` skill rule to match existing test patterns and immediately verify generated behavior under the repo’s real resolver harness. - -## Implementation Landscape - -### Key Files - -- `src/resources/extensions/gsd/tools/plan-milestone.ts` — canonical planning-tool reference. Establishes the exact validation → transaction → render → `invalidateStateCache()` + `clearParseCache()` flow S02 should mirror. -- `src/resources/extensions/gsd/bootstrap/db-tools.ts` — registers `gsd_plan_milestone`. S02 needs parallel registrations for `gsd_plan_slice` and `gsd_plan_task`, with the same execute/error/details shape and canonical-name guidance. -- `src/resources/extensions/gsd/gsd-db.ts` — schema v8 already contains the needed planning columns. `insertSlice`, `upsertSlicePlanning`, `insertTask`, `getSlice`, `getTask`, `getSliceTasks`, and `getMilestoneSlices` already expose most of the storage/query surface S02 needs. -- `src/resources/extensions/gsd/markdown-renderer.ts` — has `renderRoadmapFromDb()` and shared helpers `toArtifactPath()`, `writeAndStore()`, and cache invalidation. Natural place to add `renderPlanFromDb()` and `renderTaskPlanFromDb()`. -- `src/resources/extensions/gsd/templates/plan.md` — authoritative output shape for slice plans. The renderer should emit markdown parse-compatible with this structure, especially the `## Tasks` checkbox lines and `Verify:` field formatting. -- `src/resources/extensions/gsd/templates/task-plan.md` — authoritative task plan structure. Critical fields: frontmatter `estimated_steps`, `estimated_files`, `skills_used`; sections for Description, Steps, Must-Haves, Verification, optional Observability Impact, Inputs, Expected Output. -- `src/resources/extensions/gsd/files.ts` — parser compatibility target. `parsePlan()` still drives transition-window callers, and `parseTaskPlanFile()` only reads task-plan frontmatter today. Rendered files must satisfy these parsers without new parser work in this slice. -- `src/resources/extensions/gsd/auto-recovery.ts` — enforces R019. `verifyExpectedArtifact("plan-slice", ...)` fails when task IDs appear in `S##-PLAN.md` but matching `tasks/T##-PLAN.md` files are missing. -- `src/resources/extensions/gsd/auto-prompts.ts` — `buildSkillActivationBlock()` parses `skills_used` from task-plan frontmatter. If renderer omits or malforms that list, downstream executor prompt routing degrades. -- `src/resources/extensions/gsd/prompts/plan-slice.md` — already updated to say DB-backed tool should own state. S02 likely needs prompt contract tightening once tool names exist, but S01 already removed PLAN-as-source-of-truth framing. -- `src/resources/extensions/gsd/tests/plan-milestone.test.ts` — best reference for handler tests: validation failure, DB write success, render failure behavior, idempotent rerun, observable cache invalidation. -- `src/resources/extensions/gsd/tests/markdown-renderer.test.ts` — existing renderer/stale-repair coverage pattern. Best place for slice/task plan render tests and stale detection if needed. -- `src/resources/extensions/gsd/tests/auto-recovery.test.ts` — already proves missing task plan files break `plan-slice` artifact validity. S02 should add integration-style tests that its renderer satisfies this contract. -- `src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts` — confirms legacy markdown import populates planning columns (`goal`, task status/order, etc.). Useful as parity reference when deciding which DB fields the new renderer must expose. - -### Build Order - -1. **Renderer shape first** — implement `renderPlanFromDb()` and `renderTaskPlanFromDb()` in `markdown-renderer.ts` before tool handlers. This is the highest-risk compatibility point because transition-window callers still parse markdown and runtime checks still require plan files on disk. -2. **Slice/task handler implementation second** — add `tools/plan-slice.ts` and `tools/plan-task.ts` following the S01 handler pattern, using existing DB primitives and new renderers. -3. **Tool registration third** — wire both handlers into `bootstrap/db-tools.ts` after handler behavior is stable. -4. **Prompt/test contract updates last** — only after tool names and artifact paths are real. Keep prompt work narrow: assert the prompts reference the DB-backed path and not direct artifact writes. - -This order isolates the root risk first: if rendering is wrong, handlers and prompts still fail the slice. The `debug-like-expert` skill’s “verify, don’t assume” rule applies here — prove rendered files satisfy parser/runtime contracts before layering more orchestration on top. - -### Verification Approach - -Run the repo’s resolver-based TypeScript harness, not bare `node --test`. - -Primary proof command: - -`node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/auto-recovery.test.ts src/resources/extensions/gsd/tests/prompt-contracts.test.ts` - -What to prove: - -- `plan-slice` handler validates flat params, rejects missing/invalid fields, verifies the slice exists, writes slice planning/task rows, renders `S##-PLAN.md`, and clears both caches. -- `plan-task` handler validates flat params, verifies parent slice exists, writes task planning fields, renders `tasks/T##-PLAN.md`, and clears both caches. -- `renderPlanFromDb()` emits parse-compatible task checkbox entries and slice sections from DB state. -- `renderTaskPlanFromDb()` writes parse-compatible frontmatter with `estimated_steps`, `estimated_files`, and `skills_used`, plus the required markdown sections. -- A rendered slice plan plus rendered task plans satisfies `verifyExpectedArtifact("plan-slice", ...)`. -- Prompt contracts mention the new DB-backed tool path rather than manual file writes, if prompts are changed. - -## Constraints - -- Schema work should stay minimal. `gsd-db.ts` already has the v8 columns needed for slice and task planning (`goal`, `success_criteria`, `proof_level`, `integration_closure`, `observability_impact`, plus task `description`, `estimate`, `files`, `verify`, `inputs`, `expected_output`). -- `getSliceTasks()` and `getMilestoneSlices()` still order by `id`, not an explicit sequence column. S02 should not try to solve ordering beyond the current ID-based convention; sequence-aware ordering belongs to S04 per roadmap. -- Task-plan frontmatter is already a runtime input. `parseTaskPlanFile()` normalizes numeric strings and scalar/list `skills_used`, so rendered output should stay conservative and explicit rather than clever. -- Tool registration in this extension uses TypeBox object schemas in `db-tools.ts`; follow the existing project pattern already present for `gsd_plan_milestone`. - -## Common Pitfalls - -- **Rendering only the slice plan** — R019 will still fail because `auto-recovery.ts` checks that every task listed in `S##-PLAN.md` has a matching `tasks/T##-PLAN.md` file. -- **Forgetting cache invalidation after successful render** — S01 already proved stale parse-visible state is the failure mode; S02 must clear both `invalidateStateCache()` and `clearParseCache()` after DB + render success. -- **Writing task plans without `skills_used` frontmatter** — executor prompt skill activation silently loses task-specific skill routing because `buildSkillActivationBlock()` reads that field. -- **Using a new ad hoc markdown format** — transition-window callers still depend on `parsePlan()` and task-plan conventions. Match existing template/test shapes, don’t redesign the documents. - -## Skills Discovered - -| Technology | Skill | Status | -|------------|-------|--------| -| GSD extension/tooling | `create-gsd-extension` | installed | -| Test execution / harness discipline | `test` | installed | -| Root-cause-first verification | `debug-like-expert` | installed | -| SQLite / migration-heavy planning storage | `npx skills add martinholovsky/claude-skills-generator@sqlite-database-expert -g` | available | -| TypeBox schema authoring | `npx skills add epicenterhq/epicenter@typebox -g` | available | diff --git a/.gsd/milestones/M001/slices/S02/S02-SUMMARY.md b/.gsd/milestones/M001/slices/S02/S02-SUMMARY.md deleted file mode 100644 index 10f17c1ab..000000000 --- a/.gsd/milestones/M001/slices/S02/S02-SUMMARY.md +++ /dev/null @@ -1,132 +0,0 @@ ---- -id: S02 -parent: M001 -milestone: M001 -provides: - - gsd_plan_slice tool handler — DB-backed slice planning write path - - gsd_plan_task tool handler — DB-backed task planning write path - - renderPlanFromDb() — generates S##-PLAN.md from DB state - - renderTaskPlanFromDb() — generates T##-PLAN.md from DB state - - upsertTaskPlanning() — safe planning-field updates on existing task rows - - getSliceTasks() and getTask() query functions with planning fields populated - - Prompt contract tests for plan-slice prompt DB-backed tool references -requires: - - slice: S01 - provides: Schema v8 migration with planning columns on slices/tasks tables - - slice: S01 - provides: Tool handler pattern from plan-milestone.ts (validate → transaction → render → invalidate) - - slice: S01 - provides: renderRoadmapFromDb() and markdown-renderer.ts rendering infrastructure - - slice: S01 - provides: db-tools.ts registration pattern and DB-availability checks -affects: - - S03 - - S04 -key_files: - - src/resources/extensions/gsd/markdown-renderer.ts - - src/resources/extensions/gsd/tools/plan-slice.ts - - src/resources/extensions/gsd/tools/plan-task.ts - - src/resources/extensions/gsd/bootstrap/db-tools.ts - - src/resources/extensions/gsd/gsd-db.ts - - src/resources/extensions/gsd/prompts/plan-slice.md - - src/resources/extensions/gsd/tests/plan-slice.test.ts - - src/resources/extensions/gsd/tests/plan-task.test.ts - - src/resources/extensions/gsd/tests/prompt-contracts.test.ts - - src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts - - src/resources/extensions/gsd/tests/markdown-renderer.test.ts - - src/resources/extensions/gsd/tests/auto-recovery.test.ts -key_decisions: - - upsertTaskPlanning() updates planning fields without clobbering execution/completion state on existing task rows - - renderPlanFromDb() eagerly renders all child task-plan files so recovery checks see complete artifact set immediately - - Task-plan frontmatter uses conservative skills_used: [] — skill activation remains execution-time only - - plan-slice.md step 6 names gsd_plan_slice/gsd_plan_task as canonical write path; step 7 is degraded fallback -patterns_established: - - Flat TypeBox validation → parent-existence check → transactional DB write → render → cache invalidation pattern extended from milestone tools to slice/task tools - - Prompt contract tests as regression tripwires for tool-name and framing changes in planning prompts - - Parse-visible state assertions as ESM-safe alternative to spy-based cache invalidation testing -observability_surfaces: - - plan-slice.ts and plan-task.ts handler error payloads — structured failure messages for validation/DB/render failures - - detectStaleRenders() stderr warnings when rendered plan artifacts drift from DB state - - verifyExpectedArtifact('plan-slice', ...) — runtime recovery check for task-plan file existence - - SQLite artifacts table rows for rendered S##-PLAN.md and T##-PLAN.md files -drill_down_paths: - - .gsd/milestones/M001/slices/S02/tasks/T01-SUMMARY.md - - .gsd/milestones/M001/slices/S02/tasks/T02-SUMMARY.md - - .gsd/milestones/M001/slices/S02/tasks/T03-SUMMARY.md -duration: "" -verification_result: passed -completed_at: 2026-03-23T16:13:56.461Z -blocker_discovered: false ---- - -# S02: plan_slice + plan_task tools + PLAN/task-plan renderers - -**DB-backed gsd_plan_slice and gsd_plan_task tools write structured planning state to SQLite, render parse-compatible S##-PLAN.md and T##-PLAN.md artifacts, and the plan-slice prompt now names these tools as the canonical write path.** - -## What Happened - -S02 delivered the second layer of the markdown→DB migration: structured write paths for slice and task planning. The work proceeded through three tasks with distinct failure boundaries. - -T01 built the rendering foundation — `renderPlanFromDb()` and `renderTaskPlanFromDb()` in `markdown-renderer.ts`. These read slice/task rows from SQLite and emit markdown that round-trips cleanly through `parsePlan()` and `parseTaskPlanFile()`. The task-plan renderer uses conservative frontmatter (`skills_used: []`) so no speculative values leak from DB state. The slice-plan renderer sources verification/observability content from DB fields when present. Critically, `renderPlanFromDb()` eagerly renders all child task-plan files so `verifyExpectedArtifact("plan-slice", ...)` sees a complete on-disk artifact set immediately. Auto-recovery tests proved rendered task-plan files satisfy the existing file-existence checks, and that deleting a rendered task-plan file correctly fails recovery. - -T02 implemented the actual tool handlers — `handlePlanSlice()` and `handlePlanTask()` — following the S01 pattern: flat TypeBox validation → parent-existence check → transactional DB write → render → cache invalidation. A new `upsertTaskPlanning()` helper in `gsd-db.ts` updates planning-specific columns without clobbering completion state, enabling safe replanning of already-executed tasks. Both tools registered in `db-tools.ts` with canonical names (`gsd_plan_slice`, `gsd_plan_task`) plus aliases (`gsd_slice_plan`, `gsd_task_plan`). The test suite covers validation failures, missing-parent rejection, render-failure isolation, idempotent reruns, and parse-visible cache refresh. - -T03 closed the prompt/contract gap. The plan-slice prompt (`plan-slice.md`) was updated to name `gsd_plan_slice` and `gsd_plan_task` as the primary write path (step 6), with direct file writes explicitly positioned as a degraded fallback (step 7). Four new prompt-contract tests and one template-substitution test ensure the tool names and framing survive prompt changes. This completed the transition from "tools are optional" to "tools are the expected default." - -## Verification - -All four slice-level verification commands pass (120/120 tests): - -1. `plan-slice.test.ts` + `plan-task.test.ts` — 10/10: handler validation, parent checks, DB writes, render, cache invalidation, idempotence -2. `markdown-renderer.test.ts` + `auto-recovery.test.ts` + `prompt-contracts.test.ts` filtered to planning patterns — 60/60: renderer round-trip, task-plan file existence, stale-render detection, prompt contract alignment -3. `plan-slice.test.ts` + `plan-task.test.ts` filtered to failure/cache — 10/10: validation failures, render failures, missing-parent rejection, cache refresh -4. `prompt-contracts.test.ts` + `plan-slice-prompt.test.ts` filtered to plan-slice/DB-backed — 40/40: tool name assertions, degraded-fallback framing, per-task instruction, template substitution - -## Requirements Advanced - -- R014 — S02 renderers produce the artifacts that S04 cross-validation tests will compare against parsed state -- R015 — Both plan-slice and plan-task handlers invalidate state cache and parse cache after successful render, tested via parse-visible state assertions - -## Requirements Validated - -- R003 — plan-slice.test.ts proves flat payload validation, slice-exists check, DB write, S##-PLAN.md rendering, and cache invalidation -- R004 — plan-task.test.ts proves flat payload validation, parent-slice check, DB write, T##-PLAN.md rendering, and cache invalidation -- R008 — markdown-renderer.test.ts proves renderPlanFromDb() generates parse-compatible S##-PLAN.md and renderTaskPlanFromDb() generates T##-PLAN.md with frontmatter -- R019 — auto-recovery.test.ts proves task-plan files must exist on disk — verifyExpectedArtifact passes with files, fails without - -## New Requirements Surfaced - -None. - -## Requirements Invalidated or Re-scoped - -None. - -## Deviations - -T01 did not edit `src/resources/extensions/gsd/files.ts` — the existing parser contract already accepted the renderer output without changes. T02 added `upsertTaskPlanning()` as a narrow DB helper rather than modifying `insertTask()` semantics, which was not explicitly planned but necessary for safe replanning. The T01 summary had verification_result:mixed because the plan-slice.test.ts and plan-task.test.ts files did not exist yet at T01 execution time; T02 subsequently created them and all pass. - -## Known Limitations - -Task-plan frontmatter uses `skills_used: []` conservatively — skill activation remains execution-time only. The planning tools do not enforce task ordering within a slice; sequence is determined by insertion order. Cross-validation tests (DB state vs rendered-then-parsed state) are not yet implemented — that proof is S04's responsibility. - -## Follow-ups - -S03 needs the handler patterns from plan-slice.ts/plan-task.ts as templates for replan_slice and reassess_roadmap tools. S04 needs the query functions (getSliceTasks, getTask) and renderers (renderPlanFromDb, renderTaskPlanFromDb) as inputs for hot-path caller migration and cross-validation tests. - -## Files Created/Modified - -- `src/resources/extensions/gsd/markdown-renderer.ts` — Added renderPlanFromDb() and renderTaskPlanFromDb() — DB-backed renderers for S##-PLAN.md and T##-PLAN.md -- `src/resources/extensions/gsd/tools/plan-slice.ts` — New file — handlePlanSlice() tool handler: validate → DB write → render → cache invalidation -- `src/resources/extensions/gsd/tools/plan-task.ts` — New file — handlePlanTask() tool handler: validate → parent check → DB write → render → cache invalidation -- `src/resources/extensions/gsd/bootstrap/db-tools.ts` — Registered gsd_plan_slice and gsd_plan_task canonical tools plus gsd_slice_plan/gsd_task_plan aliases -- `src/resources/extensions/gsd/gsd-db.ts` — Added upsertTaskPlanning() helper for safe planning-field updates on existing task rows -- `src/resources/extensions/gsd/prompts/plan-slice.md` — Promoted gsd_plan_slice/gsd_plan_task to canonical write path (step 6), direct file writes to degraded fallback (step 7) -- `src/resources/extensions/gsd/tests/plan-slice.test.ts` — New file — 5 handler tests for gsd_plan_slice: validation, parent check, render, idempotence, cache -- `src/resources/extensions/gsd/tests/plan-task.test.ts` — New file — 5 handler tests for gsd_plan_task: validation, parent check, render, idempotence, cache -- `src/resources/extensions/gsd/tests/markdown-renderer.test.ts` — Extended with renderPlanFromDb/renderTaskPlanFromDb round-trip and failure tests -- `src/resources/extensions/gsd/tests/auto-recovery.test.ts` — Extended with rendered task-plan file existence and deletion tests for verifyExpectedArtifact -- `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` — Added 4 assertions for plan-slice prompt: tool names, degraded fallback, per-task instruction -- `src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts` — New file — template substitution test proving tool names survive variable replacement -- `.gsd/KNOWLEDGE.md` — Updated stale entry about missing test files, added ESM-safe testing pattern note -- `.gsd/PROJECT.md` — Updated current state to reflect S02 completion diff --git a/.gsd/milestones/M001/slices/S02/S02-UAT.md b/.gsd/milestones/M001/slices/S02/S02-UAT.md deleted file mode 100644 index 69348e79d..000000000 --- a/.gsd/milestones/M001/slices/S02/S02-UAT.md +++ /dev/null @@ -1,126 +0,0 @@ -# S02: plan_slice + plan_task tools + PLAN/task-plan renderers — UAT - -**Milestone:** M001 -**Written:** 2026-03-23T16:13:56.462Z - -# S02: plan_slice + plan_task tools + PLAN/task-plan renderers — UAT - -**Milestone:** M001 -**Written:** 2026-03-23 - -## UAT Type - -- UAT mode: artifact-driven -- Why this mode is sufficient: All S02 deliverables are tool handlers, renderers, and prompt changes that are fully testable via the resolver-harness test suite without a live runtime. The test suite covers round-trip parsing, file-existence checks, and prompt contract assertions. - -## Preconditions - -- Working tree has `src/resources/extensions/gsd/tests/resolve-ts.mjs` available -- Node.js supports `--experimental-strip-types` and `--import` flags -- No other processes hold locks on temp SQLite DBs created by tests - -## Smoke Test - -Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts` — all 10 tests should pass, confirming both handlers accept valid input, reject invalid input, write to DB, render artifacts, and refresh caches. - -## Test Cases - -### 1. gsd_plan_slice writes planning state and renders S##-PLAN.md - -1. Call `handlePlanSlice()` with a valid payload including milestoneId, sliceId, goal, demo, mustHaves, tasks array, and filesLikelyTouched. -2. Read the slice row from SQLite. -3. Read the rendered `S##-PLAN.md` from disk. -4. Parse the rendered file through `parsePlan()`. -5. **Expected:** DB row contains goal/demo/mustHaves fields. Rendered file exists on disk. Parsed result contains all tasks from the payload. All child `T##-PLAN.md` files exist on disk. - -### 2. gsd_plan_task writes task planning and renders T##-PLAN.md - -1. Create a slice row in DB. -2. Call `handlePlanTask()` with milestoneId, sliceId, taskId, title, why, files, steps, verifyCommand, doneWhen. -3. Read the task row from SQLite. -4. Read the rendered `tasks/T##-PLAN.md` from disk. -5. Parse through `parseTaskPlanFile()`. -6. **Expected:** DB row contains steps/files/verify_command fields. Rendered file has YAML frontmatter with `estimated_steps`, `estimated_files`, `skills_used: []`. Parsed result matches input fields. - -### 3. Rendered plan artifacts satisfy auto-recovery checks - -1. Seed a slice and tasks in DB. -2. Call `renderPlanFromDb()` to write S##-PLAN.md and all T##-PLAN.md files. -3. Call `verifyExpectedArtifact("plan-slice", basePath, milestoneId, sliceId)`. -4. **Expected:** Verification passes — all task-plan files exist and the plan file has real task content. - -### 4. Missing task-plan file fails recovery verification - -1. Render a complete plan from DB (S##-PLAN.md + T##-PLAN.md files). -2. Delete one `T##-PLAN.md` file from disk. -3. Call `verifyExpectedArtifact("plan-slice", ...)`. -4. **Expected:** Verification fails with a clear message about the missing task-plan file. - -### 5. Validation rejects malformed payloads - -1. Call `handlePlanSlice()` with missing required fields (e.g., no `goal`). -2. Call `handlePlanTask()` with missing required fields (e.g., no `taskId`). -3. **Expected:** Both return `{ error: true, message: "..." }` with validation failure details. No DB writes. No files created. - -### 6. Missing parent slice is rejected - -1. Call `handlePlanSlice()` with a sliceId that does not exist in DB. -2. Call `handlePlanTask()` with a sliceId that does not exist in DB. -3. **Expected:** Both return error results mentioning the missing parent. No DB writes. - -### 7. Idempotent reruns refresh parse-visible state - -1. Call `handlePlanSlice()` with a valid payload. -2. Call `handlePlanSlice()` again with modified goal text. -3. Read the re-rendered S##-PLAN.md from disk. -4. **Expected:** The file contains the updated goal, not the original. DB row reflects the latest values. - -### 8. plan-slice prompt names DB-backed tools as canonical path - -1. Read `src/resources/extensions/gsd/prompts/plan-slice.md`. -2. Check for `gsd_plan_slice` and `gsd_plan_task` in the text. -3. Check that direct file writes are described as "degraded" or "fallback". -4. **Expected:** Both tool names present. Direct writes framed as fallback, not default. - -## Edge Cases - -### Render failure does not corrupt parse-visible state - -1. Seed a slice and task in DB with a valid plan. -2. Render the initial plan artifacts (S##-PLAN.md + T##-PLAN.md). -3. Simulate a render failure (e.g., invalid basePath). -4. **Expected:** Original files remain on disk unchanged. Error result returned. No cache invalidation occurs for the failed render. - -### Task planning rerun preserves completion state - -1. Insert a task row with `status: 'complete'` and a summary. -2. Call `handlePlanTask()` for the same task with new planning fields. -3. Read the task row from DB. -4. **Expected:** Planning fields (steps, files, verify_command) are updated. Completion fields (status, summary_content, completed_at) are preserved. - -## Failure Signals - -- Any of the 10 `plan-slice.test.ts` / `plan-task.test.ts` tests fail -- `parsePlan()` or `parseTaskPlanFile()` cannot parse rendered artifacts -- `verifyExpectedArtifact("plan-slice", ...)` fails when all task-plan files exist -- Prompt contract tests fail to find `gsd_plan_slice` / `gsd_plan_task` in plan-slice.md - -## Requirements Proved By This UAT - -- R003 — gsd_plan_slice flat tool validates, writes DB, renders S##-PLAN.md, invalidates caches -- R004 — gsd_plan_task flat tool validates, writes DB, renders T##-PLAN.md, invalidates caches -- R008 — renderPlanFromDb() and renderTaskPlanFromDb() generate parse-compatible plan artifacts -- R019 — Task-plan files are generated on disk and validated for existence by auto-recovery - -## Not Proven By This UAT - -- Cross-validation (DB state vs parsed state parity) — deferred to S04 -- Hot-path caller migration from parser reads to DB reads — deferred to S04 -- Replan/reassess structural enforcement — deferred to S03 -- Live auto-mode integration (LLM actually calling these tools in a dispatch loop) — deferred to milestone UAT - -## Notes for Tester - -- All tests use temp directories and in-memory SQLite, so no cleanup needed. -- The resolver-harness (`resolve-ts.mjs`) is required — bare `node --test` may fail on `.js` sibling specifiers. -- T01's verification_result was "mixed" because plan-slice.test.ts didn't exist yet at T01 time. T02 created those files and all pass now. diff --git a/.gsd/milestones/M001/slices/S02/tasks/T01-PLAN.md b/.gsd/milestones/M001/slices/S02/tasks/T01-PLAN.md deleted file mode 100644 index ecb880ea3..000000000 --- a/.gsd/milestones/M001/slices/S02/tasks/T01-PLAN.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -estimated_steps: 5 -estimated_files: 4 -skills_used: - - create-gsd-extension - - test - - debug-like-expert ---- - -# T01: Add DB-backed slice and task plan renderers with compatibility tests - -**Slice:** S02 — plan_slice + plan_task tools + PLAN/task-plan renderers -**Milestone:** M001 - -## Description - -Implement the missing DB→markdown renderers for slice plans and task plans before touching tool handlers. This task owns the compatibility boundary for S02: the generated `S##-PLAN.md` and `tasks/T##-PLAN.md` files must still satisfy `parsePlan()`, `parseTaskPlanFile()`, `auto-recovery.ts`, and executor skill activation via `skills_used` frontmatter. - -## Steps - -1. Read the existing renderer helpers in `src/resources/extensions/gsd/markdown-renderer.ts` and the parser/runtime expectations in `src/resources/extensions/gsd/files.ts` and `src/resources/extensions/gsd/auto-recovery.ts`. -2. Implement `renderPlanFromDb()` so it reads slice/task rows from `src/resources/extensions/gsd/gsd-db.ts`, emits a complete slice plan document with goal, demo, must-haves, verification, and task checklist entries, and writes/stores the artifact through the existing renderer helpers. -3. Implement `renderTaskPlanFromDb()` so it emits a task plan file with valid frontmatter fields (`estimated_steps`, `estimated_files`, `skills_used`) and the required markdown sections from the task row. -4. Add renderer tests in `src/resources/extensions/gsd/tests/markdown-renderer.test.ts` covering parse compatibility, DB artifact persistence, and on-disk output shape for both renderers. -5. Extend `src/resources/extensions/gsd/tests/auto-recovery.test.ts` to prove a rendered slice plan plus rendered task plan files passes `verifyExpectedArtifact("plan-slice", ...)`, and that missing task-plan files still fail. - -## Must-Haves - -- [ ] `renderPlanFromDb()` generates parse-compatible `S##-PLAN.md` content from DB state. -- [ ] `renderTaskPlanFromDb()` generates parse-compatible `tasks/T##-PLAN.md` content with conservative `skills_used` frontmatter. -- [ ] Renderer tests cover both happy-path rendering and the runtime contract that task plan files must exist on disk for `plan-slice` verification. - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/auto-recovery.test.ts --test-name-pattern="renderPlanFromDb|renderTaskPlanFromDb|plan-slice|task plan"` -- Inspect the passing assertions in `src/resources/extensions/gsd/tests/markdown-renderer.test.ts` and `src/resources/extensions/gsd/tests/auto-recovery.test.ts` for rendered `PLAN.md` / `T##-PLAN.md` behavior. - -## Observability Impact - -- Signals added/changed: stale-render diagnostics and renderer test assertions now cover slice/task plan artifacts in addition to roadmap/summary artifacts. -- How a future agent inspects this: run the targeted resolver-harness test command above and inspect generated artifacts via `getArtifact()` / disk files from the renderer tests. -- Failure state exposed: parser incompatibility, missing task-plan files, and DB/artifact drift become explicit test failures instead of silent execution-time regressions. - -## Inputs - -- `src/resources/extensions/gsd/markdown-renderer.ts` — existing render helper patterns and artifact persistence hooks -- `src/resources/extensions/gsd/gsd-db.ts` — slice/task query fields available to renderers -- `src/resources/extensions/gsd/files.ts` — parser expectations for `PLAN.md` and task-plan frontmatter -- `src/resources/extensions/gsd/auto-recovery.ts` — runtime artifact checks that the rendered files must satisfy -- `src/resources/extensions/gsd/tests/markdown-renderer.test.ts` — current renderer test patterns to extend -- `src/resources/extensions/gsd/tests/auto-recovery.test.ts` — existing `plan-slice` artifact enforcement tests - -## Expected Output - -- `src/resources/extensions/gsd/markdown-renderer.ts` — new `renderPlanFromDb()` and `renderTaskPlanFromDb()` implementations -- `src/resources/extensions/gsd/tests/markdown-renderer.test.ts` — coverage for slice/task plan rendering and parse compatibility -- `src/resources/extensions/gsd/tests/auto-recovery.test.ts` — coverage proving rendered task-plan files satisfy `plan-slice` runtime checks -- `src/resources/extensions/gsd/files.ts` — only if a parser-facing compatibility adjustment is required by the new truthful renderer output diff --git a/.gsd/milestones/M001/slices/S02/tasks/T01-SUMMARY.md b/.gsd/milestones/M001/slices/S02/tasks/T01-SUMMARY.md deleted file mode 100644 index d8c0973a6..000000000 --- a/.gsd/milestones/M001/slices/S02/tasks/T01-SUMMARY.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -id: T01 -parent: S02 -milestone: M001 -key_files: - - src/resources/extensions/gsd/markdown-renderer.ts - - src/resources/extensions/gsd/tests/markdown-renderer.test.ts - - src/resources/extensions/gsd/tests/auto-recovery.test.ts - - .gsd/KNOWLEDGE.md -key_decisions: - - Rendered task-plan files use conservative `skills_used: []` frontmatter so execution-time skill activation remains explicit and no secret-bearing or speculative values are emitted from DB state. - - Slice-plan verification content is sourced from the slice `observability_impact` field when present so the DB-backed renderer preserves inspectable diagnostics/failure-path expectations instead of emitting a placeholder-only section. - - `renderPlanFromDb()` eagerly renders all child task-plan files after writing the slice plan so `verifyExpectedArtifact("plan-slice", ...)` sees a truthful on-disk artifact set immediately. -observability_surfaces: - - "markdown-renderer.ts stderr warnings on stale renders (detectStaleRenders) — visible on stderr when rendered plans drift from DB state" - - "auto-recovery.ts verifyExpectedArtifact('plan-slice', ...) — rejects when task-plan files are missing from disk" - - "SQLite artifacts table rows for S##-PLAN.md and T##-PLAN.md — queryable proof of renderer output" -duration: "" -verification_result: mixed -completed_at: 2026-03-23T15:58:46.134Z -blocker_discovered: false ---- - -# T01: Add DB-backed slice and task plan renderers with compatibility and recovery tests - -**Add DB-backed slice and task plan renderers with compatibility and recovery tests** - -## What Happened - -Implemented DB-backed plan rendering in `src/resources/extensions/gsd/markdown-renderer.ts` by adding `renderPlanFromDb()` and `renderTaskPlanFromDb()`. The slice-plan renderer now reads slice/task rows from SQLite, emits parse-compatible `S##-PLAN.md` content with goal, demo, must-haves, verification, checklist tasks, and files-likely-touched, then persists the artifact to disk and the artifacts table. The task-plan renderer now emits `tasks/T##-PLAN.md` files with conservative YAML frontmatter (`estimated_steps`, `estimated_files`, `skills_used: []`) plus `Steps`, `Inputs`, `Expected Output`, `Verification`, and optional `Observability Impact` sections. Extended `markdown-renderer.test.ts` to prove DB-backed plan rendering round-trips through `parsePlan()` and `parseTaskPlanFile()`, writes truthful on-disk artifacts, stores those artifacts in SQLite, and surfaces clear failure behavior for missing task rows. Extended `auto-recovery.test.ts` to prove a rendered slice plan plus rendered task-plan files satisfies `verifyExpectedArtifact("plan-slice", ...)`, and that deleting a rendered task-plan file still fails recovery verification as intended. Also recorded the local verification gotcha in `.gsd/KNOWLEDGE.md`: the slice plan references `plan-slice.test.ts` / `plan-task.test.ts`, but those files are not present in this checkout, so the resolver-harness renderer/recovery/prompt tests are currently the inspectable proof surface for this task. - -## Verification - -Verified the task contract with the targeted resolver-harness command for `markdown-renderer.test.ts` and `auto-recovery.test.ts`; all renderer and recovery assertions passed, including explicit failure-path checks for missing task-plan files and stale-render diagnostics. Ran the broader slice-level resolver-harness command covering `markdown-renderer.test.ts`, `auto-recovery.test.ts`, and `prompt-contracts.test.ts`; it passed and confirmed the DB-backed planning prompt contract remains aligned. Attempted the slice-plan verification command for `plan-slice.test.ts` and `plan-task.test.ts`, then confirmed those referenced files do not exist in this checkout, so that command cannot currently execute here. This is a checkout/test-surface mismatch, not a regression introduced by this task. - -## Verification Evidence - -| # | Command | Exit Code | Verdict | Duration | -|---|---------|-----------|---------|----------| -| 1 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/auto-recovery.test.ts --test-name-pattern="renderPlanFromDb|renderTaskPlanFromDb|plan-slice|task plan"` | 0 | ✅ pass | 693ms | -| 2 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts` | 1 | ❌ fail | 51ms | -| 3 | `ls src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts src/resources/extensions/gsd/tests/prompt-contracts.test.ts` | 1 | ❌ fail | 0ms | -| 4 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/auto-recovery.test.ts src/resources/extensions/gsd/tests/prompt-contracts.test.ts --test-name-pattern="plan-slice|plan-task|renderPlanFromDb|renderTaskPlanFromDb|task plan|DB-backed planning"` | 0 | ✅ pass | 697ms | - - -## Deviations - -Did not edit `src/resources/extensions/gsd/files.ts`; the existing parser contract already accepted the truthful renderer output. The slice plan’s referenced `plan-slice.test.ts` and `plan-task.test.ts` verification command could not be executed because those files are absent in the working tree, so I documented that local mismatch and used the existing resolver-harness renderer/recovery/prompt tests as the effective proof surface. - -## Known Issues - -The slice plan still references `src/resources/extensions/gsd/tests/plan-slice.test.ts` and `src/resources/extensions/gsd/tests/plan-task.test.ts`, but neither file exists in this checkout. Until those tests land, slice-level verification for planning work must rely on the existing `markdown-renderer.test.ts`, `auto-recovery.test.ts`, and related prompt-contract tests. - -## Diagnostics - -- **Rendered artifacts on disk:** Check `S##-PLAN.md` and `tasks/T##-PLAN.md` files in the milestone/slice directory — these are the renderer output and must parse cleanly via `parsePlan()` and `parseTaskPlanFile()`. -- **Artifacts table in SQLite:** Query `SELECT * FROM artifacts WHERE path LIKE '%PLAN.md'` to verify renderer wrote artifact records. -- **Stale render detection:** Run `detectStaleRenders(db, basePath, milestoneId)` — it reports plan checkbox mismatches and missing task summaries on stderr. -- **Recovery verification:** Call `verifyExpectedArtifact("plan-slice", basePath, milestoneId, sliceId)` — returns a diagnostic object with pass/fail plus the list of missing task-plan files. - -## Files Created/Modified - -- `src/resources/extensions/gsd/markdown-renderer.ts` -- `src/resources/extensions/gsd/tests/markdown-renderer.test.ts` -- `src/resources/extensions/gsd/tests/auto-recovery.test.ts` -- `.gsd/KNOWLEDGE.md` diff --git a/.gsd/milestones/M001/slices/S02/tasks/T01-VERIFY.json b/.gsd/milestones/M001/slices/S02/tasks/T01-VERIFY.json deleted file mode 100644 index f41f48982..000000000 --- a/.gsd/milestones/M001/slices/S02/tasks/T01-VERIFY.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "schemaVersion": 1, - "taskId": "T01", - "unitId": "M001/S02/T01", - "timestamp": 1774281533617, - "passed": false, - "discoverySource": "package-json", - "checks": [ - { - "command": "npm run test", - "exitCode": 1, - "durationMs": 11123, - "verdict": "fail" - } - ], - "retryAttempt": 1, - "maxRetries": 2 -} diff --git a/.gsd/milestones/M001/slices/S02/tasks/T02-PLAN.md b/.gsd/milestones/M001/slices/S02/tasks/T02-PLAN.md deleted file mode 100644 index 6d08d2635..000000000 --- a/.gsd/milestones/M001/slices/S02/tasks/T02-PLAN.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -estimated_steps: 5 -estimated_files: 6 -skills_used: - - create-gsd-extension - - test - - debug-like-expert ---- - -# T02: Implement and register gsd_plan_slice and gsd_plan_task - -**Slice:** S02 — plan_slice + plan_task tools + PLAN/task-plan renderers -**Milestone:** M001 - -## Description - -Add the actual DB-backed planning tools for slices and tasks, reusing the S01 handler pattern instead of inventing new plumbing. This task should leave the extension with canonical `gsd_plan_slice` and `gsd_plan_task` registrations, flat validation, transactional DB writes, truthful plan rendering, and observable cache invalidation proof. - -## Steps - -1. Read `src/resources/extensions/gsd/tools/plan-milestone.ts` and mirror its validate → transaction → render → invalidate flow for slice/task planning. -2. Add any missing DB helpers in `src/resources/extensions/gsd/gsd-db.ts` needed to upsert slice planning fields, create/update task planning rows, and query the rendered state used by the handlers. -3. Implement `src/resources/extensions/gsd/tools/plan-slice.ts` with flat input validation, parent-slice existence checks, transactional writes of slice planning plus task rows, renderer invocation, and cache invalidation after successful render. -4. Implement `src/resources/extensions/gsd/tools/plan-task.ts` with flat input validation, parent-slice existence checks, task row upsert logic, task-plan rendering, and post-success cache invalidation. -5. Register both tools and any aliases in `src/resources/extensions/gsd/bootstrap/db-tools.ts`, then add focused handler tests in `src/resources/extensions/gsd/tests/plan-slice.test.ts` and `src/resources/extensions/gsd/tests/plan-task.test.ts` for validation, idempotence, render failure behavior, and parse-visible cache updates. - -## Must-Haves - -- [ ] `gsd_plan_slice` exists as a registered DB-backed tool and writes/renders slice planning state from a flat payload. -- [ ] `gsd_plan_task` exists as a registered DB-backed tool and writes/renders task planning state from a flat payload. -- [ ] Both handlers invalidate `invalidateStateCache()` and `clearParseCache()` only after successful DB write + render, with observable tests proving parse-visible state updates. - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts` -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts src/resources/extensions/gsd/tests/markdown-renderer.test.ts --test-name-pattern="cache|idempotent|render failed|validation failed|plan-slice|plan-task"` - -## Observability Impact - -- Signals added/changed: new handler error payloads for validation / DB write / render failures, plus observable cache-invalidation assertions for slice/task planning writes. -- How a future agent inspects this: run the targeted plan-slice/plan-task test files and inspect `details.operation`, DB rows, and rendered artifacts captured by those tests. -- Failure state exposed: malformed input, missing parent slice, renderer failure, and stale parse-visible state become direct testable outcomes. - -## Inputs - -- `src/resources/extensions/gsd/tools/plan-milestone.ts` — canonical planning handler pattern from S01 -- `src/resources/extensions/gsd/bootstrap/db-tools.ts` — current DB tool registration surface -- `src/resources/extensions/gsd/gsd-db.ts` — existing slice/task storage and query primitives -- `src/resources/extensions/gsd/markdown-renderer.ts` — renderer functions produced by T01 -- `src/resources/extensions/gsd/tests/plan-milestone.test.ts` — reference shape for planning handler tests -- `src/resources/extensions/gsd/tests/markdown-renderer.test.ts` — renderer proof surfaces the handlers rely on - -## Expected Output - -- `src/resources/extensions/gsd/tools/plan-slice.ts` — DB-backed slice planning handler -- `src/resources/extensions/gsd/tools/plan-task.ts` — DB-backed task planning handler -- `src/resources/extensions/gsd/bootstrap/db-tools.ts` — tool registration for `gsd_plan_slice` and `gsd_plan_task` -- `src/resources/extensions/gsd/gsd-db.ts` — any missing upsert/query helpers for slice/task planning state -- `src/resources/extensions/gsd/tests/plan-slice.test.ts` — slice planning handler regression coverage -- `src/resources/extensions/gsd/tests/plan-task.test.ts` — task planning handler regression coverage diff --git a/.gsd/milestones/M001/slices/S02/tasks/T02-SUMMARY.md b/.gsd/milestones/M001/slices/S02/tasks/T02-SUMMARY.md deleted file mode 100644 index 8de1f0d99..000000000 --- a/.gsd/milestones/M001/slices/S02/tasks/T02-SUMMARY.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -id: T02 -parent: S02 -milestone: M001 -key_files: - - .gsd/milestones/M001/slices/S02/S02-PLAN.md - - src/resources/extensions/gsd/tools/plan-slice.ts - - src/resources/extensions/gsd/tools/plan-task.ts - - src/resources/extensions/gsd/bootstrap/db-tools.ts - - src/resources/extensions/gsd/gsd-db.ts - - src/resources/extensions/gsd/tests/plan-slice.test.ts - - src/resources/extensions/gsd/tests/plan-task.test.ts -key_decisions: - - Slice/task planning writes use dedicated `upsertTaskPlanning()` updates layered on top of `insertTask()` seed rows so rerunning planning does not erase execution/completion fields stored on existing tasks. - - `handlePlanSlice()` follows a DB-first flow that writes slice/task planning rows transactionally, then renders the slice plan plus all task-plan files; cache invalidation remains post-render only, and observability is proven through parse-visible file state rather than internal spies. - - `handlePlanTask()` creates a pending task row only when absent, then updates planning fields and renders the task plan artifact, preserving idempotence for reruns against existing tasks. -observability_surfaces: - - "plan-slice.ts handler error payloads — structured failure messages for validation/DB/render failures returned in tool result" - - "plan-task.ts handler error payloads — structured failure messages for validation/missing-parent/render failures" - - "invalidateStateCache() + clearParseCache() after successful render — ensures callers see fresh state immediately" - - "parse-visible file state — rendered PLAN.md and task-plan files are reparseable proof of handler success" -duration: "" -verification_result: passed -completed_at: 2026-03-23T16:05:04.223Z -blocker_discovered: false ---- - -# T02: Implement DB-backed gsd_plan_slice and gsd_plan_task handlers with registrations and regression tests - -**Implement DB-backed gsd_plan_slice and gsd_plan_task handlers with registrations and regression tests** - -## What Happened - -Implemented the DB-backed slice/task planning write path for S02. I first verified the local contracts in `plan-milestone.ts`, `db-tools.ts`, `gsd-db.ts`, `markdown-renderer.ts`, and the existing renderer/handler tests, then patched the slice plan’s verification section with an explicit diagnostic check because the pre-flight called that gap out. Added `src/resources/extensions/gsd/tools/plan-slice.ts` and `src/resources/extensions/gsd/tools/plan-task.ts`, each mirroring the S01 pattern: flat validation, parent-slice existence checks, DB writes, renderer invocation, and cache invalidation only after successful render. In `gsd-db.ts` I added `upsertTaskPlanning()` and extended the planning record shape with optional title support so planning reruns update task planning fields without overwriting completion metadata. In `src/resources/extensions/gsd/bootstrap/db-tools.ts` I registered canonical `gsd_plan_slice` and `gsd_plan_task` tools plus aliases `gsd_slice_plan` and `gsd_task_plan`, with DB-availability checks and structured handler result payloads. Finally, I added focused regression suites in `src/resources/extensions/gsd/tests/plan-slice.test.ts` and `src/resources/extensions/gsd/tests/plan-task.test.ts` covering validation failures, missing-parent rejection, successful DB-backed renders, render-failure behavior, idempotent reruns, and parse-visible cache refresh behavior via reparsed plan artifacts. - -## Verification - -Verified the new handlers with the task’s targeted resolver-harness command for `plan-slice.test.ts` and `plan-task.test.ts`; all validation, parent-check, render-failure, idempotence, and parse-visible cache refresh assertions passed. Then ran the task’s second verification command against `plan-slice.test.ts`, `plan-task.test.ts`, and `markdown-renderer.test.ts` filtered to cache/idempotence/render-failure coverage; it passed and preserved truthful stale-render diagnostics on stderr. Finally ran the broader slice-level verification command including `markdown-renderer.test.ts`, `auto-recovery.test.ts`, and `prompt-contracts.test.ts` filtered to plan-slice/plan-task and DB-backed planning coverage; it passed, confirming the new handlers coexist with existing renderer/recovery/prompt contracts. - -## Verification Evidence - -| # | Command | Exit Code | Verdict | Duration | -|---|---------|-----------|---------|----------| -| 1 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts` | 0 | ✅ pass | 180ms | -| 2 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts src/resources/extensions/gsd/tests/markdown-renderer.test.ts --test-name-pattern="cache|idempotent|render failed|validation failed|plan-slice|plan-task"` | 0 | ✅ pass | 228ms | -| 3 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/auto-recovery.test.ts src/resources/extensions/gsd/tests/prompt-contracts.test.ts --test-name-pattern="plan-slice|plan-task|renderPlanFromDb|renderTaskPlanFromDb|task plan|DB-backed planning"` | 0 | ✅ pass | 731ms | - - -## Deviations - -Updated `.gsd/milestones/M001/slices/S02/S02-PLAN.md` with an explicit diagnostic verification command to satisfy the task pre-flight requirement. The implementation reused the existing DB schema and renderer contracts already present locally, so no broader replan was needed. I also added a narrow `upsertTaskPlanning()` DB helper instead of changing `insertTask()` semantics, because planning reruns must not clobber completion-state fields. - -## Known Issues - -None. - -## Diagnostics - -- **Handler test suite:** Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts` — 10 tests covering validation, parent checks, render failure, idempotence, and cache refresh. -- **Tool registration:** Check `db-tools.ts` for `gsd_plan_slice` and `gsd_plan_task` canonical names plus `gsd_slice_plan` and `gsd_task_plan` aliases. -- **DB query helpers:** `upsertTaskPlanning()` in `gsd-db.ts` — updates planning fields without clobbering completion state. -- **Handler error payloads:** Both handlers return structured `{ error: true, message: string }` on validation/DB/render failures, surfaced in tool result payloads. - -## Files Created/Modified - -- `.gsd/milestones/M001/slices/S02/S02-PLAN.md` -- `src/resources/extensions/gsd/tools/plan-slice.ts` -- `src/resources/extensions/gsd/tools/plan-task.ts` -- `src/resources/extensions/gsd/bootstrap/db-tools.ts` -- `src/resources/extensions/gsd/gsd-db.ts` -- `src/resources/extensions/gsd/tests/plan-slice.test.ts` -- `src/resources/extensions/gsd/tests/plan-task.test.ts` diff --git a/.gsd/milestones/M001/slices/S02/tasks/T02-VERIFY.json b/.gsd/milestones/M001/slices/S02/tasks/T02-VERIFY.json deleted file mode 100644 index d3e582f28..000000000 --- a/.gsd/milestones/M001/slices/S02/tasks/T02-VERIFY.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "schemaVersion": 1, - "taskId": "T02", - "unitId": "M001/S02/T02", - "timestamp": 1774281912502, - "passed": false, - "discoverySource": "package-json", - "checks": [ - { - "command": "npm run test", - "exitCode": 1, - "durationMs": 34647, - "verdict": "fail" - } - ], - "retryAttempt": 1, - "maxRetries": 2 -} diff --git a/.gsd/milestones/M001/slices/S02/tasks/T03-PLAN.md b/.gsd/milestones/M001/slices/S02/tasks/T03-PLAN.md deleted file mode 100644 index 0f73975f1..000000000 --- a/.gsd/milestones/M001/slices/S02/tasks/T03-PLAN.md +++ /dev/null @@ -1,53 +0,0 @@ ---- -estimated_steps: 4 -estimated_files: 4 -skills_used: - - create-gsd-extension - - test ---- - -# T03: Close prompt and contract coverage around DB-backed slice planning - -**Slice:** S02 — plan_slice + plan_task tools + PLAN/task-plan renderers -**Milestone:** M001 - -## Description - -Finish the slice by aligning the planning prompt surface with the new implementation. This task is intentionally smaller: once the renderer and handlers exist, the remaining risk is the LLM still being told to treat direct markdown writes as normal. Tighten the prompt wording and contract tests so the DB-backed slice/task planning route is the explicit expected behavior. - -## Steps - -1. Read the current planning prompt text in `src/resources/extensions/gsd/prompts/plan-slice.md` and the existing assertions in `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` and `src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts`. -2. Update `src/resources/extensions/gsd/prompts/plan-slice.md` to explicitly direct slice/task planning through `gsd_plan_slice` and `gsd_plan_task` when the tool path exists, while preserving the existing decomposition instructions and output requirements. -3. Extend prompt contract tests so they assert the new tool-backed instructions and reject regressions back to manual `PLAN.md` / task-plan writes as the intended source of truth. -4. Update prompt template tests if needed so variable substitution and template integrity still pass with the new instructions. - -## Must-Haves - -- [ ] `plan-slice.md` explicitly points planning at `gsd_plan_slice` / `gsd_plan_task` instead of only warning about direct `PLAN.md` writes. -- [ ] Prompt contract tests fail if the DB-backed slice/task planning tool instructions regress. -- [ ] Prompt template tests still pass after the wording change. - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts --test-name-pattern="plan-slice|plan task|DB-backed"` -- Read the relevant assertions in `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` to confirm they mention `gsd_plan_slice` / `gsd_plan_task`. - -## Inputs - -- `src/resources/extensions/gsd/prompts/plan-slice.md` — current slice planning prompt -- `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` — prompt regression contract tests -- `src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts` — template substitution/integrity tests -- `src/resources/extensions/gsd/bootstrap/db-tools.ts` — canonical tool names to reference in the prompt/tests - -## Expected Output - -- `src/resources/extensions/gsd/prompts/plan-slice.md` — updated DB-backed slice/task planning instructions -- `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` — stronger prompt contract coverage for `gsd_plan_slice` / `gsd_plan_task` -- `src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts` — updated template tests if prompt wording changes affect expectations - -## Observability Impact - -- **Signals changed:** The planning prompt now explicitly names `gsd_plan_slice` and `gsd_plan_task` tools, so any agent following the prompt will emit structured tool calls instead of raw file writes — making planning actions observable via tool-call logs rather than implicit file-write patterns. -- **Inspection surface:** `prompt-contracts.test.ts` assertions referencing the canonical tool names serve as the regression tripwire; if the prompt text drifts back to manual-write instructions, these tests fail immediately. -- **Failure visibility:** A regression in the prompt wording (removing tool references or re-introducing manual write instructions) is caught by the contract tests before it reaches production prompt surfaces. diff --git a/.gsd/milestones/M001/slices/S02/tasks/T03-SUMMARY.md b/.gsd/milestones/M001/slices/S02/tasks/T03-SUMMARY.md deleted file mode 100644 index fcdf1ad23..000000000 --- a/.gsd/milestones/M001/slices/S02/tasks/T03-SUMMARY.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -id: T03 -parent: S02 -milestone: M001 -key_files: - - src/resources/extensions/gsd/prompts/plan-slice.md - - src/resources/extensions/gsd/tests/prompt-contracts.test.ts - - src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts - - .gsd/milestones/M001/slices/S02/tasks/T03-PLAN.md -key_decisions: - - The plan-slice prompt now uses `gsd_plan_slice` and `gsd_plan_task` as the primary numbered step (step 6) instead of a conditional afterthought (old step 8), with direct file writes explicitly labeled as a degraded fallback (step 7). -observability_surfaces: - - "prompt-contracts.test.ts — 4 new assertions for plan-slice prompt DB-backed tool references, degraded-fallback framing, and per-task tool call instruction" - - "plan-slice-prompt.test.ts — template substitution test proving tool names survive variable replacement" - - "plan-slice.md prompt text — explicit step 6 naming gsd_plan_slice/gsd_plan_task as canonical path" -duration: "" -verification_result: passed -completed_at: 2026-03-23T16:08:41.655Z -blocker_discovered: false ---- - -# T03: Update plan-slice prompt to explicitly name gsd_plan_slice/gsd_plan_task as canonical write path, add prompt contract and template regression tests - -**Update plan-slice prompt to explicitly name gsd_plan_slice/gsd_plan_task as canonical write path, add prompt contract and template regression tests** - -## What Happened - -Updated `src/resources/extensions/gsd/prompts/plan-slice.md` to replace the vague "if the tool path for this planning phase is available" language with explicit instructions naming `gsd_plan_slice` and `gsd_plan_task` as the canonical DB-backed write path for slice and task planning. The new step 6 instructs calling `gsd_plan_slice` with the full payload and `gsd_plan_task` for each task. Step 7 positions direct file writes as an explicitly degraded fallback path only used when the tools are unavailable, not the default. Removed the old step 8 that vaguely referenced "the tool path" and fixed step numbering. - -Added 4 new prompt contract tests in `prompt-contracts.test.ts`: one verifying both tool names appear and the "canonical write path" language is present, one verifying direct file writes are framed as "degraded path, not the default", one verifying the prompt no longer has a bare "Write `{{outputPath}}`" as a primary numbered step, and one verifying the prompt instructs calling `gsd_plan_task` for each task. - -Added 1 new template substitution test in `plan-slice-prompt.test.ts` confirming the tool names and canonical language survive variable substitution. - -Also applied the task-plan pre-flight fix by adding an `## Observability Impact` section to T03-PLAN.md explaining how the prompt change makes planning actions observable via tool-call logs and how the contract tests serve as regression tripwires. - -## Verification - -Ran all three slice-level verification commands: (1) plan-slice.test.ts + plan-task.test.ts — 10/10 pass, (2) markdown-renderer.test.ts + auto-recovery.test.ts + prompt-contracts.test.ts filtered to planning patterns — 60/60 pass, (3) plan-slice.test.ts + plan-task.test.ts filtered to failure/cache/validation — 10/10 pass. Also ran the task-level verification command (prompt-contracts.test.ts + plan-slice-prompt.test.ts filtered to plan-slice|plan task|DB-backed) — 40/40 pass. Read back the prompt-contracts.test.ts assertions and confirmed they explicitly reference gsd_plan_slice and gsd_plan_task. - -## Verification Evidence - -| # | Command | Exit Code | Verdict | Duration | -|---|---------|-----------|---------|----------| -| 1 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts --test-name-pattern="plan-slice|plan task|DB-backed"` | 0 | ✅ pass | 126ms | -| 2 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts` | 0 | ✅ pass | 180ms | -| 3 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/auto-recovery.test.ts src/resources/extensions/gsd/tests/prompt-contracts.test.ts --test-name-pattern="plan-slice|plan-task|renderPlanFromDb|renderTaskPlanFromDb|task plan|DB-backed planning"` | 0 | ✅ pass | 695ms | -| 4 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts --test-name-pattern="validation failed|render failed|cache|missing parent"` | 0 | ✅ pass | 180ms | - - -## Deviations - -None. - -## Known Issues - -None. - -## Diagnostics - -- **Prompt contract tests:** Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts --test-name-pattern="plan-slice"` — verifies tool names, degraded-fallback framing, and per-task instruction in the prompt. -- **Template substitution test:** Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts` — confirms DB-backed tool names survive variable substitution. -- **Prompt source:** Read `src/resources/extensions/gsd/prompts/plan-slice.md` — step 6 names `gsd_plan_slice` and `gsd_plan_task` as canonical; step 7 is degraded fallback. - -## Files Created/Modified - -- `src/resources/extensions/gsd/prompts/plan-slice.md` -- `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` -- `src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts` -- `.gsd/milestones/M001/slices/S02/tasks/T03-PLAN.md` diff --git a/.gsd/milestones/M001/slices/S02/tasks/T03-VERIFY.json b/.gsd/milestones/M001/slices/S02/tasks/T03-VERIFY.json deleted file mode 100644 index c488831cd..000000000 --- a/.gsd/milestones/M001/slices/S02/tasks/T03-VERIFY.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "schemaVersion": 1, - "taskId": "T03", - "unitId": "M001/S02/T03", - "timestamp": 1774282125185, - "passed": false, - "discoverySource": "package-json", - "checks": [ - { - "command": "npm run test", - "exitCode": 1, - "durationMs": 39009, - "verdict": "fail" - } - ], - "retryAttempt": 1, - "maxRetries": 2 -} diff --git a/.gsd/milestones/M001/slices/S03/S03-PLAN.md b/.gsd/milestones/M001/slices/S03/S03-PLAN.md deleted file mode 100644 index b67657668..000000000 --- a/.gsd/milestones/M001/slices/S03/S03-PLAN.md +++ /dev/null @@ -1,91 +0,0 @@ -# S03: replan_slice + reassess_roadmap with structural enforcement - -**Goal:** `gsd_replan_slice` rejects mutations to completed tasks, `gsd_reassess_roadmap` rejects mutations to completed slices. Both write to DB tables (replan_history, assessments), render REPLAN.md/ASSESSMENT.md from DB, and re-render PLAN.md/ROADMAP.md after mutations. -**Demo:** Tests prove that calling replan with a completed task ID returns a structural rejection error, while modifying only incomplete tasks succeeds. Similarly, calling reassess with a completed slice ID returns a rejection error, while modifying only pending slices succeeds. Rendered REPLAN.md and ASSESSMENT.md artifacts exist on disk. Prompts name `gsd_replan_slice` and `gsd_reassess_roadmap` as the canonical tool paths. - -## Must-Haves - -- `handleReplanSlice` structurally rejects mutations (update or remove) to completed tasks -- `handleReplanSlice` writes `replan_history` row, applies task mutations, re-renders PLAN.md + task plans, renders REPLAN.md -- `handleReassessRoadmap` structurally rejects mutations (modify or remove) to completed slices -- `handleReassessRoadmap` writes `assessments` row, applies slice mutations, re-renders ROADMAP.md, renders ASSESSMENT.md -- Both handlers follow validate → enforce → transaction → render → invalidate pattern -- Both handlers invalidate state cache and parse cache after success -- `replan-slice.md` and `reassess-roadmap.md` prompts name the new tools as canonical write path -- Prompt contract tests assert tool name presence in both prompts -- DB helper functions: `insertReplanHistory()`, `insertAssessment()`, `deleteTask()`, `deleteSlice()` -- Renderers: `renderReplanFromDb()`, `renderAssessmentFromDb()` - -## Proof Level - -- This slice proves: contract -- Real runtime required: no -- Human/UAT required: no - -## Verification - -```bash -# Primary proof — replan handler: validation, structural enforcement, DB writes, rendering -node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/replan-handler.test.ts - -# Primary proof — reassess handler: validation, structural enforcement, DB writes, rendering -node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/reassess-handler.test.ts - -# Prompt contracts — verify prompts reference new tool names -node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts - -# Full regression — existing tests still pass -node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/rogue-file-detection.test.ts - -# Diagnostic — verify structured error payloads name specific task/slice IDs in rejection messages -# (covered by replan-handler.test.ts "structured error payloads" and reassess-handler.test.ts equivalents) -grep -c "structured error payloads" src/resources/extensions/gsd/tests/replan-handler.test.ts src/resources/extensions/gsd/tests/reassess-handler.test.ts -``` - -## Observability / Diagnostics - -- Runtime signals: Handler error payloads include structured rejection messages naming the specific completed task/slice IDs that blocked the mutation -- Inspection surfaces: `replan_history` and `assessments` DB tables can be queried directly; rendered REPLAN.md and ASSESSMENT.md artifacts on disk -- Failure visibility: Validation errors, structural rejection errors, render failures all return distinct `{ error: string }` payloads with actionable messages - -## Integration Closure - -- Upstream surfaces consumed: `gsd-db.ts` query functions (`getSliceTasks`, `getTask`, `getSlice`, `getMilestoneSlices`, `getMilestone`), `gsd-db.ts` mutation functions (`upsertTaskPlanning`, `upsertSlicePlanning`, `insertTask`, `insertSlice`, `transaction`), `markdown-renderer.ts` renderers (`renderPlanFromDb`, `renderRoadmapFromDb`, `writeAndStore` pattern), `files.ts` (`clearParseCache`), `state.ts` (`invalidateStateCache`) -- New wiring introduced in this slice: `tools/replan-slice.ts` and `tools/reassess-roadmap.ts` handler modules, tool registrations in `db-tools.ts`, prompt template references to `gsd_replan_slice` and `gsd_reassess_roadmap` -- What remains before the milestone is truly usable end-to-end: S04 hot-path caller migration, S05 flag file migration, S06 parser deprecation - -## Tasks - -- [x] **T01: Implement replan_slice handler with structural enforcement** `est:1h` - - Why: Delivers R005 — the core replan handler that queries DB for completed tasks and structurally rejects mutations to them. Also adds required DB helpers (`insertReplanHistory`, `deleteTask`, `deleteSlice`) and the REPLAN.md renderer that all downstream work depends on. - - Files: `src/resources/extensions/gsd/gsd-db.ts`, `src/resources/extensions/gsd/tools/replan-slice.ts`, `src/resources/extensions/gsd/markdown-renderer.ts`, `src/resources/extensions/gsd/tests/replan-handler.test.ts` - - Do: (1) Add `insertReplanHistory()`, `insertAssessment()`, `deleteTask()`, `deleteSlice()` to `gsd-db.ts`. `deleteTask` must first delete from `verification_evidence` (FK constraint) before deleting the task row. `deleteSlice` must delete all child tasks' evidence, then child tasks, then the slice. (2) Add `renderReplanFromDb()` and `renderAssessmentFromDb()` to `markdown-renderer.ts` — both use `writeAndStore()` pattern. REPLAN.md should contain the blocker description, what changed, and the updated task list. ASSESSMENT.md should contain the verdict, assessment text, and slice changes. (3) Create `tools/replan-slice.ts` with `handleReplanSlice()`. Params: milestoneId, sliceId, blockerTaskId, blockerDescription, whatChanged, updatedTasks array (taskId, title, description, estimate, files, verify, inputs, expectedOutput), removedTaskIds array. Validate flat params. Query `getSliceTasks()` for completed tasks (status === 'complete' or 'done'). Reject if any updatedTasks[].taskId or removedTaskIds element matches a completed task. In transaction: write replan_history row, apply task mutations (upsert updated tasks via insertTask+upsertTaskPlanning, delete removed tasks), insert new tasks. After transaction: re-render PLAN.md via `renderPlanFromDb()`, render REPLAN.md via `renderReplanFromDb()`, invalidate caches. (4) Write `tests/replan-handler.test.ts` using `node:test` and the same pattern as `plan-slice.test.ts`. Tests must prove: validation failures, structural rejection of completed task update, structural rejection of completed task removal, successful replan modifying only incomplete tasks, replan_history row persistence, re-rendered PLAN.md correctness, REPLAN.md existence, cache invalidation via parse-visible state. - - Verify: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/replan-handler.test.ts` - - Done when: All replan handler tests pass, including structural rejection of completed-task mutations and successful replan of incomplete tasks with DB persistence and rendered artifacts. - -- [x] **T02: Implement reassess_roadmap handler with structural enforcement** `est:45m` - - Why: Delivers R006 — the reassess handler that queries DB for completed slices and structurally rejects mutations to them. Reuses DB helpers from T01 and the ASSESSMENT.md renderer. - - Files: `src/resources/extensions/gsd/tools/reassess-roadmap.ts`, `src/resources/extensions/gsd/tests/reassess-handler.test.ts` - - Do: (1) Create `tools/reassess-roadmap.ts` with `handleReassessRoadmap()`. Params: milestoneId, completedSliceId (the slice that just finished), verdict, assessment (text), sliceChanges object with: modified array (sliceId, title, risk, depends, demo), added array (same shape), removed array (sliceId strings). Validate flat params. Query `getMilestoneSlices()` for completed slices (status === 'complete' or 'done'). Reject if any modified[].sliceId or removed[] element matches a completed slice. In transaction: write assessments row (path as PK = ASSESSMENT.md artifact path, milestone_id, status=verdict, scope='roadmap', full_content=assessment text), apply slice mutations (upsert modified via `upsertSlicePlanning`, insert added via `insertSlice`, delete removed via `deleteSlice`). After transaction: re-render ROADMAP.md via `renderRoadmapFromDb()`, render ASSESSMENT.md via `renderAssessmentFromDb()`, invalidate caches. (2) Write `tests/reassess-handler.test.ts` using `node:test`. Tests must prove: validation failures, structural rejection of completed slice modification, structural rejection of completed slice removal, successful reassess modifying only pending slices, assessments row persistence, re-rendered ROADMAP.md correctness, ASSESSMENT.md existence, cache invalidation. - - Verify: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/reassess-handler.test.ts` - - Done when: All reassess handler tests pass, including structural rejection of completed-slice mutations and successful reassess with DB persistence and rendered artifacts. - -- [x] **T03: Register tools in db-tools.ts + update prompts + prompt contract tests** `est:30m` - - Why: Connects the handlers to the tool system so auto-mode dispatch can invoke them, and updates prompts to name the tools as canonical write paths. Extends prompt contract tests to catch regressions. - - Files: `src/resources/extensions/gsd/bootstrap/db-tools.ts`, `src/resources/extensions/gsd/prompts/replan-slice.md`, `src/resources/extensions/gsd/prompts/reassess-roadmap.md`, `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` - - Do: (1) Register `gsd_replan_slice` in `db-tools.ts` following the exact pattern of `gsd_plan_slice` — ensureDbOpen check, dynamic import of `../tools/replan-slice.js`, call `handleReplanSlice(params, process.cwd())`, return structured content/details. TypeBox schema matches handler params. Register alias `gsd_slice_replan`. (2) Register `gsd_reassess_roadmap` with alias `gsd_roadmap_reassess` — same pattern, dynamic import of `../tools/reassess-roadmap.js`, call `handleReassessRoadmap(params, process.cwd())`. (3) Update `replan-slice.md` prompt: add a step before the existing file-write instructions that says to use `gsd_replan_slice` tool as the canonical write path when DB-backed tools are available. Position the existing file-write instructions as degraded fallback. Name the specific tool and its parameters. (4) Update `reassess-roadmap.md` prompt: similarly add `gsd_reassess_roadmap` as canonical path. The prompt already has "Do not bypass state with manual roadmap-only edits" — strengthen by naming the specific tool. (5) Add prompt contract tests in `prompt-contracts.test.ts`: assert `replan-slice.md` contains `gsd_replan_slice`, assert `reassess-roadmap.md` contains `gsd_reassess_roadmap`. - - Verify: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts` - - Done when: Both tools are registered with aliases, both prompts name the canonical tools, and prompt contract tests pass. - -## Files Likely Touched - -- `src/resources/extensions/gsd/gsd-db.ts` -- `src/resources/extensions/gsd/markdown-renderer.ts` -- `src/resources/extensions/gsd/tools/replan-slice.ts` (new) -- `src/resources/extensions/gsd/tools/reassess-roadmap.ts` (new) -- `src/resources/extensions/gsd/bootstrap/db-tools.ts` -- `src/resources/extensions/gsd/prompts/replan-slice.md` -- `src/resources/extensions/gsd/prompts/reassess-roadmap.md` -- `src/resources/extensions/gsd/tests/replan-handler.test.ts` (new) -- `src/resources/extensions/gsd/tests/reassess-handler.test.ts` (new) -- `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` diff --git a/.gsd/milestones/M001/slices/S03/S03-RESEARCH.md b/.gsd/milestones/M001/slices/S03/S03-RESEARCH.md deleted file mode 100644 index 97aa0b680..000000000 --- a/.gsd/milestones/M001/slices/S03/S03-RESEARCH.md +++ /dev/null @@ -1,111 +0,0 @@ -# S03 — Research - -**Date:** 2026-03-23 -**Status:** Ready for planning - -## Summary - -S03 delivers two new tool handlers — `handleReplanSlice` and `handleReassessRoadmap` — that structurally enforce preservation of completed work. The core novelty is **structural rejection**: the replan handler queries the DB for completed tasks and refuses to accept mutations to them, while the reassess handler queries for completed slices and refuses mutations to them. Both write to the existing `replan_history` and `assessments` tables created in S01's schema v8 migration. Both render markdown artifacts (REPLAN.md, ASSESSMENT.md, and re-rendered PLAN.md/ROADMAP.md) from DB state. - -This is straightforward application of the S01/S02 handler pattern (validate → check completed state → transaction → render → invalidate) with one meaningful new dimension: the structural enforcement logic that inspects task/slice status before accepting writes. The schema tables already exist. The rendering infrastructure already exists. The prompt templates already have placeholder language about DB-backed tools. The registration pattern is established in `db-tools.ts`. - -## Recommendation - -Follow the exact handler pattern from `plan-slice.ts` and `plan-task.ts`. The two tools have different shapes but identical control flow: - -1. **`handleReplanSlice`** — accepts milestoneId, sliceId, blockerTaskId, blockerDescription, whatChanged, updatedTasks (array), removedTaskIds (array). Queries `getSliceTasks()` to find completed tasks. Rejects if any `updatedTasks[].taskId` matches a completed task. Rejects if any `removedTaskIds` element matches a completed task. Writes `replan_history` row. Applies task mutations (upsert updated, delete removed, insert new). Re-renders PLAN.md and task plans. Renders REPLAN.md. Invalidates caches. - -2. **`handleReassessRoadmap`** — accepts milestoneId, completedSliceId, verdict, assessment, sliceChanges (modified/added/removed/reordered arrays). Queries `getMilestoneSlices()` to find completed slices. Rejects if any modified/removed/reordered slice is completed. Writes `assessments` row. Applies slice mutations (upsert modified, insert added, delete removed, reorder). Re-renders ROADMAP.md. Renders ASSESSMENT.md. Invalidates caches. - -Build order: DB helpers first (insert functions for replan_history and assessments, plus a `deleteTask` function), then handlers, then renderers for REPLAN.md and ASSESSMENT.md, then prompt updates, then tests. Tests are the primary proof surface — they must demonstrate structural rejection of completed-work mutations. - -## Implementation Landscape - -### Key Files - -- `src/resources/extensions/gsd/gsd-db.ts` (1505 lines) — Needs new functions: `insertReplanHistory()`, `insertAssessment()`, `deleteTask()`, `deleteSlice()`, and `updateSliceSequence()` (for reordering). The `replan_history` and `assessments` tables already exist (created in S01 schema v8 migration at lines 321–347). Current exports include `getSliceTasks()`, `getTask()`, `getSlice()`, `getMilestoneSlices()` which provide the completed-state queries. `upsertTaskPlanning()` and `upsertSlicePlanning()` handle mutations to existing rows. `insertTask()` and `insertSlice()` use `INSERT OR IGNORE` — safe for idempotent reruns. - -- `src/resources/extensions/gsd/tools/plan-slice.ts` — Reference handler pattern for replan. Shows validate → parent check → transaction → render → cache invalidation flow. The replan handler follows this pattern but adds: (a) completed-task enforcement before writes, (b) task deletion for removedTaskIds, (c) REPLAN.md rendering. - -- `src/resources/extensions/gsd/tools/plan-milestone.ts` — Reference handler pattern for reassess. Shows how milestone-level mutations work through `upsertMilestonePlanning()` and `upsertSlicePlanning()`, followed by `renderRoadmapFromDb()`. - -- `src/resources/extensions/gsd/markdown-renderer.ts` (currently ~840 lines) — Needs two new renderers: `renderReplanFromDb()` for REPLAN.md and `renderAssessmentFromDb()` for ASSESSMENT.md. Both use the existing `writeAndStore()` helper. Also needs a `renderReplanedPlanFromDb()` or can reuse `renderPlanFromDb()` directly since it reads from DB state (which will already reflect the mutations). The existing `renderPlanFromDb()` already handles completed vs incomplete tasks correctly in its checkbox rendering (`task.status === "done" || task.status === "complete"` → `[x]`). - -- `src/resources/extensions/gsd/tools/replan-slice.ts` — **New file.** Handler for `gsd_replan_slice`. Flat params, structural enforcement, DB writes, render, cache invalidation. - -- `src/resources/extensions/gsd/tools/reassess-roadmap.ts` — **New file.** Handler for `gsd_reassess_roadmap`. Flat params, structural enforcement, DB writes, render, cache invalidation. - -- `src/resources/extensions/gsd/bootstrap/db-tools.ts` — Register both new tools following the exact pattern used for `gsd_plan_slice` (lines 386–461). Each gets a canonical name (`gsd_replan_slice`, `gsd_reassess_roadmap`) and an alias (`gsd_slice_replan`, `gsd_roadmap_reassess`). - -- `src/resources/extensions/gsd/prompts/replan-slice.md` — Currently instructs direct file writes to `{{replanPath}}` and `{{planPath}}`. Must be updated to instruct `gsd_replan_slice` tool call as canonical path, with direct writes as degraded fallback. The prompt already has a line about DB-backed planning tools (from S01 updates) but doesn't name the specific tool yet. - -- `src/resources/extensions/gsd/prompts/reassess-roadmap.md` — Currently instructs direct writes to `{{assessmentPath}}` and optionally `{{roadmapPath}}`. Must be updated to instruct `gsd_reassess_roadmap` tool call as canonical path. Already has "Do not bypass state with manual roadmap-only edits" language. - -- `src/resources/extensions/gsd/tests/replan-slice.test.ts` — **New file.** Must prove: validation failures, structural rejection of completed task mutations, DB write correctness, REPLAN.md rendering, PLAN.md re-rendering, cache invalidation, idempotent reruns. - -- `src/resources/extensions/gsd/tests/reassess-roadmap.test.ts` — **New file.** Must prove: validation failures, structural rejection of completed slice mutations, DB write correctness, ASSESSMENT.md rendering, ROADMAP.md re-rendering, cache invalidation, idempotent reruns. - -- `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` — Extend with assertions for replan-slice and reassess-roadmap prompts referencing the new tool names. - -### Build Order - -1. **DB helpers first** — `insertReplanHistory()`, `insertAssessment()`, `deleteTask()`, `deleteSlice()` in `gsd-db.ts`. These are pure DB functions with no rendering dependency. They unblock the handlers. - -2. **Renderers** — `renderReplanFromDb()` and `renderAssessmentFromDb()` in `markdown-renderer.ts`. These are simple markdown generators that write REPLAN.md and ASSESSMENT.md via `writeAndStore()`. They don't need the handlers to exist. Note: PLAN.md and ROADMAP.md re-rendering already works via existing `renderPlanFromDb()` and `renderRoadmapFromDb()`. - -3. **Handlers** — `handleReplanSlice` and `handleReassessRoadmap` in new tool files. These combine the DB helpers and renderers with the structural enforcement logic. This is where the core proof logic lives. - -4. **Registration + Prompts** — Register in `db-tools.ts`, update prompt templates to name the tools. - -5. **Tests** — Can be written alongside handlers or after. They are the primary proof surface for R005 and R006. - -### Verification Approach - -```bash -# Primary proof — replan handler: validation, structural enforcement, DB writes, rendering -node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/replan-slice.test.ts - -# Primary proof — reassess handler: validation, structural enforcement, DB writes, rendering -node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/reassess-roadmap.test.ts - -# Prompt contracts — verify prompts reference new tool names -node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts - -# Full regression — existing tests still pass -node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/rogue-file-detection.test.ts -``` - -Key test scenarios to prove: - -- **R005 structural enforcement**: seed a slice with T01 (complete), T02 (complete), T03 (pending). Call replan with an updatedTask targeting T01. Assert error containing "completed task" or similar. Call replan with removedTaskIds including T02. Assert error. Call replan modifying only T03 and adding T04. Assert success. - -- **R006 structural enforcement**: seed a milestone with S01 (complete), S02 (pending), S03 (pending). Call reassess with a modified slice targeting S01. Assert error. Call reassess modifying only S02 and adding S04. Assert success. - -- **Replan history persistence**: after successful replan, query `replan_history` table and verify a row exists with correct milestone_id, slice_id, summary. - -- **Assessment persistence**: after successful reassess, query `assessments` table and verify a row exists with correct path, milestone_id, status, full_content. - -- **Re-rendering correctness**: after replan, read the rendered PLAN.md back from disk, parse it, confirm completed tasks still show `[x]` and new/modified tasks appear correctly. - -- **Cache invalidation**: use parse-visible state assertions (read roadmap/plan before and after handler execution, confirm the parse results reflect the mutations). - -## Constraints - -- `replan_history` schema has columns: `id` (autoincrement), `milestone_id`, `slice_id`, `task_id`, `summary`, `previous_artifact_path`, `replacement_artifact_path`, `created_at`. The handler must populate these — `previous_artifact_path` is the old PLAN.md artifact path and `replacement_artifact_path` is the new one. -- `assessments` schema has columns: `path` (PK), `milestone_id`, `slice_id`, `task_id`, `status`, `scope`, `full_content`, `created_at`. The `path` is the ASSESSMENT.md artifact path, used as primary key — idempotent rewrites via INSERT OR REPLACE. -- No existing `deleteTask()` or `deleteSlice()` function in `gsd-db.ts` — these must be added. Must be careful with foreign key constraints (verification_evidence references tasks). -- `insertSlice()` uses `INSERT OR IGNORE` — safe for idempotent runs but won't update existing slice data. For reassess modifications to existing slices, use `upsertSlicePlanning()` plus a new `updateSliceMetadata()` or similar for title/risk/depends/demo changes. -- The resolver-based TypeScript test harness (`resolve-ts.mjs`) is required — bare `node --test` may fail on `.js` sibling specifiers. -- Cache invalidation must use parse-visible state assertions, not ESM monkey-patching (per KNOWLEDGE.md). - -## Common Pitfalls - -- **Foreign key cascading on task deletion** — The `verification_evidence` table has a foreign key referencing `tasks(milestone_id, slice_id, id)`. Deleting a task without handling this will fail. Use `DELETE FROM verification_evidence WHERE ...` before `DELETE FROM tasks WHERE ...`, or set up CASCADE in the FK (but the schema is already created without CASCADE, so the handler must delete evidence first). -- **Slice deletion vs slice reordering** — Reassess needs to distinguish between removing a slice entirely (DELETE from DB) and reordering slices (no deletion, just update sequence). The current schema doesn't have a `sequence` column — ordering is by `id` (`ORDER BY id`). If reassess reorders, it must either rename slice IDs (risky — breaks references) or add a sequence column. The simpler approach: don't support arbitrary reordering in V1 — just support add/remove/modify. Reordering can be deferred or handled by deleting and re-inserting with new IDs. But since task completions reference slice IDs, deleting completed slices is forbidden anyway, so reordering of completed slices is moot. -- **REPLAN.md path resolution** — The current `buildReplanPrompt` in `auto-prompts.ts` constructs `replanPath` as `join(base, relSlicePath(base, mid, sid) + "/" + sid + "-REPLAN.md")`. The renderer must use the same path construction pattern, or better, use `resolveSliceFile()` with the "REPLAN" suffix if it's supported — check `paths.ts` for supported suffixes. -- **Assessment path as PK** — The `assessments` table uses `path TEXT PRIMARY KEY`, which means the path must be deterministic and consistent. The current `buildReassessPrompt` uses `relSliceFile(base, mid, completedSliceId, "ASSESSMENT")` — the handler must compute the same path. - -## Open Risks - -- The `replan_history.task_id` column is nullable — it's not clear from the schema whether this tracks a specific blocker task or the entire replan event. R005 specifies `blockerTaskId` as a parameter, so this maps to `task_id` in the replan_history row. The handler should populate it. -- Reassess `sliceChanges.reordered` may be complex to implement without a sequence column. The pragmatic choice is to accept reorder directives but only apply them as metadata (not changing actual query ordering since `ORDER BY id` is used throughout). If the planner decides to skip reordering support in V1, this is acceptable since the milestone DoD says "replan and reassess structurally enforce preservation" — it doesn't mandate reordering support. diff --git a/.gsd/milestones/M001/slices/S03/S03-SUMMARY.md b/.gsd/milestones/M001/slices/S03/S03-SUMMARY.md deleted file mode 100644 index b714b61fa..000000000 --- a/.gsd/milestones/M001/slices/S03/S03-SUMMARY.md +++ /dev/null @@ -1,131 +0,0 @@ ---- -id: S03 -parent: M001 -milestone: M001 -provides: - - handleReplanSlice() — structural enforcement of completed tasks during replanning - - handleReassessRoadmap() — structural enforcement of completed slices during reassessment - - replan_history table populated with actual replan events - - assessments table populated with actual assessments - - REPLAN.md and ASSESSMENT.md rendered from DB (flag file equivalents for S05) - - gsd_replan_slice and gsd_reassess_roadmap registered in db-tools.ts with aliases - - DB helpers: insertReplanHistory(), insertAssessment(), deleteTask(), deleteSlice(), updateSliceFields(), getReplanHistory(), getAssessment() - - Renderers: renderReplanFromDb(), renderAssessmentFromDb() -requires: - - slice: S01 - provides: Schema v8 tables (replan_history, assessments), tool handler pattern from plan-milestone.ts, renderRoadmapFromDb() - - slice: S02 - provides: getSliceTasks(), getTask(), upsertTaskPlanning(), insertTask(), insertSlice(), renderPlanFromDb(), renderTaskPlanFromDb() -affects: - - S05 -key_files: - - src/resources/extensions/gsd/tools/replan-slice.ts - - src/resources/extensions/gsd/tools/reassess-roadmap.ts - - src/resources/extensions/gsd/gsd-db.ts - - src/resources/extensions/gsd/markdown-renderer.ts - - src/resources/extensions/gsd/bootstrap/db-tools.ts - - src/resources/extensions/gsd/prompts/replan-slice.md - - src/resources/extensions/gsd/prompts/reassess-roadmap.md - - src/resources/extensions/gsd/tests/replan-handler.test.ts - - src/resources/extensions/gsd/tests/reassess-handler.test.ts - - src/resources/extensions/gsd/tests/prompt-contracts.test.ts -key_decisions: - - deleteTask() cascades through verification_evidence before task row (no ON DELETE CASCADE in schema) — manual FK-aware deletion pattern - - updateSliceFields() added separately from upsertSlicePlanning() to keep planning-level vs metadata-level DB APIs distinct - - Structural enforcement checks both 'complete' and 'done' statuses as completed indicators — covers both status variants -patterns_established: - - Structural enforcement pattern: query completed items → build Set → reject before transaction if any mutation targets completed items → return { error } naming specific ID - - Handler error payloads include the specific entity ID that blocked the mutation — actionable diagnostics, not generic messages - - Manual cascade deletion pattern for FK-constrained tables (evidence → tasks → slice) since schema lacks ON DELETE CASCADE -observability_surfaces: - - replan_history DB table — queryable via getReplanHistory(db, milestoneId, sliceId) - - assessments DB table — queryable via getAssessment(db, path) - - REPLAN.md on disk — rendered at slices/S##/REPLAN.md with blocker description and mutation details - - ASSESSMENT.md on disk — rendered at slices/S##/ASSESSMENT.md with verdict and assessment text - - Handler error payloads — { error: string } naming the specific completed task/slice ID that blocked a mutation -drill_down_paths: - - .gsd/milestones/M001/slices/S03/tasks/T01-SUMMARY.md - - .gsd/milestones/M001/slices/S03/tasks/T02-SUMMARY.md - - .gsd/milestones/M001/slices/S03/tasks/T03-SUMMARY.md -duration: "" -verification_result: passed -completed_at: 2026-03-23T16:40:55.867Z -blocker_discovered: false ---- - -# S03: replan_slice + reassess_roadmap with structural enforcement - -**Delivered gsd_replan_slice and gsd_reassess_roadmap tools with structural enforcement that prevents mutations to completed tasks/slices, backed by DB persistence (replan_history, assessments tables) and rendered REPLAN.md/ASSESSMENT.md artifacts.** - -## What Happened - -S03 built the final two planning tools that complete the structural enforcement layer for the planning state machine. - -**T01 — replan_slice handler:** Implemented `handleReplanSlice()` with the validate → enforce → transaction → render → invalidate pattern. Added four DB helpers to `gsd-db.ts`: `insertReplanHistory()`, `insertAssessment()`, `deleteTask()` (with FK-aware cascade through verification_evidence), and `deleteSlice()` (cascade: evidence → tasks → slice). Added `renderReplanFromDb()` and `renderAssessmentFromDb()` to `markdown-renderer.ts` using the `writeAndStore()` pattern. The handler queries `getSliceTasks()`, builds a Set of completed task IDs (status 'complete' or 'done'), and returns a structured `{ error }` naming the specific task ID if any mutation targets a completed task. On success: writes replan_history row, applies task upserts/inserts/deletes in a transaction, then re-renders PLAN.md and writes REPLAN.md. 9 tests cover validation, structural rejection (both update and remove), success path with DB persistence, cache invalidation, idempotency, missing parent, "done" alias, and structured error payloads. - -**T02 — reassess_roadmap handler:** Implemented `handleReassessRoadmap()` with the same pattern at the milestone/slice level. Added `updateSliceFields()` to `gsd-db.ts` for title/risk/depends/demo updates (distinct from `upsertSlicePlanning()` which handles planning-level fields). Added `getAssessment()` query helper. The handler queries `getMilestoneSlices()` for completed slices and rejects modifications or removals to them. On success: writes assessments row, applies slice modifications/additions/deletions in a transaction, then re-renders ROADMAP.md and writes ASSESSMENT.md. 9 matching tests. - -**T03 — Tool registration + prompts:** Registered `gsd_replan_slice` (alias `gsd_slice_replan`) and `gsd_reassess_roadmap` (alias `gsd_roadmap_reassess`) in `db-tools.ts` with TypeBox schemas matching handler params. Updated `replan-slice.md` and `reassess-roadmap.md` prompts to position the DB-backed tools as canonical write paths with direct file writes as degraded fallback. Extended `prompt-contracts.test.ts` to 28 tests including 2 new tool-name assertions. - -All verification passed: 9/9 replan tests, 9/9 reassess tests, 28/28 prompt contract tests, 25/25 regression tests. - -## Verification - -All slice-level verification checks from the plan passed: - -1. **Replan handler tests** (9/9 pass, ~337ms): validation failures, structural rejection of completed task update, structural rejection of completed task removal, successful replan with DB persistence, cache invalidation, idempotency, missing parent slice, "done" status alias, structured error payloads. - -2. **Reassess handler tests** (9/9 pass, ~322ms): validation failures, missing milestone, structural rejection of completed slice modification, structural rejection of completed slice removal, successful reassess with DB persistence, cache invalidation, idempotency, "done" status alias, structured error payloads. - -3. **Prompt contract tests** (28/28 pass, ~205ms): includes 2 new assertions that replan-slice.md contains `gsd_replan_slice` and reassess-roadmap.md contains `gsd_reassess_roadmap`. - -4. **Full regression suite** (25/25 pass, ~723ms): plan-milestone, plan-slice, plan-task, markdown-renderer, rogue-file-detection — no regressions from gsd-db.ts/markdown-renderer.ts changes. - -5. **Diagnostic grep**: Both test files contain structured error payload assertions (1 each). - -## Requirements Advanced - -None. - -## Requirements Validated - -- R005 — replan-handler.test.ts: 9 tests prove structural rejection of completed task updates/removals, DB persistence of replan_history, re-rendered PLAN.md + REPLAN.md, cache invalidation -- R006 — reassess-handler.test.ts: 9 tests prove structural rejection of completed slice modifications/removals, DB persistence of assessments, re-rendered ROADMAP.md + ASSESSMENT.md, cache invalidation -- R013 — prompt-contracts.test.ts: replan-slice.md contains gsd_replan_slice, reassess-roadmap.md contains gsd_reassess_roadmap — extends existing R013 validation from S01 -- R015 — Both handlers call invalidateStateCache() and clearParseCache() after success — tested via cache invalidation tests in replan-handler.test.ts and reassess-handler.test.ts - -## New Requirements Surfaced - -None. - -## Requirements Invalidated or Re-scoped - -None. - -## Deviations - -Minor additive deviations only — all strengthened the implementation: -- Added `getReplanHistory()` and `getAssessment()` query helpers to gsd-db.ts (not in plan) — needed for test DB persistence assertions. -- Added `updateSliceFields()` to gsd-db.ts — needed because `upsertSlicePlanning()` only handles planning-level fields, not basic slice metadata the reassess handler modifies. -- 3 extra tests per handler beyond the minimum specified in the plan (missing parent, "done" alias, structured error payloads). - -## Known Limitations - -None. - -## Follow-ups - -None. - -## Files Created/Modified - -- `src/resources/extensions/gsd/gsd-db.ts` — Added insertReplanHistory(), insertAssessment(), deleteTask(), deleteSlice(), getReplanHistory(), getAssessment(), updateSliceFields() DB helper functions -- `src/resources/extensions/gsd/markdown-renderer.ts` — Added renderReplanFromDb() and renderAssessmentFromDb() using writeAndStore() pattern -- `src/resources/extensions/gsd/tools/replan-slice.ts` — New file — handleReplanSlice() with structural enforcement of completed tasks -- `src/resources/extensions/gsd/tools/reassess-roadmap.ts` — New file — handleReassessRoadmap() with structural enforcement of completed slices -- `src/resources/extensions/gsd/bootstrap/db-tools.ts` — Registered gsd_replan_slice (alias gsd_slice_replan) and gsd_reassess_roadmap (alias gsd_roadmap_reassess) with TypeBox schemas -- `src/resources/extensions/gsd/prompts/replan-slice.md` — Added gsd_replan_slice as canonical write path, repositioned direct file writes as degraded fallback -- `src/resources/extensions/gsd/prompts/reassess-roadmap.md` — Added gsd_reassess_roadmap as canonical write path with full parameter documentation -- `src/resources/extensions/gsd/tests/replan-handler.test.ts` — New file — 9 tests for handleReplanSlice covering validation, structural enforcement, DB persistence, rendering, cache invalidation, idempotency -- `src/resources/extensions/gsd/tests/reassess-handler.test.ts` — New file — 9 tests for handleReassessRoadmap covering validation, structural enforcement, DB persistence, rendering, cache invalidation, idempotency -- `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` — Added 2 new tests asserting replan-slice.md and reassess-roadmap.md name their canonical tools diff --git a/.gsd/milestones/M001/slices/S03/S03-UAT.md b/.gsd/milestones/M001/slices/S03/S03-UAT.md deleted file mode 100644 index 776835413..000000000 --- a/.gsd/milestones/M001/slices/S03/S03-UAT.md +++ /dev/null @@ -1,70 +0,0 @@ -# S03: replan_slice + reassess_roadmap with structural enforcement — UAT - -**Milestone:** M001 -**Written:** 2026-03-23T16:40:55.867Z - -## UAT: S03 — replan_slice + reassess_roadmap with structural enforcement - -### Preconditions -- Node.js available with `--experimental-strip-types` support -- Working directory is the gsd-2 project root -- No prior test artifacts from previous runs - -### Test Case 1: Replan structural enforcement rejects completed task mutation -**Steps:** -1. Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/replan-handler.test.ts` -2. Verify "rejects structural violation: updating a completed task" passes -3. Verify "rejects structural violation: removing a completed task" passes -4. Verify "rejects task with status 'done' (alias for complete)" passes - -**Expected:** All 3 structural rejection tests pass. Error payloads name the specific task ID. - -### Test Case 2: Replan success path with DB persistence -**Steps:** -1. In the same test run, verify "succeeds when modifying only incomplete tasks" passes -2. Verify test confirms replan_history row exists in DB after success -3. Verify test confirms PLAN.md and REPLAN.md artifacts exist on disk -4. Verify "cache invalidation: re-parsing PLAN.md reflects mutations" passes - -**Expected:** Successful replan writes DB row, renders both artifacts, and invalidates caches so re-parsing shows updated state. - -### Test Case 3: Reassess structural enforcement rejects completed slice mutation -**Steps:** -1. Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/reassess-handler.test.ts` -2. Verify "rejects structural violation: modifying a completed slice" passes -3. Verify "rejects structural violation: removing a completed slice" passes -4. Verify "rejects slice with status 'done' (alias for complete)" passes - -**Expected:** All 3 structural rejection tests pass. Error payloads name the specific slice ID. - -### Test Case 4: Reassess success path with DB persistence -**Steps:** -1. In the same test run, verify "succeeds when modifying only pending slices" passes -2. Verify test confirms assessments row exists in DB after success -3. Verify test confirms ROADMAP.md and ASSESSMENT.md artifacts exist on disk -4. Verify "cache invalidation: getMilestoneSlices reflects mutations" passes - -**Expected:** Successful reassess writes DB row, renders both artifacts, and invalidates caches. - -### Test Case 5: Tool registration and prompt wiring -**Steps:** -1. Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts` -2. Verify "replan-slice prompt names gsd_replan_slice as canonical tool" passes -3. Verify "reassess-roadmap prompt names gsd_reassess_roadmap as canonical tool" passes -4. Run `grep -q 'gsd_replan_slice' src/resources/extensions/gsd/bootstrap/db-tools.ts && echo PASS` -5. Run `grep -q 'gsd_reassess_roadmap' src/resources/extensions/gsd/bootstrap/db-tools.ts && echo PASS` - -**Expected:** Both prompt contract tests pass. Both grep checks output PASS. - -### Test Case 6: Full regression — no breakage from S03 changes -**Steps:** -1. Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` -2. Verify all 25 regression tests pass - -**Expected:** 25/25 pass, 0 failures. S03 changes to gsd-db.ts and markdown-renderer.ts introduced no regressions. - -### Edge Cases -- Idempotency: calling replan/reassess twice with same params succeeds both times (covered by idempotency tests) -- Missing parent: replan with nonexistent slice returns clear error (covered by "missing parent slice" test) -- Missing milestone: reassess with nonexistent milestone returns clear error (covered by "missing milestone" test) -- Structured error payloads: error messages name specific task/slice IDs, not generic messages (covered by structured error payload tests) diff --git a/.gsd/milestones/M001/slices/S03/tasks/T01-PLAN.md b/.gsd/milestones/M001/slices/S03/tasks/T01-PLAN.md deleted file mode 100644 index ec588ee0b..000000000 --- a/.gsd/milestones/M001/slices/S03/tasks/T01-PLAN.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -estimated_steps: 4 -estimated_files: 4 -skills_used: [] ---- - -# T01: Implement replan_slice handler with structural enforcement - -**Slice:** S03 — replan_slice + reassess_roadmap with structural enforcement -**Milestone:** M001 - -## Description - -Build the `handleReplanSlice()` handler that structurally enforces preservation of completed tasks during replanning. This task also adds required DB helper functions (`insertReplanHistory`, `insertAssessment`, `deleteTask`, `deleteSlice`) and markdown renderers (`renderReplanFromDb`, `renderAssessmentFromDb`) that both the replan and reassess handlers use. - -The handler follows the established validate → enforce → transaction → render → invalidate pattern from `plan-slice.ts`. The novel addition is the structural enforcement step: before writing any mutations, query `getSliceTasks()` and reject the operation if any `updatedTasks[].taskId` or `removedTaskIds` element matches a task with status `complete` or `done`. - -## Steps - -1. **Add DB helper functions to `gsd-db.ts`:** - - `insertReplanHistory(entry)` — INSERT into `replan_history` table. Columns: milestone_id, slice_id, task_id (nullable, the blocker task), summary, previous_artifact_path, replacement_artifact_path, created_at. - - `insertAssessment(entry)` — INSERT OR REPLACE into `assessments` table (path is PK). Columns: path, milestone_id, slice_id, task_id, status, scope, full_content, created_at. - - `deleteTask(milestoneId, sliceId, taskId)` — Must first DELETE from `verification_evidence WHERE task_id = :tid AND slice_id = :sid AND milestone_id = :mid`, then DELETE from `tasks WHERE ...`. The `verification_evidence` table has a FK referencing tasks — deleting evidence first avoids FK constraint violations. - - `deleteSlice(milestoneId, sliceId)` — Must delete all child verification_evidence rows, then all child task rows, then the slice row. Use cascade-style manual deletion. - -2. **Add renderers to `markdown-renderer.ts`:** - - `renderReplanFromDb(basePath, milestoneId, sliceId, replanData)` — Generates REPLAN.md with blocker description, what changed, and summary. Uses `writeAndStore()` with artifact_type `"REPLAN"`. The `replanData` param includes blockerTaskId, blockerDescription, whatChanged. Path: `{sliceDir}/{sliceId}-REPLAN.md`. - - `renderAssessmentFromDb(basePath, milestoneId, sliceId, assessmentData)` — Generates ASSESSMENT.md with verdict, assessment text. Uses `writeAndStore()` with artifact_type `"ASSESSMENT"`. Path: `{sliceDir}/{sliceId}-ASSESSMENT.md`. - -3. **Create `tools/replan-slice.ts` with `handleReplanSlice()`:** - - Interface `ReplanSliceParams`: milestoneId, sliceId, blockerTaskId, blockerDescription, whatChanged, updatedTasks (array of {taskId, title, description, estimate, files, verify, inputs, expectedOutput}), removedTaskIds (string array). - - Validate all required fields (same `isNonEmptyString` pattern as plan-slice.ts). - - Query `getSlice()` to verify parent slice exists. - - Query `getSliceTasks()` to get all tasks. Build a Set of completed task IDs (status === 'complete' || status === 'done'). - - **Structural enforcement**: Check if any `updatedTasks[].taskId` is in the completed set → return `{ error: "cannot modify completed task T0X" }`. Check if any `removedTaskIds` element is in the completed set → return `{ error: "cannot remove completed task T0X" }`. - - In `transaction()`: call `insertReplanHistory()` with the replan metadata. For each updatedTask: if task exists, use `upsertTaskPlanning()` to update planning fields; if new, use `insertTask()` then `upsertTaskPlanning()`. For each removedTaskId: call `deleteTask()`. - - After transaction: call `renderPlanFromDb()` to re-render PLAN.md and task plans. Call `renderReplanFromDb()` to write REPLAN.md. Call `invalidateStateCache()` and `clearParseCache()`. - - Return `{ milestoneId, sliceId, replanPath, planPath }` on success. - -4. **Write `tests/replan-handler.test.ts`:** - - Use `node:test` (import test from 'node:test') and `node:assert/strict`. Follow the exact test setup pattern from `plan-slice.test.ts`: `makeTmpBase()`, `openDatabase()`, `cleanup()`, seed parent milestone+slice+tasks. - - Test cases: - - Validation failure (missing milestoneId) → returns `{ error }` containing "validation failed" - - Structural rejection: seed T01 as complete, T02 as pending. Call replan with updatedTasks targeting T01. Assert error contains "completed task" and "T01". - - Structural rejection: seed T01 as complete. Call replan with removedTaskIds containing T01. Assert error contains "completed task". - - Successful replan: seed T01 complete, T02 pending, T03 pending. Call replan updating T02 and removing T03 and adding T04. Assert success. Verify replan_history row exists in DB. Verify T02 updated in DB. Verify T03 deleted from DB. Verify T04 exists in DB. Verify rendered PLAN.md exists on disk. Verify REPLAN.md exists on disk. - - Cache invalidation: verify that re-parsing the PLAN.md after replan reflects the mutations (parse-visible state assertion). - - Idempotent rerun: call replan twice with same params, assert second call also succeeds. - -## Must-Haves - -- [ ] `insertReplanHistory()`, `insertAssessment()`, `deleteTask()`, `deleteSlice()` exported from `gsd-db.ts` -- [ ] `deleteTask()` handles FK constraint by deleting verification_evidence first -- [ ] `renderReplanFromDb()` and `renderAssessmentFromDb()` exported from `markdown-renderer.ts` -- [ ] `handleReplanSlice()` exported from `tools/replan-slice.ts` -- [ ] Structural rejection returns error naming the specific completed task ID -- [ ] Successful replan writes `replan_history` row with blocker metadata -- [ ] Successful replan re-renders PLAN.md and writes REPLAN.md via `writeAndStore()` -- [ ] Cache invalidation via `invalidateStateCache()` + `clearParseCache()` after render -- [ ] All tests in `replan-handler.test.ts` pass - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/replan-handler.test.ts` — all tests pass -- Structural rejection tests prove completed tasks cannot be mutated -- DB persistence tests prove replan_history row exists after successful replan - -## Observability Impact - -- Signals added/changed: Replan handler error payloads include the specific completed task IDs that blocked the mutation -- How a future agent inspects this: Query `replan_history` table, read rendered REPLAN.md, check PLAN.md for updated task list -- Failure state exposed: Validation errors, structural rejection errors, render failures return distinct `{ error: string }` payloads - -## Inputs - -- `src/resources/extensions/gsd/gsd-db.ts` — existing DB functions: `getSliceTasks()`, `getTask()`, `getSlice()`, `insertTask()`, `upsertTaskPlanning()`, `transaction()`, `insertArtifact()` -- `src/resources/extensions/gsd/markdown-renderer.ts` — existing `writeAndStore()` pattern, `renderPlanFromDb()` for PLAN.md re-rendering -- `src/resources/extensions/gsd/tools/plan-slice.ts` — reference handler pattern (validate → transaction → render → invalidate) -- `src/resources/extensions/gsd/tests/plan-slice.test.ts` — reference test pattern (setup, seed, assert) -- `src/resources/extensions/gsd/state.ts` — `invalidateStateCache()` import -- `src/resources/extensions/gsd/files.ts` — `clearParseCache()` import - -## Expected Output - -- `src/resources/extensions/gsd/gsd-db.ts` — modified with 4 new exported functions -- `src/resources/extensions/gsd/markdown-renderer.ts` — modified with 2 new renderer functions -- `src/resources/extensions/gsd/tools/replan-slice.ts` — new handler file -- `src/resources/extensions/gsd/tests/replan-handler.test.ts` — new test file diff --git a/.gsd/milestones/M001/slices/S03/tasks/T01-SUMMARY.md b/.gsd/milestones/M001/slices/S03/tasks/T01-SUMMARY.md deleted file mode 100644 index 591966da0..000000000 --- a/.gsd/milestones/M001/slices/S03/tasks/T01-SUMMARY.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -id: T01 -parent: S03 -milestone: M001 -key_files: - - src/resources/extensions/gsd/gsd-db.ts - - src/resources/extensions/gsd/markdown-renderer.ts - - src/resources/extensions/gsd/tools/replan-slice.ts - - src/resources/extensions/gsd/tests/replan-handler.test.ts - - .gsd/milestones/M001/slices/S03/S03-PLAN.md -key_decisions: - - deleteTask() deletes verification_evidence before task row to avoid FK constraint violations — cascade-style manual deletion pattern - - Structural enforcement checks both 'complete' and 'done' statuses as completed-task indicators - - Error payloads include the specific task ID that blocked the mutation for actionable diagnostics -observability_surfaces: - - "replan_history DB table — query with getReplanHistory(db, milestoneId, sliceId) to inspect replan events" - - "REPLAN.md artifact on disk — rendered at slices/S##/REPLAN.md with blocker description and what changed" - - "Handler error payloads — { error: string } naming the specific completed task ID that blocked the mutation" -duration: "" -verification_result: passed -completed_at: 2026-03-23T16:28:29.943Z -blocker_discovered: false ---- - -# T01: Implement replan_slice handler with structural enforcement, DB helpers, renderers, and tests - -**Implement replan_slice handler with structural enforcement, DB helpers, renderers, and tests** - -## What Happened - -Built the `handleReplanSlice()` handler that structurally enforces preservation of completed tasks during replanning, following the validate → enforce → transaction → render → invalidate pattern from `plan-slice.ts`. - -**Step 1 — DB helpers in `gsd-db.ts`:** Added four new exported functions: `insertReplanHistory()` writes to the `replan_history` table, `insertAssessment()` does INSERT OR REPLACE into `assessments`, `deleteTask()` handles FK constraints by deleting `verification_evidence` rows before the task row, and `deleteSlice()` performs cascade-style manual deletion (evidence → tasks → slice). Also added `getReplanHistory()` query helper for test assertions. - -**Step 2 — Renderers in `markdown-renderer.ts`:** Added `renderReplanFromDb()` which generates REPLAN.md with blocker description, what changed, and metadata sections using `writeAndStore()` with artifact_type "REPLAN". Added `renderAssessmentFromDb()` which generates ASSESSMENT.md with verdict and assessment text using artifact_type "ASSESSMENT". Both resolve slice paths via `resolveSlicePath()` with fallback. - -**Step 3 — Handler in `tools/replan-slice.ts`:** Created `handleReplanSlice()` with full validation of all required fields. Queries `getSliceTasks()` and builds a Set of completed task IDs (status === 'complete' || status === 'done'). Returns specific `{ error }` naming the exact task ID when any `updatedTasks[].taskId` or `removedTaskIds` element matches a completed task. In transaction: inserts replan_history row, upserts or inserts updated tasks, deletes removed tasks. After transaction: re-renders PLAN.md via `renderPlanFromDb()`, writes REPLAN.md via `renderReplanFromDb()`, invalidates both state cache and parse cache. - -**Step 4 — Tests in `tests/replan-handler.test.ts`:** Wrote 9 tests following the exact `plan-slice.test.ts` pattern (makeTmpBase, openDatabase, cleanup, seed). Tests cover: validation failure, structural rejection of completed task update, structural rejection of completed task removal, successful replan (verifies DB persistence of replan_history, task mutations, rendered artifacts), cache invalidation via re-parse, idempotent rerun, missing parent slice, "done" status alias handling, and structured error payload verification. - -**Pre-flight fix:** Added diagnostic verification step to S03-PLAN.md Verification section confirming structured error payload tests exist. - -## Verification - -Ran `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/replan-handler.test.ts` — all 9 tests pass (9/9, 0 failures, ~180ms). Ran full regression suite across plan-milestone, plan-slice, plan-task, markdown-renderer, and rogue-file-detection tests — all 25 tests pass (0 failures). Structural rejection tests prove completed tasks (both "complete" and "done" statuses) cannot be mutated or removed. DB persistence tests verify replan_history rows exist with correct metadata after successful replan. Rendered PLAN.md and REPLAN.md artifacts verified on disk. - -## Verification Evidence - -| # | Command | Exit Code | Verdict | Duration | -|---|---------|-----------|---------|----------| -| 1 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/replan-handler.test.ts` | 0 | ✅ pass | 253ms | -| 2 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` | 0 | ✅ pass | 609ms | -| 3 | `grep -c 'structured error payloads' src/resources/extensions/gsd/tests/replan-handler.test.ts` | 0 | ✅ pass | 10ms | - - -## Deviations - -Added `getReplanHistory()` query helper to `gsd-db.ts` (not in plan) — needed for test assertions to verify DB persistence. Added 3 extra tests beyond the plan's 6: missing parent slice error, "done" status alias handling, and structured error payloads with specific task IDs — strengthens observability coverage. - -## Known Issues - -None. - -## Diagnostics - -- **Inspect replan history:** `getReplanHistory(db, milestoneId, sliceId)` returns all replan events for a slice including blocker description, what changed, and timestamps. -- **Verify structural enforcement:** Run `replan-handler.test.ts` — tests "rejects structural violation: updating a completed task" and "removing a completed task" prove the enforcement gate. -- **Check rendered artifacts:** After a successful replan, `REPLAN.md` exists at `slices/S##/REPLAN.md` and PLAN.md is re-rendered with updated tasks. -- **Error payloads:** Handler returns `{ error: "Cannot update/remove completed task T##..." }` with the specific task ID. - -## Files Created/Modified - -- `src/resources/extensions/gsd/gsd-db.ts` -- `src/resources/extensions/gsd/markdown-renderer.ts` -- `src/resources/extensions/gsd/tools/replan-slice.ts` -- `src/resources/extensions/gsd/tests/replan-handler.test.ts` -- `.gsd/milestones/M001/slices/S03/S03-PLAN.md` diff --git a/.gsd/milestones/M001/slices/S03/tasks/T01-VERIFY.json b/.gsd/milestones/M001/slices/S03/tasks/T01-VERIFY.json deleted file mode 100644 index edf045dd9..000000000 --- a/.gsd/milestones/M001/slices/S03/tasks/T01-VERIFY.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "schemaVersion": 1, - "taskId": "T01", - "unitId": "M001/S03/T01", - "timestamp": 1774283314702, - "passed": false, - "discoverySource": "package-json", - "checks": [ - { - "command": "npm run test", - "exitCode": 1, - "durationMs": 39728, - "verdict": "fail" - } - ], - "retryAttempt": 1, - "maxRetries": 2 -} diff --git a/.gsd/milestones/M001/slices/S03/tasks/T02-PLAN.md b/.gsd/milestones/M001/slices/S03/tasks/T02-PLAN.md deleted file mode 100644 index da4326acd..000000000 --- a/.gsd/milestones/M001/slices/S03/tasks/T02-PLAN.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -estimated_steps: 2 -estimated_files: 2 -skills_used: [] ---- - -# T02: Implement reassess_roadmap handler with structural enforcement - -**Slice:** S03 — replan_slice + reassess_roadmap with structural enforcement -**Milestone:** M001 - -## Description - -Build the `handleReassessRoadmap()` handler that structurally enforces preservation of completed slices during roadmap reassessment. This handler follows the identical control flow pattern as `handleReplanSlice()` from T01 but operates at the milestone/slice level instead of the slice/task level. It reuses the DB helpers (`insertAssessment`, `deleteSlice`) and the `renderAssessmentFromDb()` renderer from T01. - -The structural enforcement logic: before writing any mutations, query `getMilestoneSlices()` and reject if any modified or removed slice has status `complete` or `done`. - -## Steps - -1. **Create `tools/reassess-roadmap.ts` with `handleReassessRoadmap()`:** - - Interface `ReassessRoadmapParams`: milestoneId, completedSliceId (the slice that just finished), verdict (string — e.g. "confirmed", "adjusted"), assessment (text body), sliceChanges object with: modified (array of {sliceId, title, risk, depends, demo}), added (array of {sliceId, title, risk, depends, demo}), removed (array of sliceId strings). - - Validate all required fields. `sliceChanges` must be an object with modified, added, removed arrays (can be empty arrays but must exist). - - Query `getMilestone()` to verify milestone exists. - - Query `getMilestoneSlices()` to get all slices. Build a Set of completed slice IDs (status === 'complete' || status === 'done'). - - **Structural enforcement**: Check if any `sliceChanges.modified[].sliceId` is in the completed set → return `{ error: "cannot modify completed slice S0X" }`. Check if any `sliceChanges.removed[]` element is in the completed set → return `{ error: "cannot remove completed slice S0X" }`. - - Compute assessment artifact path: `{sliceDir}/{completedSliceId}-ASSESSMENT.md` (the assessment lives in the completed slice's directory). - - In `transaction()`: call `insertAssessment()` with path (PK), milestone_id, status=verdict, scope='roadmap', full_content=assessment text, created_at. For each modified slice: call `upsertSlicePlanning()` to update title/risk/depends/demo. For each added slice: call `insertSlice()` with id, milestoneId, title, status='pending', demo. For each removed sliceId: call `deleteSlice()`. - - After transaction: call `renderRoadmapFromDb()` to re-render ROADMAP.md. Call `renderAssessmentFromDb()` to write ASSESSMENT.md. Call `invalidateStateCache()` and `clearParseCache()`. - - Return `{ milestoneId, completedSliceId, assessmentPath, roadmapPath }` on success. - -2. **Write `tests/reassess-handler.test.ts`:** - - Use `node:test` and `node:assert/strict`. Follow the setup pattern from `plan-slice.test.ts`: temp directory with `.gsd/milestones/M001/` structure, `openDatabase()`, seed milestone with S01 (complete), S02 (pending), S03 (pending). - - Test cases: - - Validation failure (missing milestoneId) → returns `{ error }` containing "validation failed" - - Missing milestone → returns `{ error }` containing "not found" - - Structural rejection: call reassess with modified containing S01 (complete). Assert error contains "completed slice" and "S01". - - Structural rejection: call reassess with removed containing S01 (complete). Assert error contains "completed slice". - - Successful reassess: modify S02 title/demo, add S04, remove S03. Assert success. Verify assessments row exists in DB (query by path). Verify S02 updated in DB. Verify S03 deleted from DB. Verify S04 exists in DB. Verify ROADMAP.md re-rendered on disk. Verify ASSESSMENT.md exists on disk. - - Cache invalidation: verify parse-visible state reflects mutations. - - Idempotent rerun: call reassess twice, second also succeeds (INSERT OR REPLACE on assessments path PK). - -## Must-Haves - -- [ ] `handleReassessRoadmap()` exported from `tools/reassess-roadmap.ts` -- [ ] Structural rejection returns error naming the specific completed slice ID -- [ ] Successful reassess writes `assessments` row with path PK and assessment content -- [ ] Successful reassess re-renders ROADMAP.md and writes ASSESSMENT.md via renderers -- [ ] Cache invalidation via `invalidateStateCache()` + `clearParseCache()` after render -- [ ] All tests in `reassess-handler.test.ts` pass - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/reassess-handler.test.ts` — all tests pass -- Structural rejection tests prove completed slices cannot be mutated -- DB persistence tests prove assessments row exists after successful reassess - -## Observability Impact - -- Signals added/changed: Reassess handler error payloads include the specific completed slice IDs that blocked the mutation -- How a future agent inspects this: Query `assessments` table by path, read rendered ASSESSMENT.md, check ROADMAP.md for updated slice list -- Failure state exposed: Validation errors, structural rejection errors, render failures return distinct `{ error: string }` payloads - -## Inputs - -- `src/resources/extensions/gsd/gsd-db.ts` — `getMilestoneSlices()`, `getMilestone()`, `insertSlice()`, `upsertSlicePlanning()`, `insertAssessment()`, `deleteSlice()`, `transaction()` (the last two added by T01) -- `src/resources/extensions/gsd/markdown-renderer.ts` — `renderRoadmapFromDb()`, `renderAssessmentFromDb()` (the latter added by T01) -- `src/resources/extensions/gsd/tools/replan-slice.ts` — reference handler pattern from T01 -- `src/resources/extensions/gsd/tests/replan-handler.test.ts` — reference test pattern from T01 -- `src/resources/extensions/gsd/state.ts` — `invalidateStateCache()` -- `src/resources/extensions/gsd/files.ts` — `clearParseCache()` - -## Expected Output - -- `src/resources/extensions/gsd/tools/reassess-roadmap.ts` — new handler file -- `src/resources/extensions/gsd/tests/reassess-handler.test.ts` — new test file diff --git a/.gsd/milestones/M001/slices/S03/tasks/T02-SUMMARY.md b/.gsd/milestones/M001/slices/S03/tasks/T02-SUMMARY.md deleted file mode 100644 index e9c28714a..000000000 --- a/.gsd/milestones/M001/slices/S03/tasks/T02-SUMMARY.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -id: T02 -parent: S03 -milestone: M001 -key_files: - - src/resources/extensions/gsd/tools/reassess-roadmap.ts - - src/resources/extensions/gsd/tests/reassess-handler.test.ts - - src/resources/extensions/gsd/gsd-db.ts -key_decisions: - - Added updateSliceFields() to gsd-db.ts for title/risk/depends/demo updates because upsertSlicePlanning() only handles planning-level fields (goal, success_criteria, etc.) — keeps DB API consistent rather than using raw SQL in the handler - - Added getAssessment() query helper to gsd-db.ts for test verification of assessments DB persistence — follows the same pattern as getReplanHistory() added in T01 -observability_surfaces: - - "assessments DB table — query with getAssessment(db, path) to inspect assessment events" - - "ASSESSMENT.md artifact on disk — rendered at slices/S##/ASSESSMENT.md with verdict and assessment text" - - "Handler error payloads — { error: string } naming the specific completed slice ID that blocked the mutation" -duration: "" -verification_result: passed -completed_at: 2026-03-23T16:32:59.273Z -blocker_discovered: false ---- - -# T02: Implement reassess_roadmap handler with structural enforcement, DB persistence, and tests - -**Implement reassess_roadmap handler with structural enforcement, DB persistence, and tests** - -## What Happened - -Built the `handleReassessRoadmap()` handler in `tools/reassess-roadmap.ts` following the identical validate → enforce → transaction → render → invalidate pattern established by `handleReplanSlice()` in T01, but operating at the milestone/slice level instead of slice/task level. - -**Handler implementation:** Validates all required fields including `sliceChanges` object with `modified`, `added`, and `removed` arrays. Queries `getMilestone()` to verify milestone exists. Queries `getMilestoneSlices()` and builds a Set of completed slice IDs (status === 'complete' || status === 'done'). Structural enforcement rejects any `sliceChanges.modified[].sliceId` or `sliceChanges.removed[]` element that matches a completed slice, returning `{ error }` naming the specific slice ID. In transaction: writes `assessments` row via `insertAssessment()` with path PK, applies slice modifications via `updateSliceFields()`, inserts new slices via `insertSlice()`, deletes removed slices via `deleteSlice()`. After transaction: re-renders ROADMAP.md via `renderRoadmapFromDb()`, writes ASSESSMENT.md via `renderAssessmentFromDb()`, invalidates both state cache and parse cache. - -**DB helper addition:** Added `updateSliceFields()` to `gsd-db.ts` — a targeted function that updates title/risk/depends/demo on existing slice rows. This was needed because `upsertSlicePlanning()` only handles planning fields (goal, success_criteria, etc.), not the basic slice metadata the reassess handler needs to modify. Also added `getAssessment()` query helper for test assertions. - -**Tests:** Wrote 9 tests in `reassess-handler.test.ts` following the exact pattern from `replan-handler.test.ts`. Tests cover: validation failure (missing milestoneId), missing milestone, structural rejection of completed slice modification, structural rejection of completed slice removal, successful reassess (verifies DB persistence of assessments row, slice mutations, rendered artifacts on disk), cache invalidation via getMilestoneSlices, idempotent rerun, "done" status alias handling, and structured error payload verification with specific slice IDs. - -## Verification - -Ran `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/reassess-handler.test.ts` — all 9 tests pass (0 failures, ~174ms). Ran replan handler tests — 9/9 pass (no regressions from gsd-db.ts changes). Ran full regression suite (plan-milestone, plan-slice, plan-task, markdown-renderer, rogue-file-detection) — 25/25 pass. Ran prompt contract tests — 26/26 pass. Diagnostic grep confirms both test files contain structured error payload assertions. - -## Verification Evidence - -| # | Command | Exit Code | Verdict | Duration | -|---|---------|-----------|---------|----------| -| 1 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/reassess-handler.test.ts` | 0 | ✅ pass | 174ms | -| 2 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/replan-handler.test.ts` | 0 | ✅ pass | 293ms | -| 3 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` | 0 | ✅ pass | 645ms | -| 4 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts` | 0 | ✅ pass | 116ms | -| 5 | `grep -c 'structured error payloads' src/resources/extensions/gsd/tests/replan-handler.test.ts src/resources/extensions/gsd/tests/reassess-handler.test.ts` | 0 | ✅ pass | 10ms | - - -## Deviations - -Added `updateSliceFields()` to `gsd-db.ts` (not in task plan's expected output) — needed because `upsertSlicePlanning()` only handles planning fields, not the basic slice fields (title/risk/depends/demo) that the reassess handler modifies. Also added `getAssessment()` query helper for test DB persistence assertions. - -## Known Issues - -None. - -## Diagnostics - -- **Inspect assessments:** `getAssessment(db, path)` returns the assessment row for a given artifact path. -- **Verify structural enforcement:** Run `reassess-handler.test.ts` — tests "rejects structural violation: modifying a completed slice" and "removing a completed slice" prove the enforcement gate. -- **Check rendered artifacts:** After a successful reassess, `ASSESSMENT.md` exists at `slices/S##/ASSESSMENT.md` and ROADMAP.md is re-rendered. -- **Error payloads:** Handler returns `{ error: "Cannot modify/remove completed slice S##..." }` with the specific slice ID. - -## Files Created/Modified - -- `src/resources/extensions/gsd/tools/reassess-roadmap.ts` -- `src/resources/extensions/gsd/tests/reassess-handler.test.ts` -- `src/resources/extensions/gsd/gsd-db.ts` diff --git a/.gsd/milestones/M001/slices/S03/tasks/T02-VERIFY.json b/.gsd/milestones/M001/slices/S03/tasks/T02-VERIFY.json deleted file mode 100644 index 18ea99964..000000000 --- a/.gsd/milestones/M001/slices/S03/tasks/T02-VERIFY.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "schemaVersion": 1, - "taskId": "T02", - "unitId": "M001/S03/T02", - "timestamp": 1774283594680, - "passed": false, - "discoverySource": "package-json", - "checks": [ - { - "command": "npm run test", - "exitCode": 1, - "durationMs": 39663, - "verdict": "fail" - } - ], - "retryAttempt": 1, - "maxRetries": 2 -} diff --git a/.gsd/milestones/M001/slices/S03/tasks/T03-PLAN.md b/.gsd/milestones/M001/slices/S03/tasks/T03-PLAN.md deleted file mode 100644 index 1029473a8..000000000 --- a/.gsd/milestones/M001/slices/S03/tasks/T03-PLAN.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -estimated_steps: 5 -estimated_files: 4 -skills_used: [] ---- - -# T03: Register tools in db-tools.ts + update prompts + prompt contract tests - -**Slice:** S03 — replan_slice + reassess_roadmap with structural enforcement -**Milestone:** M001 - -## Description - -Wire the two new handlers into the tool system by registering them in `db-tools.ts`, update the prompt templates to name the specific tools as canonical write paths, and extend prompt contract tests to catch regressions. This is the integration closure task that makes the handlers callable by auto-mode dispatch. - -## Steps - -1. **Register `gsd_replan_slice` in `db-tools.ts`:** - - Add after the `gsd_plan_task` registration block (around line 531). - - Follow the exact pattern of `gsd_plan_slice`: `ensureDbOpen()` guard, dynamic `import("../tools/replan-slice.js")`, call `handleReplanSlice(params, process.cwd())`, check for `error` in result, return structured `content`/`details`. - - TypeBox schema mirrors `ReplanSliceParams`: milestoneId, sliceId, blockerTaskId, blockerDescription, whatChanged as `Type.String()`, updatedTasks as `Type.Array(Type.Object({...}))`, removedTaskIds as `Type.Array(Type.String())`. - - Name: `gsd_replan_slice`, label: `"Replan Slice"`, description mentioning structural enforcement of completed tasks. - - promptGuidelines: mention canonical name and alias. - - Register alias: `gsd_slice_replan` → `gsd_replan_slice`. - -2. **Register `gsd_reassess_roadmap` in `db-tools.ts`:** - - Same pattern. Dynamic `import("../tools/reassess-roadmap.js")`, call `handleReassessRoadmap(params, process.cwd())`. - - TypeBox schema mirrors `ReassessRoadmapParams`: milestoneId, completedSliceId, verdict, assessment as `Type.String()`, sliceChanges as `Type.Object({ modified: Type.Array(...), added: Type.Array(...), removed: Type.Array(Type.String()) })`. - - Name: `gsd_reassess_roadmap`, label: `"Reassess Roadmap"`. - - Register alias: `gsd_roadmap_reassess` → `gsd_reassess_roadmap`. - -3. **Update `replan-slice.md` prompt:** - - Add a new step before the existing file-write instructions (before step 3). The new step should say: "If a DB-backed planning tool is available, use `gsd_replan_slice` with the following parameters: milestoneId, sliceId, blockerTaskId, blockerDescription, whatChanged, updatedTasks, removedTaskIds. This is the canonical write path — it structurally enforces preservation of completed tasks and writes replan history to the DB." - - Reposition the existing file-write steps (writing `{{replanPath}}` and `{{planPath}}`) as the degraded fallback: "If the `gsd_replan_slice` tool is not available, fall back to writing files directly..." - - Keep all existing hard constraints about completed tasks intact — they remain as documentation even though the tool enforces them structurally. - -4. **Update `reassess-roadmap.md` prompt:** - - Add a new instruction before the "If changes are needed" section: "Use `gsd_reassess_roadmap` to persist the assessment and any roadmap changes. Pass: milestoneId, completedSliceId, verdict, assessment text, and sliceChanges with modified/added/removed arrays." - - The prompt already has "Do not bypass state with manual roadmap-only edits" — augment it with: "when `gsd_reassess_roadmap` is available". - - Keep the existing file-write instructions as degraded fallback. - -5. **Extend `prompt-contracts.test.ts`:** - - Add test: `replan-slice prompt names gsd_replan_slice as canonical tool` — assert `replan-slice.md` contains `gsd_replan_slice`. - - Add test: `reassess-roadmap prompt names gsd_reassess_roadmap as canonical tool` — assert `reassess-roadmap.md` contains `gsd_reassess_roadmap`. - - Update the existing test at line 170 (`"replan-slice prompt requires DB-backed planning state when available"`) if the new prompt content makes the old assertion redundant — the existing test checks for generic "DB-backed planning tool" language, the new test checks for the specific tool name. - -## Must-Haves - -- [ ] `gsd_replan_slice` registered in db-tools.ts with TypeBox schema and alias `gsd_slice_replan` -- [ ] `gsd_reassess_roadmap` registered in db-tools.ts with TypeBox schema and alias `gsd_roadmap_reassess` -- [ ] `replan-slice.md` contains `gsd_replan_slice` as canonical tool name -- [ ] `reassess-roadmap.md` contains `gsd_reassess_roadmap` as canonical tool name -- [ ] Prompt contract tests pass asserting tool name presence in both prompts -- [ ] Existing prompt contract tests still pass (no regressions) - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts` — all tests pass including new assertions -- `grep -q 'gsd_replan_slice' src/resources/extensions/gsd/prompts/replan-slice.md` — exits 0 -- `grep -q 'gsd_reassess_roadmap' src/resources/extensions/gsd/prompts/reassess-roadmap.md` — exits 0 -- `grep -q 'gsd_replan_slice' src/resources/extensions/gsd/bootstrap/db-tools.ts` — exits 0 -- `grep -q 'gsd_reassess_roadmap' src/resources/extensions/gsd/bootstrap/db-tools.ts` — exits 0 - -## Inputs - -- `src/resources/extensions/gsd/tools/replan-slice.ts` — handler created in T01 -- `src/resources/extensions/gsd/tools/reassess-roadmap.ts` — handler created in T02 -- `src/resources/extensions/gsd/bootstrap/db-tools.ts` — existing registration patterns for plan_slice, plan_task -- `src/resources/extensions/gsd/prompts/replan-slice.md` — existing prompt template -- `src/resources/extensions/gsd/prompts/reassess-roadmap.md` — existing prompt template -- `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` — existing prompt contract tests - -## Expected Output - -- `src/resources/extensions/gsd/bootstrap/db-tools.ts` — modified with two new tool registrations -- `src/resources/extensions/gsd/prompts/replan-slice.md` — modified to name `gsd_replan_slice` -- `src/resources/extensions/gsd/prompts/reassess-roadmap.md` — modified to name `gsd_reassess_roadmap` -- `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` — modified with new tool name assertions diff --git a/.gsd/milestones/M001/slices/S03/tasks/T03-SUMMARY.md b/.gsd/milestones/M001/slices/S03/tasks/T03-SUMMARY.md deleted file mode 100644 index c0782d341..000000000 --- a/.gsd/milestones/M001/slices/S03/tasks/T03-SUMMARY.md +++ /dev/null @@ -1,84 +0,0 @@ ---- -id: T03 -parent: S03 -milestone: M001 -key_files: - - src/resources/extensions/gsd/bootstrap/db-tools.ts - - src/resources/extensions/gsd/prompts/replan-slice.md - - src/resources/extensions/gsd/prompts/reassess-roadmap.md - - src/resources/extensions/gsd/tests/prompt-contracts.test.ts -key_decisions: - - Prompt updates position the DB-backed tool as canonical write path with direct file writes as degraded fallback — consistent with the pattern established for plan-slice and plan-milestone prompts -observability_surfaces: - - "db-tools.ts tool registrations — grep for gsd_replan_slice and gsd_reassess_roadmap to verify wiring" - - "Prompt contract tests — prompt-contracts.test.ts asserts tool names appear in prompts as regression guard" - - "Prompt files — replan-slice.md and reassess-roadmap.md contain canonical write path instructions" -duration: "" -verification_result: passed -completed_at: 2026-03-23T16:36:49.549Z -blocker_discovered: false ---- - -# T03: Register gsd_replan_slice and gsd_reassess_roadmap tools in db-tools.ts, update prompts to name canonical tools, add prompt contract tests - -**Register gsd_replan_slice and gsd_reassess_roadmap tools in db-tools.ts, update prompts to name canonical tools, add prompt contract tests** - -## What Happened - -Wired the two new handlers into the tool system and updated prompts to direct auto-mode dispatch through the canonical tool paths. - -**Step 1 — Register `gsd_replan_slice` in `db-tools.ts`:** Added the full tool registration following the exact pattern of `gsd_plan_slice` — `ensureDbOpen()` guard, dynamic `import("../tools/replan-slice.js")`, call `handleReplanSlice(params, process.cwd())`, check for `error` in result, return structured `content`/`details` with `operation: "replan_slice"`. TypeBox schema mirrors `ReplanSliceParams` with all required fields including `updatedTasks` as `Type.Array(Type.Object({...}))` and `removedTaskIds` as `Type.Array(Type.String())`. Registered alias `gsd_slice_replan` → `gsd_replan_slice`. Description mentions structural enforcement of completed tasks. `promptGuidelines` describe the canonical name, alias, parameter list, and enforcement behavior. - -**Step 2 — Register `gsd_reassess_roadmap` in `db-tools.ts`:** Same pattern. Dynamic import of `../tools/reassess-roadmap.js`, call `handleReassessRoadmap(params, process.cwd())`. TypeBox schema mirrors `ReassessRoadmapParams` with `sliceChanges` as a nested `Type.Object` containing `modified`, `added`, and `removed` arrays. Registered alias `gsd_roadmap_reassess` → `gsd_reassess_roadmap`. - -**Step 3 — Update `replan-slice.md` prompt:** Added step 3 "Canonical write path — use `gsd_replan_slice`" before the existing file-write instructions, naming the tool and all its parameters, and explaining it as the canonical write path with structural enforcement. Repositioned existing file-write steps (4–5) as "Degraded fallback — direct file writes" with the condition "If the `gsd_replan_slice` tool is not available". Renumbered all subsequent steps. All existing hard constraints about completed tasks preserved. - -**Step 4 — Update `reassess-roadmap.md` prompt:** Added `gsd_reassess_roadmap` as the canonical write path in both the "roadmap is still good" and "changes are needed" sections. Step 1 under changes needed is now "Canonical write path — use `gsd_reassess_roadmap`" with full parameter documentation. Step 2 is the degraded fallback, augmented with "when `gsd_reassess_roadmap` is available" on the bypass prohibition. - -**Step 5 — Extend `prompt-contracts.test.ts`:** Added two new tests: "replan-slice prompt names gsd_replan_slice as canonical tool" asserts both the tool name and "canonical write path" text; "reassess-roadmap prompt names gsd_reassess_roadmap as canonical tool" does the same. Both tests pass alongside the existing 26 prompt contract tests (28 total). - -## Verification - -All slice-level verification checks pass: -- Prompt contract tests: 28/28 pass (including 2 new tool name assertions) -- Replan handler tests: 9/9 pass (no regressions from db-tools.ts changes) -- Reassess handler tests: 9/9 pass (no regressions) -- Full regression suite (plan-milestone, plan-slice, plan-task, markdown-renderer, rogue-file-detection): 25/25 pass -- Diagnostic grep: Both test files contain structured error payload assertions (1 each) -- grep -q checks: All 4 pass (gsd_replan_slice in prompt and db-tools, gsd_reassess_roadmap in prompt and db-tools) - -## Verification Evidence - -| # | Command | Exit Code | Verdict | Duration | -|---|---------|-----------|---------|----------| -| 1 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/prompt-contracts.test.ts` | 0 | ✅ pass | 123ms | -| 2 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/replan-handler.test.ts` | 0 | ✅ pass | 324ms | -| 3 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/reassess-handler.test.ts` | 0 | ✅ pass | 314ms | -| 4 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/rogue-file-detection.test.ts` | 0 | ✅ pass | 676ms | -| 5 | `grep -c 'structured error payloads' src/resources/extensions/gsd/tests/replan-handler.test.ts src/resources/extensions/gsd/tests/reassess-handler.test.ts` | 0 | ✅ pass | 10ms | -| 6 | `grep -q 'gsd_replan_slice' src/resources/extensions/gsd/prompts/replan-slice.md` | 0 | ✅ pass | 5ms | -| 7 | `grep -q 'gsd_reassess_roadmap' src/resources/extensions/gsd/prompts/reassess-roadmap.md` | 0 | ✅ pass | 5ms | -| 8 | `grep -q 'gsd_replan_slice' src/resources/extensions/gsd/bootstrap/db-tools.ts` | 0 | ✅ pass | 5ms | -| 9 | `grep -q 'gsd_reassess_roadmap' src/resources/extensions/gsd/bootstrap/db-tools.ts` | 0 | ✅ pass | 5ms | - - -## Deviations - -None. - -## Known Issues - -None. - -## Diagnostics - -- **Verify tool registration:** `grep -q 'gsd_replan_slice' src/resources/extensions/gsd/bootstrap/db-tools.ts && grep -q 'gsd_reassess_roadmap' src/resources/extensions/gsd/bootstrap/db-tools.ts` — both must succeed. -- **Verify prompt wiring:** `grep -q 'gsd_replan_slice' src/resources/extensions/gsd/prompts/replan-slice.md && grep -q 'gsd_reassess_roadmap' src/resources/extensions/gsd/prompts/reassess-roadmap.md` — both must succeed. -- **Prompt contract regression guard:** Run `prompt-contracts.test.ts` — 28 tests including the 2 new tool-name assertions catch regressions if someone removes the canonical tool references from prompts. - -## Files Created/Modified - -- `src/resources/extensions/gsd/bootstrap/db-tools.ts` -- `src/resources/extensions/gsd/prompts/replan-slice.md` -- `src/resources/extensions/gsd/prompts/reassess-roadmap.md` -- `src/resources/extensions/gsd/tests/prompt-contracts.test.ts` diff --git a/.gsd/milestones/M001/slices/S03/tasks/T03-VERIFY.json b/.gsd/milestones/M001/slices/S03/tasks/T03-VERIFY.json deleted file mode 100644 index 6fe90d2a1..000000000 --- a/.gsd/milestones/M001/slices/S03/tasks/T03-VERIFY.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "schemaVersion": 1, - "taskId": "T03", - "unitId": "M001/S03/T03", - "timestamp": 1774283829836, - "passed": false, - "discoverySource": "package-json", - "checks": [ - { - "command": "npm run test", - "exitCode": 1, - "durationMs": 41263, - "verdict": "fail" - } - ], - "retryAttempt": 1, - "maxRetries": 2 -} diff --git a/.gsd/milestones/M001/slices/S04/S04-PLAN.md b/.gsd/milestones/M001/slices/S04/S04-PLAN.md deleted file mode 100644 index ace160289..000000000 --- a/.gsd/milestones/M001/slices/S04/S04-PLAN.md +++ /dev/null @@ -1,83 +0,0 @@ -# S04: Hot-path caller migration + cross-validation tests - -**Goal:** The six highest-frequency parser callers in the auto-mode dispatch loop read from DB instead of parsing markdown, and cross-validation tests prove DB↔rendered parity. -**Demo:** `dispatch-guard.ts`, `auto-dispatch.ts` (3 rules), `auto-verification.ts`, and `parallel-eligibility.ts` import DB query functions instead of `parseRoadmapSlices`/`parseRoadmap`/`parsePlan`. All existing tests pass. New cross-validation tests prove rendered-then-parsed state matches DB state. - -## Must-Haves - -- `sequence INTEGER DEFAULT 0` column on `slices` and `tasks` tables via schema v9 migration (R016) -- All 6 `ORDER BY id` queries in gsd-db.ts updated to `ORDER BY sequence, id` with null-safe fallback (R016) -- `dispatch-guard.ts` uses `getMilestoneSlices()` instead of `parseRoadmapSlices()` (R009) -- `auto-dispatch.ts` uat-verdict-gate, validating-milestone, completing-milestone rules use `getMilestoneSlices()` instead of `parseRoadmap()` (R009) -- `auto-verification.ts` uses `getTask()` instead of `parsePlan()` (R009) -- `parallel-eligibility.ts` uses `getMilestoneSlices()` + `getSliceTasks()` instead of `parseRoadmap()` + `parsePlan()` (R009) -- Cross-validation test proving DB state matches rendered-then-parsed state for ROADMAP and PLAN artifacts (R014) -- `dispatch-guard.test.ts` updated to seed DB state instead of writing markdown files - -## Proof Level - -- This slice proves: contract + integration -- Real runtime required: no -- Human/UAT required: no - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts` — sequence column migration and ORDER BY behavior -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/dispatch-guard.test.ts` — dispatch guard using DB queries -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/planning-crossval.test.ts` — DB↔rendered parity -- `rg 'parseRoadmapSlices|parseRoadmap|parsePlan' src/resources/extensions/gsd/dispatch-guard.ts src/resources/extensions/gsd/auto-verification.ts src/resources/extensions/gsd/parallel-eligibility.ts` returns no matches (parser imports removed from migrated files) -- `rg 'parseRoadmap' src/resources/extensions/gsd/auto-dispatch.ts` returns no matches (parser import narrowed) -- Diagnostic: `node -e "const{openDatabase,getMilestoneSlices}=require('./src/resources/extensions/gsd/gsd-db.ts');openDatabase(':memory:');console.log(getMilestoneSlices('NONEXISTENT'))"` — returns empty array `[]` (no crash on missing milestone, observable failure state) - -## Observability / Diagnostics - -- Runtime signals: `isDbAvailable()` gate in each migrated caller — falls back to disk parsing when DB is not open, logging a stderr diagnostic -- Inspection surfaces: SQLite `slices` and `tasks` tables with `sequence` column; `getMilestoneSlices()`/`getSliceTasks()` query functions -- Failure visibility: dispatch-guard returns blocker string on failure; auto-dispatch rules return stop/skip actions; stderr warnings when DB unavailable - -## Integration Closure - -- Upstream surfaces consumed: `gsd-db.ts` query functions (`getMilestoneSlices`, `getSliceTasks`, `getTask`, `isDbAvailable`), `markdown-renderer.ts` (`renderRoadmapFromDb`, `renderPlanFromDb`, `renderTaskPlanFromDb`), schema v8 migration from S01/S02 -- New wiring introduced in this slice: DB imports in dispatch-guard, auto-dispatch, auto-verification, parallel-eligibility; schema v9 migration block -- What remains before the milestone is truly usable end-to-end: S05 warm/cold callers + flag files, S06 parser removal - -## Tasks - -- [x] **T01: Add schema v9 migration with sequence column and fix ORDER BY queries** `est:30m` - - Why: R016 requires sequence-aware ordering. All caller migrations and cross-validation depend on correct query ordering. - - Files: `src/resources/extensions/gsd/gsd-db.ts`, `src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts` - - Do: Add `sequence INTEGER DEFAULT 0` to slices and tasks tables in a `currentVersion < 9` migration block. Bump `SCHEMA_VERSION` to 9. Update `SliceRow` and `TaskRow` interfaces to include `sequence: number`. Change all 6 `ORDER BY id` queries to `ORDER BY sequence, id`. Add `insertSlicePlanning`/`insertTask` to accept optional `sequence` param. Write test file proving: migration adds column, ORDER BY respects sequence, null/0 sequence falls back to id ordering, backfill from positional order. - - Verify: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts` - - Done when: All 6 ORDER BY queries use `sequence, id`, test file passes, existing tests unbroken - -- [x] **T02: Migrate dispatch-guard.ts to DB queries and update tests** `est:45m` - - Why: dispatch-guard re-parses ROADMAP.md on every slice dispatch — the single hottest parser caller. R009 requires this migration. - - Files: `src/resources/extensions/gsd/dispatch-guard.ts`, `src/resources/extensions/gsd/tests/dispatch-guard.test.ts` - - Do: Replace `parseRoadmapSlices(roadmapContent)` with `getMilestoneSlices(mid)`. Map `SliceRow.status === 'complete'` to `done: true`. Remove `readRoadmapFromDisk()`, `readFileSync`, and `parseRoadmapSlices` imports. Add `isDbAvailable()` + `getMilestoneSlices()` import from `gsd-db.js`. Keep the `findMilestoneIds()` disk-based milestone discovery (DB doesn't own milestone queue order). Add fallback to disk parsing when `!isDbAvailable()`. Update all 8 test cases to seed DB via `openDatabase`/`insertMilestone`/`insertSlice` instead of writing ROADMAP markdown files. Preserve all existing assertion semantics. - - Verify: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/dispatch-guard.test.ts` - - Done when: dispatch-guard.ts has zero `parseRoadmapSlices` references, all 8 tests pass with DB seeding - -- [x] **T03: Migrate auto-dispatch.ts, auto-verification.ts, and parallel-eligibility.ts to DB queries** `est:45m` - - Why: These four files contain the remaining hot-path parser callers. R009 requires all six callers migrated. - - Files: `src/resources/extensions/gsd/auto-dispatch.ts`, `src/resources/extensions/gsd/auto-verification.ts`, `src/resources/extensions/gsd/parallel-eligibility.ts` - - Do: In `auto-dispatch.ts`: replace 3 `parseRoadmap(roadmapContent).slices` calls (lines ~176, ~507, ~564) with `getMilestoneSlices(mid)` mapping `status === 'complete'` to `done`. Remove `parseRoadmap` from the import (keep `loadFile`, `extractUatType`, `loadActiveOverrides`). Add `isDbAvailable`, `getMilestoneSlices` import from `gsd-db.js`. Gate each migrated rule on `isDbAvailable()` with disk-parse fallback. In `auto-verification.ts`: replace `parsePlan(planContent).tasks.find(t => t.id === tid).verify` with `getTask(mid, sid, tid)?.verify`. Remove `parsePlan` and `loadFile` imports. Add `isDbAvailable`, `getTask` import. Gate on `isDbAvailable()` with disk-parse fallback. In `parallel-eligibility.ts`: replace `parseRoadmap().slices` with `getMilestoneSlices(mid)`, replace `parsePlan().filesLikelyTouched` with `getSliceTasks(mid, sid).flatMap(t => t.files)`. Remove `parseRoadmap`, `parsePlan`, `loadFile` imports. Add `isDbAvailable`, `getMilestoneSlices`, `getSliceTasks` import. Gate on `isDbAvailable()` with disk-parse fallback. - - Verify: `rg 'parseRoadmap' src/resources/extensions/gsd/auto-dispatch.ts src/resources/extensions/gsd/auto-verification.ts src/resources/extensions/gsd/parallel-eligibility.ts` returns no matches; `rg 'parsePlan' src/resources/extensions/gsd/auto-verification.ts src/resources/extensions/gsd/parallel-eligibility.ts` returns no matches - - Done when: All three files import from `gsd-db.js` for planning state, zero parser references in migrated call sites, existing tests pass - -- [x] **T04: Write cross-validation tests proving DB↔rendered↔parsed parity** `est:45m` - - Why: R014 requires proof that DB state matches rendered-then-parsed state during the transition window. This is the slice's highest-value proof artifact. - - Files: `src/resources/extensions/gsd/tests/planning-crossval.test.ts` - - Do: Create test file following the `derive-state-crossval.test.ts` pattern. Test scenarios: (1) Insert milestone + slices via DB, render ROADMAP via `renderRoadmapFromDb()`, parse back via `parseRoadmapSlices()`, assert field parity for `id`, `done`/status, `depends`, `risk`, `title`, `demo`. (2) Insert slice + tasks via DB with planning fields (description, files, verify, estimate), render via `renderPlanFromDb()`, parse back via `parsePlan()`, assert field parity for task `id`, `title`, `verify`, `filesLikelyTouched`, task count. (3) Insert task with all planning fields, render via `renderTaskPlanFromDb()`, parse back via `parseTaskPlanFile()` or read frontmatter, assert field parity for `description`, `verify`, `files`, `inputs`, `expected_output`. (4) Sequence ordering: insert slices with non-sequential sequence values, render ROADMAP, parse back, verify slice order matches sequence order not insertion order. Use `openDatabase`/`closeDatabase` with temp dirs, clean up after each test. - - Verify: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/planning-crossval.test.ts` - - Done when: All 4 cross-validation scenarios pass, proving DB↔rendered↔parsed round-trip fidelity - -## Files Likely Touched - -- `src/resources/extensions/gsd/gsd-db.ts` -- `src/resources/extensions/gsd/dispatch-guard.ts` -- `src/resources/extensions/gsd/auto-dispatch.ts` -- `src/resources/extensions/gsd/auto-verification.ts` -- `src/resources/extensions/gsd/parallel-eligibility.ts` -- `src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts` -- `src/resources/extensions/gsd/tests/dispatch-guard.test.ts` -- `src/resources/extensions/gsd/tests/planning-crossval.test.ts` diff --git a/.gsd/milestones/M001/slices/S04/S04-RESEARCH.md b/.gsd/milestones/M001/slices/S04/S04-RESEARCH.md deleted file mode 100644 index 9c9053b4c..000000000 --- a/.gsd/milestones/M001/slices/S04/S04-RESEARCH.md +++ /dev/null @@ -1,73 +0,0 @@ -# S04: Hot-path caller migration + cross-validation tests — Research - -**Date:** 2026-03-23 -**Status:** Ready for planning - -## Summary - -S04 migrates the six highest-frequency parser callers to DB queries and adds cross-validation tests proving DB state matches rendered-then-parsed state. The callers are: `dispatch-guard.ts` (parseRoadmapSlices → getMilestoneSlices), three `auto-dispatch.ts` rules (parseRoadmap → getMilestoneSlices for uat-verdict-gate, validating-milestone, completing-milestone), `auto-verification.ts` (parsePlan → getTask for verify command), and `parallel-eligibility.ts` (parseRoadmap + parsePlan → getMilestoneSlices + getSliceTasks for dependency and file-overlap analysis). - -R016 requires a `sequence` column on slices and tasks tables so `getMilestoneSlices()` and `getSliceTasks()` `ORDER BY sequence` instead of `ORDER BY id`. This column does not exist yet — it needs a schema v9 migration and propagation to all six query functions that currently `ORDER BY id`. - -The work is straightforward: each caller is a narrow transformation from "read file → parse markdown → extract field" to "call DB query → map field". No new architectural patterns needed — just wiring up existing DB functions and adding the sequence column. - -## Recommendation - -Build in three phases: (1) schema v9 migration adding `sequence` column + fixing all `ORDER BY` clauses (unblocks everything), (2) caller migrations in parallel since they're independent files, (3) cross-validation tests last since they need the migrated callers and sequence ordering to produce meaningful comparisons. - -The cross-validation tests should follow the `derive-state-crossval.test.ts` pattern: create fixture data in DB via insert functions, render to markdown via renderers, parse back via parsers, and assert field parity. This proves renderer fidelity during the transition window. - -## Implementation Landscape - -### Key Files - -- `src/resources/extensions/gsd/gsd-db.ts` — Needs `sequence INTEGER` column on `slices` and `tasks` tables via schema v9 migration. Six query functions need `ORDER BY sequence, id` (fallback to id when sequence is null/0). Query functions: `getMilestoneSlices()` (line 1391), `getSliceTasks()` (line 1242), `getActiveSliceFromDb()` (line 1364), `getActiveTaskFromDb()` (line 1382), `getAllMilestones()` (line 1341), `getActiveMilestoneFromDb()` (line 1355). -- `src/resources/extensions/gsd/dispatch-guard.ts` — 106 lines. `getPriorSliceCompletionBlocker()` reads ROADMAP from disk via `readRoadmapFromDisk()`, calls `parseRoadmapSlices()`, uses `slice.done`, `slice.id`, `slice.depends`. Replace with `getMilestoneSlices(mid)` mapping `status === 'complete'` → `done`, preserving `depends` array from DB. Remove `readFileSync` and `parseRoadmapSlices` import. -- `src/resources/extensions/gsd/auto-dispatch.ts` — Three rules use `parseRoadmap()`: **uat-verdict-gate** (line ~176, iterates completed slices to check UAT verdict files), **validating-milestone** (line ~507, checks all slices have SUMMARY files), **completing-milestone** (line ~564, same pattern). All three need `getMilestoneSlices(mid)` instead. The `loadFile`/`parseRoadmap` import can be narrowed after migration. -- `src/resources/extensions/gsd/auto-verification.ts` — Line ~71: parses full PLAN file to find `taskEntry.verify` for a specific task. Replace with `getTask(mid, sid, tid)?.verify`. Removes `parsePlan` and `loadFile` imports entirely. -- `src/resources/extensions/gsd/parallel-eligibility.ts` — Lines 45/55: `parseRoadmap()` for slice list, `parsePlan()` for `filesLikelyTouched`. Replace with `getMilestoneSlices(mid)` for slices and aggregate `getSliceTasks(mid, sid)` → `task.files` for file collection. The `parsePlan` and `parseRoadmap` imports can be removed. -- `src/resources/extensions/gsd/tests/dispatch-guard.test.ts` — 187 lines. Existing tests create ROADMAP files on disk and test `getPriorSliceCompletionBlocker`. After migration, tests must seed DB instead of writing markdown files. May need a parallel test approach: keep existing disk-based tests to prove backward compat, add DB-backed tests. -- `src/resources/extensions/gsd/tests/derive-state-crossval.test.ts` — 527 lines. The M001 cross-validation pattern. New cross-validation tests should follow this structure: setup fixture in DB via inserts → render to markdown → parse back → compare DB state vs parsed state field by field. - -### Interface Mapping - -| Parser field | DB equivalent | Notes | -|---|---|---| -| `RoadmapSliceEntry.done` | `SliceRow.status === 'complete'` | Direct boolean mapping | -| `RoadmapSliceEntry.id` | `SliceRow.id` | Same field | -| `RoadmapSliceEntry.depends` | `SliceRow.depends` | Both `string[]` | -| `RoadmapSliceEntry.title` | `SliceRow.title` | Same field | -| `RoadmapSliceEntry.risk` | `SliceRow.risk` | Same field | -| `RoadmapSliceEntry.demo` | `SliceRow.demo` | Same field | -| `SlicePlan.filesLikelyTouched` | `getSliceTasks(mid, sid).flatMap(t => t.files)` | Aggregated from task rows | -| `TaskPlanEntry.verify` | `TaskRow.verify` | Direct field | - -### Build Order - -1. **Schema v9 + sequence ordering** — Add `sequence INTEGER DEFAULT 0` to slices and tasks tables. Update all six `ORDER BY id` queries to `ORDER BY sequence, id`. This is the prerequisite for R016 and must land first because all caller migrations depend on correct query ordering. Backfill sequence from positional order of existing rows. -2. **Caller migrations** — dispatch-guard.ts, auto-verification.ts, and the three auto-dispatch.ts rules can be migrated independently. parallel-eligibility.ts too. Each is a self-contained file change. -3. **Cross-validation tests** — Write tests that exercise the DB→render→parse round-trip for ROADMAP (slices with completion state, depends, risk) and PLAN (tasks with verify, files, description). These prove R014: renderer fidelity during the transition window. -4. **Test updates** — Update dispatch-guard.test.ts to seed DB state instead of writing markdown files. This is downstream of the dispatch-guard migration. - -### Verification Approach - -- Run all existing tests with the resolver harness to confirm no regressions: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/dispatch-guard.test.ts src/resources/extensions/gsd/tests/derive-state-crossval.test.ts` -- Run new cross-validation tests: the new test file proves DB↔parsed field parity across multiple fixture scenarios -- Run slice-level proof: all S04 test files pass under the resolver harness -- Verify the four hot-path files no longer import parser functions (grep for `parseRoadmapSlices`, `parseRoadmap`, `parsePlan` in the migrated files) - -## Constraints - -- **Resolver-based test harness required** — Tests must run under `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test`. Bare `node --test` fails on `.js` sibling specifiers. -- **No ESM monkey-patching for cache tests** — Verify cache invalidation through observable parse-visible state, not by spying on imported ESM bindings. This was learned in S01 and recorded in KNOWLEDGE.md. -- **`deleteTask()` requires manual FK cascade** — No `ON DELETE CASCADE` in schema. When tests clean up: evidence → tasks → slices. This matters if cross-validation tests need teardown between scenarios. -- **`upsertSlicePlanning()` vs `updateSliceFields()`** — Planning fields use the former, basic metadata (title, risk, depends, demo) uses the latter. Caller migration code should use the existing query functions, not introduce new ones. -- **`dispatch-guard.ts` reads from working tree, not git** — The migration must preserve this semantic: DB state is always current (like disk), not committed state. Since DB is the write target for planning tools, this is satisfied by default. -- **`parallel-eligibility.ts` uses `deriveState()`** — This file also calls `deriveState(basePath)` for milestone status. That function already has a DB path (`deriveStateFromDb`). The migration should not change the `deriveState` call — only replace the parser calls within `collectTouchedFiles`. - -## Common Pitfalls - -- **Forgetting fallback when DB is empty** — dispatch-guard and auto-dispatch currently read from disk. If DB has no slices (pre-migration project), `getMilestoneSlices()` returns `[]` which could unblock all dispatches incorrectly. Callers should check for empty DB results and potentially fall back to disk parsing during the transition, OR the migration path (S05's `migrateHierarchyToDb`) guarantees DB is populated before callers run. -- **`ORDER BY sequence, id` with NULL sequence** — SQLite sorts NULLs first by default. Use `ORDER BY COALESCE(sequence, 999999), id` or `DEFAULT 0` to ensure pre-migration rows sort lexicographically by id when sequence hasn't been set. -- **dispatch-guard test coupling to markdown format** — The 187-line test file writes ROADMAP markdown to disk and tests the function. After migration, these fixtures need DB seeding instead. Don't try to make the function work with both paths simultaneously — pick DB and update tests. -- **Removing too many imports from auto-dispatch.ts** — Only 3 of the 18 rules use `parseRoadmap`. The file still has other `loadFile` and `parseRoadmap` usages outside S04's scope (warm/cold callers in S05). Only narrow the import, don't remove it entirely yet. diff --git a/.gsd/milestones/M001/slices/S04/S04-SUMMARY.md b/.gsd/milestones/M001/slices/S04/S04-SUMMARY.md deleted file mode 100644 index 42504b411..000000000 --- a/.gsd/milestones/M001/slices/S04/S04-SUMMARY.md +++ /dev/null @@ -1,139 +0,0 @@ ---- -id: S04 -parent: M001 -milestone: M001 -provides: - - Hot-path callers migrated to DB — dispatch loop no longer parses markdown for planning state - - Sequence-aware query ordering proven in getMilestoneSlices/getSliceTasks — ORDER BY sequence, id - - Cross-validation test infrastructure — planning-crossval.test.ts pattern for DB↔rendered↔parsed parity - - isDbAvailable() + lazy createRequire fallback pattern — reusable for S05 warm/cold caller migration - - Schema v9 with sequence column on slices and tasks tables -requires: - - slice: S01 - provides: Schema v8, insertMilestonePlanning/getMilestonePlanning query functions, renderRoadmapFromDb, tool handler pattern - - slice: S02 - provides: getSliceTasks/getTask query functions, renderPlanFromDb/renderTaskPlanFromDb renderers, slice/task v8 columns populated -affects: - - S05 - - S06 -key_files: - - src/resources/extensions/gsd/gsd-db.ts - - src/resources/extensions/gsd/dispatch-guard.ts - - src/resources/extensions/gsd/auto-dispatch.ts - - src/resources/extensions/gsd/auto-verification.ts - - src/resources/extensions/gsd/parallel-eligibility.ts - - src/resources/extensions/gsd/markdown-renderer.ts - - src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts - - src/resources/extensions/gsd/tests/dispatch-guard.test.ts - - src/resources/extensions/gsd/tests/planning-crossval.test.ts -key_decisions: - - Used lazy createRequire with .ts/.js extension fallback instead of dynamic import() — keeps hot-path callers synchronous, avoiding cascading async changes (D007) - - Added sequence column to initial CREATE TABLE DDL in addition to migration block — required for fresh databases that skip migrations - - Fixed renderRoadmapMarkdown depends serialization from JSON.stringify to join-based — required for parser round-trip parity - - Kept loadFile in auto-dispatch.ts module imports — still used by 15 other rules for non-planning file content - - TaskRow.files already parsed as string[] by rowToTask() — no additional JSON.parse needed in consumer code -patterns_established: - - isDbAvailable() gate + lazy createRequire fallback — standard pattern for migrating synchronous callers from parser to DB queries without breaking call chain signatures - - Cross-validation test pattern (planning-crossval.test.ts) — DB→render→parse round-trip parity tests for planning artifacts, following derive-state-crossval.test.ts for completion artifacts - - Sequence-aware query ordering — ORDER BY sequence, id with DEFAULT 0 fallback ensures reassessment reordering propagates through all readers -observability_surfaces: - - isDbAvailable() gate in 4 migrated files — stderr diagnostic when DB unavailable and fallback to disk parse - - SQLite slices.sequence and tasks.sequence columns — inspect via SELECT id, sequence FROM slices ORDER BY sequence, id - - schema-v9-sequence.test.ts — 7 tests covering migration, ordering, defaults - - dispatch-guard.test.ts — 8 tests with DB seeding (primary DB-path verification) - - planning-crossval.test.ts — 65 assertions across 3 cross-validation scenarios - - SCHEMA_VERSION=9 — verify via PRAGMA user_version on DB file -drill_down_paths: - - .gsd/milestones/M001/slices/S04/tasks/T01-SUMMARY.md - - .gsd/milestones/M001/slices/S04/tasks/T02-SUMMARY.md - - .gsd/milestones/M001/slices/S04/tasks/T03-SUMMARY.md - - .gsd/milestones/M001/slices/S04/tasks/T04-SUMMARY.md -duration: "" -verification_result: passed -completed_at: 2026-03-23T17:21:49.297Z -blocker_discovered: false ---- - -# S04: Hot-path caller migration + cross-validation tests - -**Six hot-path dispatch-loop callers migrated from markdown parsing to DB queries, with 65-assertion cross-validation tests proving DB↔rendered↔parsed parity and schema v9 sequence-aware ordering.** - -## What Happened - -This slice eliminated markdown parsing from the auto-mode dispatch loop's hottest code paths, replacing 6 parser callers across 4 files with SQLite DB queries. - -**T01 — Schema v9 + sequence ordering:** Added `sequence INTEGER DEFAULT 0` to both `slices` and `tasks` tables via a v9 migration block, plus updated initial CREATE TABLE DDL for fresh databases. All 4 slice/task ORDER BY queries changed from `ORDER BY id` to `ORDER BY sequence, id`. Updated `SliceRow`/`TaskRow` interfaces and `insertSlice`/`insertTask` to accept optional sequence params. 7 tests verify migration, ordering, and defaults. - -**T02 — dispatch-guard.ts migration:** Replaced `parseRoadmapSlices(roadmapContent)` with `getMilestoneSlices(mid)` behind an `isDbAvailable()` gate. Lazy `createRequire`-based fallback loads parser only when DB is unavailable, keeping the function synchronous (avoiding cascading async changes through loop-deps.ts and phases.ts). All 8 test cases rewritten to seed state via `openDatabase`/`insertMilestone`/`insertSlice` instead of writing ROADMAP markdown. `findMilestoneIds()` still reads disk for milestone queue ordering (out of scope). - -**T03 — auto-dispatch.ts, auto-verification.ts, parallel-eligibility.ts migration:** Applied the same `isDbAvailable()` + lazy `createRequire` fallback pattern to the remaining 3 files. In auto-dispatch.ts, migrated 3 rules (uat-verdict-gate, validating-milestone, completing-milestone) from `parseRoadmap().slices` to `getMilestoneSlices(mid)`. In auto-verification.ts, replaced `parsePlan().tasks.find()` with `getTask(mid, sid, tid)?.verify`. In parallel-eligibility.ts, replaced both `parseRoadmap().slices` and `parsePlan().filesLikelyTouched` with DB queries. `loadFile` kept in auto-dispatch.ts for 15 other rules that read non-planning file content. - -**T04 — Cross-validation tests + renderer fix:** Created `planning-crossval.test.ts` with 3 test scenarios (65 assertions): ROADMAP round-trip (field parity for id, done/status, depends, risk, title across 4 slices), PLAN round-trip (task count, per-task fields, filesLikelyTouched aggregation), and sequence ordering (scrambled insertion order preserved through full round-trip). Discovered and fixed a depends-quoting bug in `renderRoadmapMarkdown()` — JSON.stringify produced quoted strings that didn't survive parser round-trip. Changed to unquoted join format. - -## Verification - -**Slice-level verification (all pass):** -1. schema-v9-sequence.test.ts — 7/7 pass (migration, ordering, defaults) -2. dispatch-guard.test.ts — 8/8 pass (DB-seeded dispatch blocking/allowing) -3. planning-crossval.test.ts — 65/65 assertions across 3 scenarios (DB↔rendered↔parsed parity) -4. No module-level parser imports in dispatch-guard.ts, auto-dispatch.ts, auto-verification.ts, parallel-eligibility.ts — verified via grep -5. No module-level parseRoadmap in auto-dispatch.ts — only lazy fallback references -6. getMilestoneSlices('NONEXISTENT') returns [] — graceful empty-state handling - -**Regression suites (confirmed passing by task executors):** -- plan-milestone.test.ts — 15/15 -- plan-slice.test.ts, plan-task.test.ts — all pass -- integration-mixed-milestones.test.ts — 54/54 (exercises disk-parse fallback) -- markdown-renderer.test.ts — 106/106 (renderer depends fix regression) -- derive-state-crossval.test.ts — 189/189 (renderer fix regression) -- auto-recovery.test.ts — 33/33 - -## Requirements Advanced - -None. - -## Requirements Validated - -- R009 — dispatch-guard.ts, auto-dispatch.ts (3 rules), auto-verification.ts, parallel-eligibility.ts all migrated to DB queries. Zero module-level parser imports. Tests: dispatch-guard.test.ts 8/8, integration-mixed-milestones.test.ts 54/54. -- R014 — planning-crossval.test.ts — 65 assertions across 3 scenarios proving DB→render→parse round-trip parity for ROADMAP, PLAN, and sequence ordering. -- R016 — Schema v9 adds sequence column. All 4 slice/task ORDER BY queries use ORDER BY sequence, id. schema-v9-sequence.test.ts 7/7 plus cross-validation test 3 proves ordering survives render→parse round-trip. - -## New Requirements Surfaced - -None. - -## Requirements Invalidated or Re-scoped - -None. - -## Deviations - -1. Depends-quoting fix in markdown-renderer.ts (T04): renderRoadmapMarkdown() used JSON.stringify for depends arrays, producing quoted strings that broke parser round-trip. Changed to unquoted join format. This was a genuine parity bug, not scope creep — required for cross-validation tests to pass. - -2. Sequence column in CREATE TABLE DDL (T01): Added to initial DDL, not just migration block. Fresh databases skip migrations, so the column must be in the CREATE TABLE statement. - -3. createRequire pattern instead of dynamic import() (T02, applied in T03): Kept callers synchronous to avoid cascading async changes through loop-deps.ts, phases.ts, and test mocks. Not planned but architecturally necessary. - -## Known Limitations - -1. findMilestoneIds() in dispatch-guard.ts still reads milestone directories from disk for queue ordering — DB doesn't own milestone queue discovery. This is acceptable because milestone discovery is a directory scan, not a parser call. - -2. Lazy createRequire fallback blocks use the parser at runtime when DB is unavailable. The parsers aren't removed — they're moved from module-level imports to lazy-loaded fallback paths. Full parser removal happens in S06. - -3. 15 of 18 auto-dispatch.ts rules still use loadFile for non-planning content (UAT files, context files). These are warm/cold callers, not hot-path planning callers — migrated in S05. - -## Follow-ups - -None. All remaining work (warm/cold callers, flag files, parser removal) is already planned in S05 and S06. - -## Files Created/Modified - -- `src/resources/extensions/gsd/gsd-db.ts` — Schema v9 migration (sequence column on slices/tasks), ORDER BY sequence,id in 4 queries, insertSlice/insertTask accept sequence param -- `src/resources/extensions/gsd/dispatch-guard.ts` — Migrated from parseRoadmapSlices to getMilestoneSlices with isDbAvailable gate and lazy createRequire fallback -- `src/resources/extensions/gsd/auto-dispatch.ts` — Migrated 3 rules (uat-verdict-gate, validating-milestone, completing-milestone) from parseRoadmap to getMilestoneSlices with fallback -- `src/resources/extensions/gsd/auto-verification.ts` — Migrated from parsePlan to getTask with isDbAvailable gate and lazy createRequire fallback -- `src/resources/extensions/gsd/parallel-eligibility.ts` — Migrated from parseRoadmap+parsePlan to getMilestoneSlices+getSliceTasks with isDbAvailable gate and lazy fallback -- `src/resources/extensions/gsd/markdown-renderer.ts` — Fixed depends serialization from JSON.stringify to unquoted join for parser round-trip parity -- `src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts` — New: 7 tests for schema v9 migration, sequence ordering, defaults -- `src/resources/extensions/gsd/tests/dispatch-guard.test.ts` — Rewritten: 8 tests now seed state via DB instead of writing ROADMAP markdown files -- `src/resources/extensions/gsd/tests/planning-crossval.test.ts` — New: 65 assertions across 3 cross-validation scenarios proving DB↔rendered↔parsed parity diff --git a/.gsd/milestones/M001/slices/S04/S04-UAT.md b/.gsd/milestones/M001/slices/S04/S04-UAT.md deleted file mode 100644 index 196131f2a..000000000 --- a/.gsd/milestones/M001/slices/S04/S04-UAT.md +++ /dev/null @@ -1,94 +0,0 @@ -# S04: Hot-path caller migration + cross-validation tests — UAT - -**Milestone:** M001 -**Written:** 2026-03-23T17:21:49.297Z - -# S04: Hot-path caller migration + cross-validation tests — UAT - -**Milestone:** M001 -**Written:** 2026-03-23 - -## UAT Type - -- UAT mode: artifact-driven -- Why this mode is sufficient: All verification is through automated tests (DB queries, parser comparison, grep for imports) — no runtime behavior or human-facing UI to test - -## Preconditions - -- Working directory is the gsd-2 repo root -- Node.js with `--experimental-strip-types` support available -- No running DB connections (tests use in-memory SQLite) - -## Smoke Test - -Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/planning-crossval.test.ts` and verify 65/65 assertions pass across 3 scenarios. This single test proves the core deliverable: DB state survives render→parse round-trip. - -## Test Cases - -### 1. Schema v9 sequence ordering - -1. Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts` -2. **Expected:** 7/7 tests pass covering migration, sequence-based ordering for slices and tasks, default fallback, and active-slice/task resolution - -### 2. Dispatch guard DB migration - -1. Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/dispatch-guard.test.ts` -2. **Expected:** 8/8 tests pass with DB-seeded state (not markdown files) - -### 3. Cross-validation parity - -1. Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/planning-crossval.test.ts` -2. **Expected:** 65/65 assertions pass across 3 scenarios (ROADMAP parity, PLAN parity, sequence ordering parity) - -### 4. No module-level parser imports in migrated files - -1. Run `grep -n '^import.*parseRoadmapSlices\|^import.*parseRoadmap\|^import.*parsePlan' src/resources/extensions/gsd/dispatch-guard.ts src/resources/extensions/gsd/auto-dispatch.ts src/resources/extensions/gsd/auto-verification.ts src/resources/extensions/gsd/parallel-eligibility.ts` -2. **Expected:** No output (exit code 1) — zero module-level parser imports - -### 5. Disk-parse fallback path - -1. Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts` -2. **Expected:** 54/54 pass — these tests don't seed DB, so they exercise the lazy createRequire disk-parse fallback - -### 6. Renderer regression after depends fix - -1. Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts` -2. **Expected:** 106/106 pass — depends serialization change doesn't break existing rendering - -## Edge Cases - -### Empty milestone (no slices in DB) - -1. Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types -e "import{openDatabase,getMilestoneSlices}from'./src/resources/extensions/gsd/gsd-db.ts';openDatabase(':memory:');console.log(JSON.stringify(getMilestoneSlices('NONEXISTENT')))"` -2. **Expected:** Outputs `[]` — no crash, graceful empty-state handling - -### Sequence defaults to 0 - -1. In schema-v9-sequence.test.ts, test "sequence field defaults to 0 when not provided" verifies that slices/tasks inserted without explicit sequence get `sequence: 0` -2. **Expected:** Passes — backward compatible with pre-v9 data - -## Failure Signals - -- Any module-level `import ... parseRoadmap` or `import ... parsePlan` in the 4 migrated files -- planning-crossval.test.ts assertion failures indicating field mismatch between DB and parsed-back state -- dispatch-guard.test.ts failures indicating DB seeding doesn't produce correct blocking behavior -- integration-mixed-milestones.test.ts failures indicating broken disk-parse fallback - -## Requirements Proved By This UAT - -- R009 — All 6 hot-path parser callers migrated to DB queries (test cases 1-5) -- R014 — Cross-validation tests prove DB↔rendered↔parsed parity (test case 3) -- R016 — Sequence-aware ordering in all queries (test cases 1, 3) - -## Not Proven By This UAT - -- Live auto-mode runtime behavior (auto-dispatch rules exercised via integration tests, not live dispatch loop) -- S05 warm/cold callers (doctor, visualizer, github-sync, etc.) -- S06 parser removal from hot paths -- Flag file migration (CONTINUE, CONTEXT-DRAFT, etc.) - -## Notes for Tester - -- All tests use in-memory SQLite — no persistent DB files to clean up -- The lazy createRequire fallback references will still match grep for parser names in function bodies — this is intentional; only module-level imports should be absent -- `loadFile` remains in auto-dispatch.ts module imports — it's used by 15 non-planning rules and is not a parser caller diff --git a/.gsd/milestones/M001/slices/S04/tasks/T01-PLAN.md b/.gsd/milestones/M001/slices/S04/tasks/T01-PLAN.md deleted file mode 100644 index 6a401cbfd..000000000 --- a/.gsd/milestones/M001/slices/S04/tasks/T01-PLAN.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -estimated_steps: 5 -estimated_files: 2 -skills_used: [] ---- - -# T01: Add schema v9 migration with sequence column and fix ORDER BY queries - -**Slice:** S04 — Hot-path caller migration + cross-validation tests -**Milestone:** M001 - -## Description - -Add a `sequence INTEGER DEFAULT 0` column to the `slices` and `tasks` tables via a schema v9 migration block. Update all six `ORDER BY id` queries in gsd-db.ts to `ORDER BY sequence, id` so rows sort by explicit sequence first, falling back to lexicographic id when sequence is 0 or equal. Update the `SliceRow` and `TaskRow` TypeScript interfaces to include the new field. Write a test file proving the migration works and ordering respects sequence. - -## Steps - -1. In `src/resources/extensions/gsd/gsd-db.ts`, bump `SCHEMA_VERSION` from 8 to 9. -2. Add a `currentVersion < 9` migration block after the v8 block. Use `ensureColumn()` to add `sequence INTEGER DEFAULT 0` to both `slices` and `tasks` tables. Insert schema_version row for version 9. -3. Add `sequence: number` to both `SliceRow` and `TaskRow` interfaces. -4. Update all 6 `ORDER BY id` queries to `ORDER BY sequence, id`: - - `getSliceTasks()` (line ~1245): `ORDER BY sequence, id` - - `getAllMilestones()` (line ~1341): keep `ORDER BY id` (milestones don't have sequence) - - `getActiveMilestoneFromDb()` (line ~1355): keep `ORDER BY id` - - `getActiveSliceFromDb()` (line ~1364): `ORDER BY sequence, id` - - `getActiveTaskFromDb()` (line ~1385): `ORDER BY sequence, id` - - `getMilestoneSlices()` (line ~1393): `ORDER BY sequence, id` -5. Write `src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts` with tests: - - Migration adds `sequence` column to both tables - - `getMilestoneSlices()` returns slices ordered by sequence then id - - `getSliceTasks()` returns tasks ordered by sequence then id - - Default sequence (0) falls back to id-based ordering - - `insertSlice` / `insertTask` accept the sequence field - -## Must-Haves - -- [ ] `SCHEMA_VERSION` is 9 -- [ ] `sequence INTEGER DEFAULT 0` exists on both `slices` and `tasks` tables after migration -- [ ] `SliceRow` and `TaskRow` interfaces include `sequence: number` -- [ ] All slice/task queries use `ORDER BY sequence, id` -- [ ] Test file passes under resolver harness - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts` -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts` (no regressions) - -## Inputs - -- `src/resources/extensions/gsd/gsd-db.ts` — current schema v8 migration, query functions, SliceRow/TaskRow interfaces -- `src/resources/extensions/gsd/tests/resolve-ts.mjs` — test resolver harness - -## Expected Output - -- `src/resources/extensions/gsd/gsd-db.ts` — updated with schema v9, sequence field, ORDER BY changes -- `src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts` — new test file proving sequence ordering - -## Observability Impact - -- **Schema version**: `SCHEMA_VERSION` constant changes from 8 → 9; `schema_version` table gains a row for version 9 with timestamp -- **Column visibility**: `PRAGMA table_info(slices)` and `PRAGMA table_info(tasks)` now show `sequence INTEGER DEFAULT 0` -- **Query ordering**: All slice/task list queries sort by `sequence, id` — inspectable via `EXPLAIN QUERY PLAN` or by inserting rows with non-lexicographic sequence values -- **Failure state**: `getMilestoneSlices('NONEXISTENT')` returns `[]` (empty array, no crash); `getSliceTasks` with no DB open returns `[]` -- **Interface change**: `SliceRow.sequence` and `TaskRow.sequence` fields available to all downstream consumers diff --git a/.gsd/milestones/M001/slices/S04/tasks/T01-SUMMARY.md b/.gsd/milestones/M001/slices/S04/tasks/T01-SUMMARY.md deleted file mode 100644 index 061270474..000000000 --- a/.gsd/milestones/M001/slices/S04/tasks/T01-SUMMARY.md +++ /dev/null @@ -1,72 +0,0 @@ ---- -id: T01 -parent: S04 -milestone: M001 -key_files: - - src/resources/extensions/gsd/gsd-db.ts - - src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts - - .gsd/milestones/M001/slices/S04/S04-PLAN.md - - .gsd/milestones/M001/slices/S04/tasks/T01-PLAN.md -key_decisions: - - Added sequence column to initial CREATE TABLE DDL in addition to migration block — required for fresh databases that skip migrations - - Used INTEGER DEFAULT 0 (not NOT NULL) for sequence column to keep it nullable-safe and backward compatible -observability_surfaces: - - "SQLite slices.sequence and tasks.sequence columns — inspect via SELECT id, sequence FROM slices ORDER BY sequence, id" - - "SCHEMA_VERSION=9 — verify via PRAGMA user_version on the DB file" - - "schema-v9-sequence.test.ts — 7 tests covering migration, ordering, defaults" -duration: "" -verification_result: passed -completed_at: 2026-03-23T16:57:23.834Z -blocker_discovered: false ---- - -# T01: Add schema v9 migration with sequence column on slices/tasks tables and fix ORDER BY queries to use sequence, id - -**Add schema v9 migration with sequence column on slices/tasks tables and fix ORDER BY queries to use sequence, id** - -## What Happened - -Added a `sequence INTEGER DEFAULT 0` column to both `slices` and `tasks` tables via two changes: (1) updated the initial CREATE TABLE definitions so fresh databases include the column from the start, and (2) added a `currentVersion < 9` migration block using `ensureColumn()` for existing databases upgrading from v8. Bumped `SCHEMA_VERSION` from 8 to 9. - -Updated both `SliceRow` and `TaskRow` TypeScript interfaces to include `sequence: number`, and updated their `rowToSlice`/`rowToTask` converter functions to read the field with a `?? 0` fallback. - -Updated all 4 slice/task `ORDER BY id` queries to `ORDER BY sequence, id`: `getSliceTasks()`, `getActiveSliceFromDb()`, `getActiveTaskFromDb()`, and `getMilestoneSlices()`. Left the 2 milestone queries (`getAllMilestones`, `getActiveMilestoneFromDb`) using `ORDER BY id` as milestones don't have a sequence column. - -Updated `insertSlice` and `insertTask` to accept an optional `sequence` parameter, defaulting to 0. - -Wrote 7 tests covering: migration adds columns, sequence-based ordering for slices and tasks, default sequence=0 falls back to id ordering, `getActiveSliceFromDb` and `getActiveTaskFromDb` respect sequence, and sequence defaults to 0 when not provided. - -Also addressed the pre-flight observability gaps: added a diagnostic verification step to S04-PLAN.md and an Observability Impact section to T01-PLAN.md. - -## Verification - -Ran schema-v9-sequence test suite: 7/7 pass. Ran plan-milestone, plan-slice, plan-task regression tests: 15/15 pass. Verified SCHEMA_VERSION=9. Verified all 4 slice/task ORDER BY queries use `sequence, id`. Verified milestone ORDER BY queries remain `ORDER BY id`. - -## Verification Evidence - -| # | Command | Exit Code | Verdict | Duration | -|---|---------|-----------|---------|----------| -| 1 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts` | 0 | ✅ pass | 203ms | -| 2 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/plan-milestone.test.ts src/resources/extensions/gsd/tests/plan-slice.test.ts src/resources/extensions/gsd/tests/plan-task.test.ts` | 0 | ✅ pass | 207ms | - - -## Deviations - -Added `sequence INTEGER DEFAULT 0` to the initial CREATE TABLE definitions for slices and tasks (not just the migration block). This was necessary because fresh databases created via `openDatabase` use the CREATE TABLE DDL directly — the migration block only runs for existing DBs upgrading from a prior version. Without this, insertSlice/insertTask would fail on fresh DBs because the column wouldn't exist. - -## Known Issues - -None. - -## Diagnostics - -- Verify schema version: `node -e "const db=require('better-sqlite3')('path/to/gsd.db'); console.log(db.pragma('user_version'))"` — should return `[{ user_version: 9 }]` -- Inspect sequence values: `SELECT id, sequence FROM slices WHERE milestone_id='M001' ORDER BY sequence, id` in the SQLite DB -- Run regression: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts` - -## Files Created/Modified - -- `src/resources/extensions/gsd/gsd-db.ts` -- `src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts` -- `.gsd/milestones/M001/slices/S04/S04-PLAN.md` -- `.gsd/milestones/M001/slices/S04/tasks/T01-PLAN.md` diff --git a/.gsd/milestones/M001/slices/S04/tasks/T01-VERIFY.json b/.gsd/milestones/M001/slices/S04/tasks/T01-VERIFY.json deleted file mode 100644 index 34caa973a..000000000 --- a/.gsd/milestones/M001/slices/S04/tasks/T01-VERIFY.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "schemaVersion": 1, - "taskId": "T01", - "unitId": "M001/S04/T01", - "timestamp": 1774285048330, - "passed": false, - "discoverySource": "package-json", - "checks": [ - { - "command": "npm run test", - "exitCode": 1, - "durationMs": 39381, - "verdict": "fail" - } - ], - "retryAttempt": 1, - "maxRetries": 2 -} diff --git a/.gsd/milestones/M001/slices/S04/tasks/T02-PLAN.md b/.gsd/milestones/M001/slices/S04/tasks/T02-PLAN.md deleted file mode 100644 index f54b8187b..000000000 --- a/.gsd/milestones/M001/slices/S04/tasks/T02-PLAN.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -estimated_steps: 5 -estimated_files: 2 -skills_used: [] ---- - -# T02: Migrate dispatch-guard.ts to DB queries and update tests - -**Slice:** S04 — Hot-path caller migration + cross-validation tests -**Milestone:** M001 - -## Description - -Replace `parseRoadmapSlices()` in `dispatch-guard.ts` with `getMilestoneSlices()` from `gsd-db.ts`. The function `getPriorSliceCompletionBlocker()` currently reads ROADMAP.md from disk and parses it — change it to query DB state. Update all 8 test cases in `dispatch-guard.test.ts` to seed DB via `insertMilestone`/`insertSlice` instead of writing markdown files. Add an `isDbAvailable()` gate with disk-parse fallback so the function works during pre-migration bootstrapping. - -## Steps - -1. In `dispatch-guard.ts`, add imports: `import { isDbAvailable, getMilestoneSlices } from "./gsd-db.js"`. Keep `findMilestoneIds` import from `./guided-flow.js` (milestone queue order is disk-based). -2. Replace the body of the milestone-iteration loop: - - When `isDbAvailable()`: call `getMilestoneSlices(mid)` to get `SliceRow[]`. Map each row: `done = (row.status === 'complete')`, `id = row.id`, `depends = row.depends` (already `string[]`). Use the same slice-dispatch logic (dependency check or positional fallback). - - When `!isDbAvailable()`: keep the existing `readRoadmapFromDisk()` + `parseRoadmapSlices()` path as fallback. -3. Remove the `readFileSync` import if it's no longer used outside the fallback. Keep `readdirSync` if still needed. Remove `parseRoadmapSlices` import from `./roadmap-slices.js` — move it inside the fallback branch or use a lazy import to avoid importing the parser when DB is available. -4. Update `dispatch-guard.test.ts`: - - Add imports: `openDatabase`, `closeDatabase`, `insertMilestone`, `insertSlice` from `../gsd-db.ts`. - - In each test: create a temp dir, call `openDatabase(join(repo, '.gsd', 'gsd.db'))` to seed DB state. Call `insertMilestone()` and `insertSlice()` with appropriate `status` values (`'complete'` for done slices, `'pending'` for undone ones). Set `depends` arrays on slices that declare dependencies. - - Remove `writeFileSync` calls that created ROADMAP markdown files. - - Add `closeDatabase()` in `finally` blocks before `rmSync`. - - For the milestone-SUMMARY skip test: still write a SUMMARY file on disk (dispatch-guard checks `resolveMilestoneFile(base, mid, "SUMMARY")` to skip completed milestones). - - For the PARKED skip test: still write PARKED file on disk. -5. Run the test suite and confirm all 8 tests pass. - -## Must-Haves - -- [ ] `dispatch-guard.ts` calls `getMilestoneSlices()` instead of `parseRoadmapSlices()` when DB is available -- [ ] Fallback to disk parsing when `!isDbAvailable()` -- [ ] All 8 existing tests pass with DB seeding -- [ ] Zero `parseRoadmapSlices` import at module level in dispatch-guard.ts - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/dispatch-guard.test.ts` -- `rg 'parseRoadmapSlices' src/resources/extensions/gsd/dispatch-guard.ts` returns no matches (or only in fallback block) - -## Inputs - -- `src/resources/extensions/gsd/dispatch-guard.ts` — current 106-line file using `parseRoadmapSlices` -- `src/resources/extensions/gsd/tests/dispatch-guard.test.ts` — current 187-line test file with 8 test cases writing ROADMAP markdown -- `src/resources/extensions/gsd/gsd-db.ts` — `getMilestoneSlices()`, `isDbAvailable()`, `insertMilestone()`, `insertSlice()`, `openDatabase()`, `closeDatabase()` - -## Expected Output - -- `src/resources/extensions/gsd/dispatch-guard.ts` — migrated to DB queries with disk fallback -- `src/resources/extensions/gsd/tests/dispatch-guard.test.ts` — updated to seed DB state - -## Observability Impact - -- **Signal change**: `getPriorSliceCompletionBlocker()` now reads slice status from `slices` table via `getMilestoneSlices()` when DB is open, instead of parsing ROADMAP.md from disk. The returned blocker string is unchanged — callers see no difference. -- **Inspection**: To verify DB path is active, check that `isDbAvailable()` returns `true` before calling `getPriorSliceCompletionBlocker()`. Inspect the `slices` table (`SELECT id, status, depends FROM slices WHERE milestone_id = ?`) to see exactly what the guard evaluates. -- **Fallback visibility**: When DB is unavailable, the guard falls back to disk parsing via `lazyParseRoadmapSlices()`. No stderr warning is emitted from this function (the `isDbAvailable()` check is silent), but downstream callers can detect fallback by checking `isDbAvailable()` before dispatch. -- **Failure state**: If `getMilestoneSlices()` returns an empty array for a milestone that has slices on disk, the guard silently skips that milestone (same as when no ROADMAP file exists). This is safe — it means no blocking, not false blocking. diff --git a/.gsd/milestones/M001/slices/S04/tasks/T02-SUMMARY.md b/.gsd/milestones/M001/slices/S04/tasks/T02-SUMMARY.md deleted file mode 100644 index 1ff109552..000000000 --- a/.gsd/milestones/M001/slices/S04/tasks/T02-SUMMARY.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -id: T02 -parent: S04 -milestone: M001 -key_files: - - src/resources/extensions/gsd/dispatch-guard.ts - - src/resources/extensions/gsd/tests/dispatch-guard.test.ts - - .gsd/milestones/M001/slices/S04/tasks/T02-PLAN.md -key_decisions: - - Used createRequire with try .ts/.js fallback for lazy parser loading instead of dynamic import() — keeps getPriorSliceCompletionBlocker synchronous, avoiding cascading async changes to loop-deps.ts, phases.ts, and all test mocks - - Kept minimal ROADMAP stub files on disk in tests because findMilestoneIds() reads milestone directories from disk for queue ordering — DB migration of milestone discovery is out of scope for this task -observability_surfaces: - - "dispatch-guard.ts isDbAvailable() gate — stderr diagnostic when DB unavailable and fallback to disk parse" - - "dispatch-guard.test.ts — 8 tests covering DB-seeded dispatch blocking/allowing" - - "integration-mixed-milestones.test.ts — 54 tests exercising disk-parse fallback path" -duration: "" -verification_result: passed -completed_at: 2026-03-23T17:03:27.608Z -blocker_discovered: false ---- - -# T02: Migrate dispatch-guard.ts to DB queries with isDbAvailable() gate and lazy disk-parse fallback - -**Migrate dispatch-guard.ts to DB queries with isDbAvailable() gate and lazy disk-parse fallback** - -## What Happened - -Migrated `getPriorSliceCompletionBlocker()` in `dispatch-guard.ts` from parsing ROADMAP.md files via `parseRoadmapSlices()` to querying the `slices` table via `getMilestoneSlices()` from `gsd-db.ts`. - -**dispatch-guard.ts changes:** -- Replaced module-level `parseRoadmapSlices` import with `isDbAvailable()` + `getMilestoneSlices()` from `gsd-db.js` -- Added `isDbAvailable()` gate: when DB is open, maps `SliceRow[]` to normalised `{id, done, depends}` objects; when DB is unavailable, falls back to disk parsing via a lazy `createRequire`-based loader -- The lazy loader (`lazyParseRoadmapSlices`) uses `createRequire(import.meta.url)` and tries `.ts` first (strip-types dev), then `.js` (compiled production) — avoids module-level import of the parser -- Removed unused `readdirSync` and `milestonesDir` imports; kept `readFileSync` for the disk fallback path -- Function signature and return type unchanged — no cascading changes to callers - -**dispatch-guard.test.ts changes:** -- All 8 test cases now seed state via `openDatabase()` + `insertMilestone()` + `insertSlice()` instead of writing ROADMAP markdown files -- Added `setupRepo()` / `teardownRepo()` helpers for consistent DB lifecycle (open before test, close in finally) -- Milestone directory + minimal ROADMAP stub still written for `findMilestoneIds()` which reads disk for milestone discovery -- SUMMARY file still written on disk for the SUMMARY-skip test (dispatch-guard checks `resolveMilestoneFile`) - -**Integration tests:** The `integration-mixed-milestones.test.ts` suite (54 sub-tests) passes — these tests don't seed DB, so they exercise the disk-parse fallback path, confirming both code paths work. - -## Verification - -1. `dispatch-guard.test.ts` — all 8 tests pass with DB seeding -2. `integration-mixed-milestones.test.ts` — all 54 sub-tests pass (exercises fallback path) -3. `schema-v9-sequence.test.ts` — all 7 tests pass (T01 regression) -4. `grep parseRoadmapSlices dispatch-guard.ts` — only matches in lazy fallback block (lines 17,19), zero module-level imports -5. Diagnostic: `getMilestoneSlices('NONEXISTENT')` returns `[]` (no crash on missing milestone) - -## Verification Evidence - -| # | Command | Exit Code | Verdict | Duration | -|---|---------|-----------|---------|----------| -| 1 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/dispatch-guard.test.ts` | 0 | ✅ pass | 614ms | -| 2 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts` | 0 | ✅ pass | 749ms | -| 3 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts` | 0 | ✅ pass | 137ms | -| 4 | `grep -c parseRoadmapSlices dispatch-guard.ts (module-level imports)` | 0 | ✅ pass — only in lazy fallback block | 5ms | -| 5 | `node --import resolve-ts.mjs -e 'getMilestoneSlices(NONEXISTENT)' diagnostic` | 0 | ✅ pass — returns [] | 200ms | - - -## Deviations - -The task plan suggested removing `readFileSync` import if no longer needed outside fallback — it's still needed for the `readRoadmapFromDisk()` fallback function, so it was kept. The `readdirSync` import and `milestonesDir` import were removed as they were unused. The lazy import approach uses `createRequire` with try/catch for .ts/.js extension resolution instead of a dynamic `import()`, keeping the function synchronous and avoiding cascading async changes to the call chain. - -## Known Issues - -None. - -## Diagnostics - -- Verify no module-level parser imports: `grep -n '^import.*parseRoadmapSlices' src/resources/extensions/gsd/dispatch-guard.ts` — should return no matches -- Test DB path: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/dispatch-guard.test.ts` -- Test fallback path: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts` - -## Files Created/Modified - -- `src/resources/extensions/gsd/dispatch-guard.ts` -- `src/resources/extensions/gsd/tests/dispatch-guard.test.ts` -- `.gsd/milestones/M001/slices/S04/tasks/T02-PLAN.md` diff --git a/.gsd/milestones/M001/slices/S04/tasks/T02-VERIFY.json b/.gsd/milestones/M001/slices/S04/tasks/T02-VERIFY.json deleted file mode 100644 index 1458536e8..000000000 --- a/.gsd/milestones/M001/slices/S04/tasks/T02-VERIFY.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "schemaVersion": 1, - "taskId": "T02", - "unitId": "M001/S04/T02", - "timestamp": 1774285423761, - "passed": false, - "discoverySource": "package-json", - "checks": [ - { - "command": "npm run test", - "exitCode": 1, - "durationMs": 39568, - "verdict": "fail" - } - ], - "retryAttempt": 1, - "maxRetries": 2 -} diff --git a/.gsd/milestones/M001/slices/S04/tasks/T03-PLAN.md b/.gsd/milestones/M001/slices/S04/tasks/T03-PLAN.md deleted file mode 100644 index bb197a9fe..000000000 --- a/.gsd/milestones/M001/slices/S04/tasks/T03-PLAN.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -estimated_steps: 5 -estimated_files: 3 -skills_used: [] ---- - -# T03: Migrate auto-dispatch.ts, auto-verification.ts, and parallel-eligibility.ts to DB queries - -**Slice:** S04 — Hot-path caller migration + cross-validation tests -**Milestone:** M001 - -## Description - -Migrate the remaining hot-path parser callers to DB queries. Three files, each with a narrow transformation: replace parser calls with DB query functions, gate on `isDbAvailable()`, add disk-parse fallback. The auto-dispatch.ts changes touch only 3 of 18 rules — leave other `loadFile` usages untouched (those are S05 warm-path callers). - -## Steps - -1. **auto-dispatch.ts** — Migrate 3 rules that use `parseRoadmap()`: - - Add import: `import { isDbAvailable, getMilestoneSlices } from "./gsd-db.js"`. - - **uat-verdict-gate rule** (~line 176): Replace `parseRoadmap(roadmapContent).slices.filter(s => s.done)` with: if `isDbAvailable()`, use `getMilestoneSlices(mid).filter(s => s.status === 'complete')`. Map `slice.id` directly (same field). Keep the `resolveSliceFile` + `loadFile` for UAT-RESULT content reading (that's file content, not planning state). Else fall back to existing disk code. - - **validating-milestone rule** (~line 507): Replace `parseRoadmap(roadmapContent).slices` with: if `isDbAvailable()`, use `getMilestoneSlices(mid)`. Map `slice.id` directly for the `resolveSliceFile` SUMMARY existence check. Else fall back to existing disk code. - - **completing-milestone rule** (~line 564): Same pattern as validating-milestone — replace `parseRoadmap(roadmapContent).slices` with `getMilestoneSlices(mid)` when DB is available. - - Remove `parseRoadmap` from the import on line 15. Keep `loadFile`, `extractUatType`, `loadActiveOverrides`. - -2. **auto-verification.ts** — Migrate task verify lookup: - - Add import: `import { isDbAvailable, getTask } from "./gsd-db.js"`. - - At ~line 69-75: Replace the `loadFile(planFile)` → `parsePlan(planContent)` → `taskEntry?.verify` chain with: if `isDbAvailable()`, use `getTask(mid, sid, tid)?.verify`. Else fall back to existing disk code. - - Remove `parsePlan` and `loadFile` from imports. The remaining code in the file doesn't use either. - -3. **parallel-eligibility.ts** — Migrate `collectTouchedFiles()`: - - Add import: `import { isDbAvailable, getMilestoneSlices, getSliceTasks } from "./gsd-db.js"`. - - Replace `collectTouchedFiles()` body: if `isDbAvailable()`, use `getMilestoneSlices(milestoneId)` for slice list, then for each slice `getSliceTasks(milestoneId, slice.id)` → `flatMap(t => JSON.parse(t.files) or t.files)` for file paths. Note: `TaskRow.files` is `string[]` (already parsed by the getter). Else fall back to existing disk code. - - Remove `parseRoadmap`, `parsePlan`, `loadFile` from imports. The file still imports `resolveMilestoneFile` and `resolveSliceFile` for the disk fallback path. - -4. Verify no parser references remain in migrated call sites: - - `rg 'parseRoadmap' src/resources/extensions/gsd/auto-dispatch.ts` — should return zero matches - - `rg 'parsePlan|parseRoadmap' src/resources/extensions/gsd/auto-verification.ts` — zero matches - - `rg 'parsePlan|parseRoadmap' src/resources/extensions/gsd/parallel-eligibility.ts` — zero matches - -5. Run existing test suites to confirm no regressions (these files are exercised indirectly by integration tests). - -## Must-Haves - -- [ ] auto-dispatch.ts: 3 rules use `getMilestoneSlices()` instead of `parseRoadmap()`, with disk fallback -- [ ] auto-verification.ts: uses `getTask()?.verify` instead of `parsePlan()`, with disk fallback -- [ ] parallel-eligibility.ts: uses `getMilestoneSlices()` + `getSliceTasks()` instead of parsers, with disk fallback -- [ ] `parseRoadmap` removed from auto-dispatch.ts import -- [ ] `parsePlan` and `loadFile` removed from auto-verification.ts imports -- [ ] `parseRoadmap`, `parsePlan`, `loadFile` removed from parallel-eligibility.ts imports - -## Verification - -- `rg 'parseRoadmap' src/resources/extensions/gsd/auto-dispatch.ts` returns no matches -- `rg 'parsePlan|parseRoadmap' src/resources/extensions/gsd/auto-verification.ts` returns no matches -- `rg 'parsePlan|parseRoadmap' src/resources/extensions/gsd/parallel-eligibility.ts` returns no matches -- No TypeScript compilation errors in the modified files (check via `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types -e "import './src/resources/extensions/gsd/auto-dispatch.ts'; import './src/resources/extensions/gsd/auto-verification.ts'; import './src/resources/extensions/gsd/parallel-eligibility.ts'"` or equivalent) - -## Inputs - -- `src/resources/extensions/gsd/auto-dispatch.ts` — 656-line file, 3 rules using `parseRoadmap()` at lines ~176, ~507, ~564 -- `src/resources/extensions/gsd/auto-verification.ts` — 233-line file, `parsePlan()` at line ~71 -- `src/resources/extensions/gsd/parallel-eligibility.ts` — 233-line file, `parseRoadmap()` + `parsePlan()` in `collectTouchedFiles()` -- `src/resources/extensions/gsd/gsd-db.ts` — `isDbAvailable()`, `getMilestoneSlices()`, `getSliceTasks()`, `getTask()` - -## Observability Impact - -- **Signals changed:** `isDbAvailable()` gate in each migrated caller emits `process.stderr.write` diagnostic when DB is unavailable, making fallback events visible in auto-mode logs. -- **Inspection:** Future agents can confirm migration by `rg 'parseRoadmap|parsePlan' ` returning zero matches. DB queries are visible in SQLite `slices`/`tasks` tables. -- **Failure visibility:** All three files fall back to disk parsing when DB is not open — no hard failures from DB unavailability. Disk-parse fallback is silent (same behavior as before migration). - -## Expected Output - -- `src/resources/extensions/gsd/auto-dispatch.ts` — 3 rules migrated to DB queries -- `src/resources/extensions/gsd/auto-verification.ts` — task verify lookup migrated to DB query -- `src/resources/extensions/gsd/parallel-eligibility.ts` — file collection migrated to DB queries diff --git a/.gsd/milestones/M001/slices/S04/tasks/T03-SUMMARY.md b/.gsd/milestones/M001/slices/S04/tasks/T03-SUMMARY.md deleted file mode 100644 index 28ecc40f2..000000000 --- a/.gsd/milestones/M001/slices/S04/tasks/T03-SUMMARY.md +++ /dev/null @@ -1,98 +0,0 @@ ---- -id: T03 -parent: S04 -milestone: M001 -key_files: - - src/resources/extensions/gsd/auto-dispatch.ts - - src/resources/extensions/gsd/auto-verification.ts - - src/resources/extensions/gsd/parallel-eligibility.ts - - .gsd/milestones/M001/slices/S04/tasks/T03-PLAN.md -key_decisions: - - Used lazy createRequire fallback for all three files (same pattern as T02) — avoids module-level parser imports while keeping fallback path functional when DB is unavailable - - Kept loadFile in auto-dispatch.ts module imports since it's still used by 15 other rules for non-planning file content (UAT files, context files, etc.) — only parseRoadmap was removed - - TaskRow.files is already a parsed string[] from the getter (rowToTask), so no JSON.parse needed in parallel-eligibility.ts DB path -observability_surfaces: - - "isDbAvailable() gate in auto-dispatch.ts, auto-verification.ts, parallel-eligibility.ts — stderr diagnostic on fallback" - - "auto-dispatch.ts lazyParseRoadmap — createRequire fallback loader with .ts/.js resolution" - - "auto-verification.ts lazy loader — createRequire fallback for loadFile + parsePlan" - - "parallel-eligibility.ts lazy loader — createRequire fallback for parseRoadmap + parsePlan + loadFile" -duration: "" -verification_result: passed -completed_at: 2026-03-23T17:09:17.905Z -blocker_discovered: false ---- - -# T03: Migrate auto-dispatch.ts (3 rules), auto-verification.ts, and parallel-eligibility.ts from parser calls to DB queries with lazy disk-parse fallback - -**Migrate auto-dispatch.ts (3 rules), auto-verification.ts, and parallel-eligibility.ts from parser calls to DB queries with lazy disk-parse fallback** - -## What Happened - -Migrated the three remaining hot-path parser callers to DB queries, following the same pattern established in T02 (dispatch-guard.ts). - -**auto-dispatch.ts changes:** -- Removed `parseRoadmap` from module-level `files.js` import; added `isDbAvailable, getMilestoneSlices` from `gsd-db.js` and `createRequire` from `node:module`. -- Added `lazyParseRoadmap()` fallback using `createRequire` with .ts/.js extension resolution (same pattern as T02's `lazyParseRoadmapSlices`). -- **uat-verdict-gate rule:** Replaced `parseRoadmap(roadmapContent).slices.filter(s => s.done)` with `getMilestoneSlices(mid).filter(s => s.status === 'complete')` when DB is available. Falls back to lazy disk parse. Kept `loadFile` for UAT-RESULT file content reading (that's file content, not planning state). -- **validating-milestone rule:** Replaced `parseRoadmap(roadmapContent).slices` → `getMilestoneSlices(mid)` for SUMMARY existence checks. Falls back to lazy disk parse when DB unavailable. -- **completing-milestone rule:** Same pattern as validating-milestone — `getMilestoneSlices(mid)` for SUMMARY checks with lazy disk fallback. -- All other rules (15 of 18) untouched — they use `loadFile` for non-planning content or don't use parsers at all. - -**auto-verification.ts changes:** -- Removed `loadFile` and `parsePlan` from module-level `files.js` import; added `isDbAvailable, getTask` from `gsd-db.js` and `createRequire`. -- Replaced `loadFile(planFile)` → `parsePlan(planContent)` → `taskEntry?.verify` chain with `getTask(mid, sid, tid)?.verify` when DB is available. -- Disk fallback uses lazy `createRequire` to load `loadFile` and `parsePlan` from `files.ts/.js`. - -**parallel-eligibility.ts changes:** -- Removed `parseRoadmap`, `parsePlan`, `loadFile` from module-level `files.js` import; added `isDbAvailable, getMilestoneSlices, getSliceTasks` from `gsd-db.js` and `createRequire`. -- `collectTouchedFiles()`: When DB is available, uses `getMilestoneSlices(milestoneId)` for slice list, then `getSliceTasks(milestoneId, slice.id)` and reads `task.files` (already parsed `string[]` by the getter). When DB unavailable, falls back to lazy-loaded parsers via `createRequire`. - -All three files follow the T02-established pattern: `isDbAvailable()` gate → DB query path → lazy `createRequire` fallback with .ts/.js extension resolution. - -## Verification - -1. `rg 'parseRoadmap' auto-dispatch.ts` — only matches in lazy fallback block (lazyParseRoadmap), zero module-level imports. -2. `rg 'parsePlan|parseRoadmap' auto-verification.ts` — only matches in lazy fallback block type annotations, zero module-level imports. -3. `rg 'parsePlan|parseRoadmap' parallel-eligibility.ts` — only matches in lazy fallback block, zero module-level imports. -4. TypeScript compilation: all 3 files import and execute cleanly under `--experimental-strip-types`. -5. `schema-v9-sequence.test.ts` — 7/7 pass (T01 regression). -6. `dispatch-guard.test.ts` — 8/8 pass (T02 regression). -7. `integration-mixed-milestones.test.ts` — 54/54 pass (exercises disk-parse fallback path). -8. Diagnostic: `getMilestoneSlices('NONEXISTENT')` returns `[]` (no crash on missing milestone). - -## Verification Evidence - -| # | Command | Exit Code | Verdict | Duration | -|---|---------|-----------|---------|----------| -| 1 | `rg '^import.*parseRoadmap' src/resources/extensions/gsd/auto-dispatch.ts` | 1 | ✅ pass — no module-level parseRoadmap import | 5ms | -| 2 | `rg '^import.*loadFile|parsePlan' src/resources/extensions/gsd/auto-verification.ts` | 1 | ✅ pass — no module-level loadFile/parsePlan imports | 5ms | -| 3 | `rg '^import.*parseRoadmap|parsePlan|loadFile' src/resources/extensions/gsd/parallel-eligibility.ts` | 1 | ✅ pass — no module-level parser imports | 5ms | -| 4 | `node --import resolve-ts.mjs --experimental-strip-types -e "import './auto-dispatch.ts'"` | 0 | ✅ pass | 3200ms | -| 5 | `node --import resolve-ts.mjs --experimental-strip-types -e "import './auto-verification.ts'"` | 0 | ✅ pass | 3200ms | -| 6 | `node --import resolve-ts.mjs --experimental-strip-types -e "import './parallel-eligibility.ts'"` | 0 | ✅ pass | 3200ms | -| 7 | `node --import resolve-ts.mjs --experimental-strip-types --test schema-v9-sequence.test.ts` | 0 | ✅ pass — 7/7 | 164ms | -| 8 | `node --import resolve-ts.mjs --experimental-strip-types --test dispatch-guard.test.ts` | 0 | ✅ pass — 8/8 | 640ms | -| 9 | `node --import resolve-ts.mjs --experimental-strip-types --test integration-mixed-milestones.test.ts` | 0 | ✅ pass — 54/54 | 770ms | -| 10 | `node -e "getMilestoneSlices('NONEXISTENT')" diagnostic` | 0 | ✅ pass — returns [] | 200ms | - - -## Deviations - -The task plan said `rg 'parseRoadmap' auto-dispatch.ts` should return zero matches. It returns matches in the lazy fallback block (lazyParseRoadmap function body), not module-level imports. This is the same pattern T02 established for dispatch-guard.ts where `rg 'parseRoadmapSlices'` matches in the lazy loader. The intent — no module-level parser imports — is satisfied. - -## Known Issues - -None. - -## Diagnostics - -- Verify no module-level parser imports: `grep -n '^import.*parseRoadmap\|^import.*parsePlan' src/resources/extensions/gsd/auto-dispatch.ts src/resources/extensions/gsd/auto-verification.ts src/resources/extensions/gsd/parallel-eligibility.ts` — should return no matches -- Confirm lazy-only references: `grep -n 'parseRoadmap\|parsePlan' src/resources/extensions/gsd/auto-dispatch.ts` — all matches should be inside lazy fallback blocks (lines 19-27) -- Run regression: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts` - -## Files Created/Modified - -- `src/resources/extensions/gsd/auto-dispatch.ts` -- `src/resources/extensions/gsd/auto-verification.ts` -- `src/resources/extensions/gsd/parallel-eligibility.ts` -- `.gsd/milestones/M001/slices/S04/tasks/T03-PLAN.md` diff --git a/.gsd/milestones/M001/slices/S04/tasks/T03-VERIFY.json b/.gsd/milestones/M001/slices/S04/tasks/T03-VERIFY.json deleted file mode 100644 index 04d512109..000000000 --- a/.gsd/milestones/M001/slices/S04/tasks/T03-VERIFY.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "schemaVersion": 1, - "taskId": "T03", - "unitId": "M001/S04/T03", - "timestamp": 1774285779949, - "passed": false, - "discoverySource": "package-json", - "checks": [ - { - "command": "npm run test", - "exitCode": 1, - "durationMs": 39295, - "verdict": "fail" - } - ], - "retryAttempt": 1, - "maxRetries": 2 -} diff --git a/.gsd/milestones/M001/slices/S04/tasks/T04-PLAN.md b/.gsd/milestones/M001/slices/S04/tasks/T04-PLAN.md deleted file mode 100644 index a0e44f2a4..000000000 --- a/.gsd/milestones/M001/slices/S04/tasks/T04-PLAN.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -estimated_steps: 4 -estimated_files: 1 -skills_used: [] ---- - -# T04: Write cross-validation tests proving DB↔rendered↔parsed parity - -**Slice:** S04 — Hot-path caller migration + cross-validation tests -**Milestone:** M001 - -## Description - -Create `planning-crossval.test.ts` following the `derive-state-crossval.test.ts` pattern. These tests prove R014: DB state matches rendered-then-parsed state during the transition window. Each test seeds planning data into DB via insert functions, renders markdown via renderers, parses back via existing parsers, and asserts field-by-field parity. This is the slice's highest-value proof artifact. - -## Steps - -1. Create `src/resources/extensions/gsd/tests/planning-crossval.test.ts`. Import from `node:test`, `node:assert/strict`, `node:fs`, `node:path`, `node:os`. Import DB functions: `openDatabase`, `closeDatabase`, `insertMilestone`, `insertSlice`, `insertTask`, `getMilestoneSlices`, `getSliceTasks`, `getTask` from `../gsd-db.ts`. Import renderers: `renderRoadmapFromDb`, `renderPlanFromDb`, `renderTaskPlanFromDb` from `../markdown-renderer.ts`. Import parsers: `parseRoadmapSlices` from `../roadmap-slices.ts`, `parsePlan` from `../files.ts`. Each test creates a temp dir, opens a DB, seeds data, renders, parses, asserts, then cleans up. - -2. **Test 1: ROADMAP round-trip parity.** Insert a milestone with 4 slices having varied status (2 complete, 2 pending), depends arrays, risk levels, and demo strings. Call `renderRoadmapFromDb()` to generate ROADMAP.md. Read the rendered file, call `parseRoadmapSlices()`. Assert for each slice: `parsedSlice.id === dbSlice.id`, `parsedSlice.done === (dbSlice.status === 'complete')`, `parsedSlice.depends` deep-equals `dbSlice.depends`, `parsedSlice.risk === dbSlice.risk`, `parsedSlice.title === dbSlice.title`. Assert slice count matches. - -3. **Test 2: PLAN round-trip parity.** Insert a milestone, one slice, and 3 tasks with planning fields populated (description, files as JSON arrays, verify commands, estimate). Call `renderPlanFromDb()` to generate S##-PLAN.md. Read the rendered file, call `parsePlan()`. Assert: `parsedPlan.tasks.length === 3`, each task's `id`, `title`, `verify` field matches the DB row. Assert `parsedPlan.filesLikelyTouched` contains all files from all task rows (aggregate). Assert task order matches sequence ordering from DB. - -4. **Test 3: Sequence ordering parity.** Insert a milestone with 4 slices having sequence values `[3, 1, 4, 2]` (non-sequential insertion order). Call `renderRoadmapFromDb()`. Parse back via `parseRoadmapSlices()`. Assert the parsed slice order matches sequence order `[1, 2, 3, 4]`, not insertion order. This proves R016 — sequence ordering propagates through render and is preserved by the parser. - -## Must-Haves - -- [ ] Test 1 passes: ROADMAP DB→render→parse round-trip proves field parity (id, done/status, depends, risk, title) -- [ ] Test 2 passes: PLAN DB→render→parse round-trip proves task field parity (id, title, verify, files) -- [ ] Test 3 passes: Sequence ordering preserved through DB→render→parse round-trip -- [ ] All tests use temp directories and clean up after themselves -- [ ] Tests run under the resolver harness - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/planning-crossval.test.ts` - -## Inputs - -- `src/resources/extensions/gsd/gsd-db.ts` — `openDatabase`, `closeDatabase`, insert functions, query functions (with sequence ordering from T01) -- `src/resources/extensions/gsd/markdown-renderer.ts` — `renderRoadmapFromDb`, `renderPlanFromDb`, `renderTaskPlanFromDb` -- `src/resources/extensions/gsd/roadmap-slices.ts` — `parseRoadmapSlices` -- `src/resources/extensions/gsd/files.ts` — `parsePlan` -- `src/resources/extensions/gsd/tests/derive-state-crossval.test.ts` — pattern reference for test structure - -## Expected Output - -- `src/resources/extensions/gsd/tests/planning-crossval.test.ts` — new cross-validation test file with 3 scenarios - -## Observability Impact - -- **Signals changed:** No runtime signals changed — this is a test-only task. -- **Inspection:** Test output reports pass/fail per field-parity assertion across 3 scenarios (ROADMAP round-trip, PLAN round-trip, sequence ordering). Future agents can run the test to verify DB↔rendered↔parsed parity holds after any renderer or parser change. -- **Failure visibility:** Test failures print `FAIL: : ` with expected vs actual values, enabling precise field-level diagnosis of parity regressions. diff --git a/.gsd/milestones/M001/slices/S04/tasks/T04-SUMMARY.md b/.gsd/milestones/M001/slices/S04/tasks/T04-SUMMARY.md deleted file mode 100644 index 6b3fe2c12..000000000 --- a/.gsd/milestones/M001/slices/S04/tasks/T04-SUMMARY.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -id: T04 -parent: S04 -milestone: M001 -key_files: - - src/resources/extensions/gsd/tests/planning-crossval.test.ts - - src/resources/extensions/gsd/markdown-renderer.ts - - .gsd/milestones/M001/slices/S04/tasks/T04-PLAN.md -key_decisions: - - Fixed renderRoadmapMarkdown depends serialization from JSON.stringify (quoted) to join-based (unquoted) — required for parser round-trip parity since parseRoadmapSlices doesn't strip quotes from dependency IDs -observability_surfaces: - - "planning-crossval.test.ts — 65 assertions across 3 scenarios (ROADMAP parity, PLAN parity, sequence ordering)" - - "Cross-validation pattern follows derive-state-crossval.test.ts established in prior work" -duration: "" -verification_result: passed -completed_at: 2026-03-23T17:15:58.443Z -blocker_discovered: false ---- - -# T04: Add planning-crossval tests proving DB↔rendered↔parsed parity and fix renderer depends quoting - -**Add planning-crossval tests proving DB↔rendered↔parsed parity and fix renderer depends quoting** - -## What Happened - -Created `planning-crossval.test.ts` with 3 test scenarios (65 assertions) proving DB→render→parse round-trip parity for planning data: - -**Test 1: ROADMAP round-trip parity** — Seeds 4 slices with varied status (2 complete, 2 pending), depends arrays, risk levels, and demo strings. Renders via `renderRoadmapFromDb()`, parses back via `parseRoadmapSlices()`, asserts field-by-field parity for id, title, done↔status, risk, and depends. - -**Test 2: PLAN round-trip parity** — Seeds 1 slice with 3 tasks having planning fields (description, files arrays, verify commands, estimates). Renders via `renderPlanFromDb()`, parses back via `parsePlan()`, asserts task count, per-task field parity (id, title, verify, done↔status, files), filesLikelyTouched aggregation, and sequence ordering. - -**Test 3: Sequence ordering parity** — Seeds 4 slices inserted in scrambled order (seq 3,1,4,2). Verifies DB query returns sequence order, render produces slices in sequence order, and parsed-back slices preserve that order through the full round-trip. - -**Renderer fix:** Discovered and fixed a parity bug in `renderRoadmapMarkdown()` — it used `JSON.stringify()` for the depends array, producing `depends:["S01","S02"]` with quoted strings. The parser doesn't strip quotes, so round-trip produces `['"S01"', '"S02"']` instead of `['S01', 'S02']`. Changed to `[${deps.join(",")}]` to produce `depends:[S01,S02]` matching the parser's expected format. All 106 existing renderer tests and 189 derive-state-crossval assertions pass with this fix. - -## Verification - -1. `planning-crossval.test.ts` — 65/65 assertions pass across 3 scenarios (149ms). -2. `schema-v9-sequence.test.ts` — 7/7 pass (T01 regression). -3. `dispatch-guard.test.ts` — 8/8 pass (T02 regression). -4. `markdown-renderer.test.ts` — 106/106 pass (renderer fix regression). -5. `derive-state-crossval.test.ts` — 189/189 pass (renderer fix regression). -6. `auto-recovery.test.ts` — 33/33 pass (renderPlanFromDb regression). -7. Diagnostic: `getMilestoneSlices('NONEXISTENT')` returns `[]` (no crash). - -## Verification Evidence - -| # | Command | Exit Code | Verdict | Duration | -|---|---------|-----------|---------|----------| -| 1 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/planning-crossval.test.ts` | 0 | ✅ pass — 65/65 assertions across 3 scenarios | 153ms | -| 2 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts` | 0 | ✅ pass — 7/7 | 135ms | -| 3 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/dispatch-guard.test.ts` | 0 | ✅ pass — 8/8 | 543ms | -| 4 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts` | 0 | ✅ pass — 106/106 | 192ms | -| 5 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/derive-state-crossval.test.ts` | 0 | ✅ pass — 189/189 | 527ms | -| 6 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/auto-recovery.test.ts` | 0 | ✅ pass — 33/33 | 627ms | -| 7 | `grep parseRoadmapSlices|parseRoadmap|parsePlan dispatch-guard.ts auto-verification.ts parallel-eligibility.ts` | 0 | ✅ pass — only lazy-loader references, no module-level imports | 5ms | -| 8 | `node --import resolve-ts.mjs --experimental-strip-types -e getMilestoneSlices(NONEXISTENT) diagnostic` | 0 | ✅ pass — returns [] | 200ms | - - -## Deviations - -Fixed a depends-quoting bug in `renderRoadmapMarkdown()` in `markdown-renderer.ts` — the renderer used `JSON.stringify()` for the depends array, which produced quoted strings `["S01"]` that didn't round-trip through the parser. Changed to `[S01]` format. This was required to make Test 1 pass and is a genuine parity fix, not scope creep. - -## Known Issues - -None. - -## Diagnostics - -- Run cross-validation tests: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/planning-crossval.test.ts` -- Verify renderer fix: `grep 'join.*","' src/resources/extensions/gsd/markdown-renderer.ts` — depends serialization should use `.join(",")` not `JSON.stringify` -- Run renderer regression: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts` - -## Files Created/Modified - -- `src/resources/extensions/gsd/tests/planning-crossval.test.ts` -- `src/resources/extensions/gsd/markdown-renderer.ts` -- `.gsd/milestones/M001/slices/S04/tasks/T04-PLAN.md` diff --git a/.gsd/milestones/M001/slices/S04/tasks/T04-VERIFY.json b/.gsd/milestones/M001/slices/S04/tasks/T04-VERIFY.json deleted file mode 100644 index 1d2620e44..000000000 --- a/.gsd/milestones/M001/slices/S04/tasks/T04-VERIFY.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "schemaVersion": 1, - "taskId": "T04", - "unitId": "M001/S04/T04", - "timestamp": 1774286186158, - "passed": false, - "discoverySource": "package-json", - "checks": [ - { - "command": "npm run test", - "exitCode": 1, - "durationMs": 40279, - "verdict": "fail" - } - ], - "retryAttempt": 1, - "maxRetries": 2 -} diff --git a/.gsd/milestones/M001/slices/S05/S05-PLAN.md b/.gsd/milestones/M001/slices/S05/S05-PLAN.md deleted file mode 100644 index 0f274f4a8..000000000 --- a/.gsd/milestones/M001/slices/S05/S05-PLAN.md +++ /dev/null @@ -1,94 +0,0 @@ -# S05: Warm/cold callers + flag files + pre-M002 migration - -**Goal:** All non-hot-path parseRoadmap/parsePlan callers migrated to DB queries with lazy parser fallback. REPLAN.md and REPLAN-TRIGGER.md flag-file detection in deriveStateFromDb() replaced with DB table/column queries. migrateHierarchyToDb() populates v8 planning columns from parsed markdown. -**Demo:** `grep -rn 'import.*parseRoadmap\|import.*parsePlan' src/resources/extensions/gsd/*.ts | grep -v '/tests/' | grep -v 'md-importer' | grep -v 'files.ts'` returns only lazy `createRequire` references and markdown-renderer.ts lazy imports. Flag-file phase detection works without disk files when DB is seeded. - -## Must-Haves - -- Schema v10 adds `replan_triggered_at TEXT` column to slices table (both CREATE TABLE DDL and migration block) -- `deriveStateFromDb()` uses `getReplanHistory()` for REPLAN detection and `replan_triggered_at` column for REPLAN-TRIGGER detection instead of `resolveSliceFile()` disk checks -- `triage-resolution.ts` `executeReplan()` writes `replan_triggered_at` column in addition to disk file -- `migrateHierarchyToDb()` passes `planning: { vision, successCriteria, boundaryMapMarkdown }` to `insertMilestone()`, `planning: { goal }` to `insertSlice()`, and `files`/`verify` to `insertTask()` -- All 13 warm/cold caller files have module-level `parseRoadmap`/`parsePlan` imports replaced with `isDbAvailable()` gate + lazy `createRequire` fallback (or dynamic import for async callers) -- `markdown-renderer.ts` validation moves parser import from module-level to lazy `createRequire` (keeps parser calls — they're intentional disk-vs-DB comparison) -- CONTINUE.md and CONTEXT-DRAFT.md migration NOT touched per D003 (locked, non-revisable) -- All existing tests pass (no regressions) - -## Proof Level - -- This slice proves: integration (DB queries replace parser calls across 13+ files) -- Real runtime required: no (unit tests with seeded DBs prove behavior) -- Human/UAT required: no - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/flag-file-db.test.ts` — flag-file DB migration tests pass -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/gsd-recover.test.ts` — extended recovery tests pass (v8 column population) -- `grep -rn 'import.*parseRoadmap\|import.*parsePlan\|import.*parseRoadmapSlices' src/resources/extensions/gsd/*.ts | grep -v '/tests/' | grep -v 'md-importer' | grep -v 'files.ts'` — returns zero module-level imports (only lazy createRequire references) -- Regression suites: doctor.test.ts, auto-recovery.test.ts, auto-dashboard.test.ts, derive-state-db.test.ts, derive-state-crossval.test.ts, planning-crossval.test.ts, markdown-renderer.test.ts all pass -- Diagnostic: `gsd-recover.test.ts` v8 column assertions include SQL-level queryability checks for vision, goal, files, verify columns — verifying inspectable state after migration failure or empty data - -## Observability / Diagnostics - -- Runtime signals: `replan_triggered_at` column on slices table records when triage writes a replan trigger; `replan_history` table rows indicate completed replans — both queryable via SQL -- Inspection surfaces: `SELECT id, replan_triggered_at FROM slices WHERE milestone_id = :mid` shows trigger state; `SELECT * FROM replan_history WHERE milestone_id = :mid AND slice_id = :sid` shows replan completion -- Failure visibility: `isDbAvailable()` gate in all migrated callers writes to stderr when falling back to parser — detectable in logs -- Redaction constraints: none - -## Integration Closure - -- Upstream surfaces consumed: `getReplanHistory()` from S03, `getMilestoneSlices()`/`getSliceTasks()`/`getTask()` from S01/S02, `isDbAvailable()` + lazy `createRequire` pattern from S04 -- New wiring introduced: `replan_triggered_at` column writer in `triage-resolution.ts`, v8 column population in `migrateHierarchyToDb()` -- What remains before the milestone is truly usable end-to-end: S06 (parser deprecation + cleanup — removes dead parser code from hot paths) - -## Tasks - -- [x] **T01: Schema v10 + flag-file DB migration in deriveStateFromDb** `est:45m` - - Why: The architecturally novel piece — REPLAN.md and REPLAN-TRIGGER.md detection in `deriveStateFromDb()` must use DB queries instead of disk-file checks. Schema v10 adds the `replan_triggered_at` column. Triage-resolution must also write the column. - - Files: `src/resources/extensions/gsd/gsd-db.ts`, `src/resources/extensions/gsd/state.ts`, `src/resources/extensions/gsd/triage-resolution.ts`, `src/resources/extensions/gsd/tests/flag-file-db.test.ts` - - Do: (1) Bump SCHEMA_VERSION to 10, add `replan_triggered_at TEXT DEFAULT NULL` to slices CREATE TABLE DDL and v10 migration block. (2) Update `SliceRow` interface and `rowToSlice()`. (3) In `deriveStateFromDb()`, replace `resolveSliceFile(... "REPLAN")` with `getReplanHistory(mid, sid).length > 0` check, replace `resolveSliceFile(... "REPLAN-TRIGGER")` with checking `getSlice(mid, sid)?.replan_triggered_at`. (4) In `triage-resolution.ts` `executeReplan()`, after writing the disk file, also write the `replan_triggered_at` column via `UPDATE slices SET replan_triggered_at = :ts`. (5) Write `flag-file-db.test.ts` testing: blocker→replan detection via DB (no disk file), REPLAN-TRIGGER via DB column (no disk file), loop protection (replan_history exists = no replanning phase). - - Verify: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/flag-file-db.test.ts` - - Done when: deriveStateFromDb returns phase='replanning-slice' from DB-only data (no REPLAN.md or REPLAN-TRIGGER.md on disk) and returns phase='executing' when replan_history exists (loop protection). SCHEMA_VERSION=10. - -- [x] **T02: Extend migrateHierarchyToDb with v8 column population** `est:30m` - - Why: Existing projects migrating to the DB need their parsed ROADMAP/PLAN data written into the v8 planning columns so DB queries return meaningful data. The `gsd recover` test must verify this. - - Files: `src/resources/extensions/gsd/md-importer.ts`, `src/resources/extensions/gsd/tests/gsd-recover.test.ts` - - Do: (1) In `migrateHierarchyToDb()`, extend the `insertMilestone()` call to pass `planning: { vision: roadmap.vision, successCriteria: roadmap.successCriteria, boundaryMapMarkdown: boundaryMapSection }` where `boundaryMapMarkdown` is the raw "## Boundary Map" section extracted from the roadmap content. (2) Extend `insertSlice()` calls to pass `planning: { goal: plan.goal }` from the parsed plan (when plan exists). (3) Extend `insertTask()` calls to pass `planning: { files: task.files, verify: task.verify }` from TaskPlanEntry. (4) Extend `gsd-recover.test.ts` to assert: after recover, milestone has non-empty `vision`; slice has non-empty `goal`; task has populated `files` array and `verify` string. - - Verify: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/gsd-recover.test.ts` - - Done when: migrateHierarchyToDb populates vision, successCriteria, boundaryMapMarkdown on milestones; goal on slices; files and verify on tasks. Recovery test proves it. - -- [x] **T03: Migrate warm/cold callers batch 1 — doctor, visualizer, workspace, dashboard, guided-flow** `est:40m` - - Why: Seven files with straightforward parseRoadmap/parsePlan usage need the S04 isDbAvailable + lazy createRequire pattern applied. - - Files: `src/resources/extensions/gsd/doctor.ts`, `src/resources/extensions/gsd/doctor-checks.ts`, `src/resources/extensions/gsd/visualizer-data.ts`, `src/resources/extensions/gsd/workspace-index.ts`, `src/resources/extensions/gsd/dashboard-overlay.ts`, `src/resources/extensions/gsd/auto-dashboard.ts`, `src/resources/extensions/gsd/guided-flow.ts` - - Do: For each file: (1) Remove module-level `parseRoadmap`/`parsePlan` from the import statement. (2) At each call site, add `isDbAvailable()` gate calling `getMilestoneSlices()`/`getSliceTasks()` for the DB path. (3) Add lazy `createRequire`-based fallback loading the parser for non-DB path. (4) For `parsePlan().filesLikelyTouched` aggregation in callers: collect `.files` arrays from `getSliceTasks()` results. (5) Keep other non-parser imports (loadFile, parseSummary, etc.) as module-level. Note: these files are async or synchronous — check each. For async callers, dynamic `import()` is also acceptable. Follow the exact pattern from `dispatch-guard.ts` (S04). - - Verify: `grep -n 'import.*parseRoadmap\|import.*parsePlan' src/resources/extensions/gsd/doctor.ts src/resources/extensions/gsd/doctor-checks.ts src/resources/extensions/gsd/visualizer-data.ts src/resources/extensions/gsd/workspace-index.ts src/resources/extensions/gsd/dashboard-overlay.ts src/resources/extensions/gsd/auto-dashboard.ts src/resources/extensions/gsd/guided-flow.ts` returns zero results. Existing test suites pass. - - Done when: Zero module-level parseRoadmap/parsePlan imports in these 7 files. All existing tests for these files pass. - -- [x] **T04: Migrate warm/cold callers batch 2 — auto-prompts, auto-recovery, auto-direct-dispatch, auto-worktree, reactive-graph, markdown-renderer + final verification** `est:50m` - - Why: The remaining 6 files include auto-prompts.ts (6 parser calls, 1649 lines, highest complexity) and markdown-renderer.ts (intentional parser usage → lazy import only). Final grep verification confirms zero module-level parser imports remain. - - Files: `src/resources/extensions/gsd/auto-prompts.ts`, `src/resources/extensions/gsd/auto-recovery.ts`, `src/resources/extensions/gsd/auto-direct-dispatch.ts`, `src/resources/extensions/gsd/auto-worktree.ts`, `src/resources/extensions/gsd/reactive-graph.ts`, `src/resources/extensions/gsd/markdown-renderer.ts` - - Do: (1) **auto-prompts.ts** — all functions are async, so use dynamic `import("./gsd-db.js")` pattern (already used in this file for decisions/requirements). For `inlineDependencySummaries`: replace `parseRoadmap(roadmapContent).slices.find(s => s.id === sid)?.depends` with `getSlice(mid, sid)?.depends`. For `checkNeedsReassessment`/`checkNeedsRunUat`: replace `parseRoadmap().slices` with `getMilestoneSlices(mid)`, map `s.done` to `s.status === 'complete'`. For `buildCompleteMilestonePrompt`/`buildValidateMilestonePrompt`: replace slice iteration with `getMilestoneSlices()`. For `buildResumeContextListing` parsePlan: replace with `getSliceTasks()` to find incomplete tasks. Keep `parseSummary`, `parseContinue`, `loadFile`, `parseTaskPlanFile` imports — those aren't in scope. (2) **auto-recovery.ts** — the `parsePlan` at line 370 replaces with `getSliceTasks()` to check task plan files exist. The `parseRoadmap` at line 407 is already inside an `!isDbAvailable()` block — leave it, just move to lazy import. (3) **auto-direct-dispatch.ts** — replace 2 `parseRoadmap` calls with `getMilestoneSlices()` behind `isDbAvailable()` gate. (4) **auto-worktree.ts** — replace 1 `parseRoadmap` call with `getMilestoneSlices()`. (5) **reactive-graph.ts** — replace 1 `parsePlan` call with `getSliceTasks()`. Also uses `parseTaskPlanIO` — keep that as-is (not a planning parser). (6) **markdown-renderer.ts** — move `parseRoadmap`/`parsePlan` from module-level import to lazy `createRequire` (the parser calls are intentional disk-vs-DB comparison in `findStaleArtifacts()`). (7) Run final grep to confirm zero module-level parser imports remain across all non-test, non-md-importer, non-files.ts source files. - - Verify: `grep -rn 'import.*parseRoadmap\|import.*parsePlan\|import.*parseRoadmapSlices' src/resources/extensions/gsd/*.ts | grep -v '/tests/' | grep -v 'md-importer' | grep -v 'files.ts'` returns zero results. `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/auto-recovery.test.ts` passes. - - Done when: Zero module-level parseRoadmap/parsePlan/parseRoadmapSlices imports in any non-test, non-md-importer, non-files.ts source file. All existing test suites pass. - -## Files Likely Touched - -- `src/resources/extensions/gsd/gsd-db.ts` -- `src/resources/extensions/gsd/state.ts` -- `src/resources/extensions/gsd/triage-resolution.ts` -- `src/resources/extensions/gsd/md-importer.ts` -- `src/resources/extensions/gsd/doctor.ts` -- `src/resources/extensions/gsd/doctor-checks.ts` -- `src/resources/extensions/gsd/visualizer-data.ts` -- `src/resources/extensions/gsd/workspace-index.ts` -- `src/resources/extensions/gsd/dashboard-overlay.ts` -- `src/resources/extensions/gsd/auto-dashboard.ts` -- `src/resources/extensions/gsd/guided-flow.ts` -- `src/resources/extensions/gsd/reactive-graph.ts` -- `src/resources/extensions/gsd/auto-direct-dispatch.ts` -- `src/resources/extensions/gsd/auto-worktree.ts` -- `src/resources/extensions/gsd/auto-recovery.ts` -- `src/resources/extensions/gsd/auto-prompts.ts` -- `src/resources/extensions/gsd/markdown-renderer.ts` -- `src/resources/extensions/gsd/tests/flag-file-db.test.ts` -- `src/resources/extensions/gsd/tests/gsd-recover.test.ts` diff --git a/.gsd/milestones/M001/slices/S05/S05-RESEARCH.md b/.gsd/milestones/M001/slices/S05/S05-RESEARCH.md deleted file mode 100644 index 0e0323933..000000000 --- a/.gsd/milestones/M001/slices/S05/S05-RESEARCH.md +++ /dev/null @@ -1,114 +0,0 @@ -# S05: Warm/cold callers + flag files + pre-M002 migration — Research - -**Date:** 2026-03-23 -**Status:** Ready for planning - -## Summary - -S05 migrates the remaining ~13 non-hot-path files from module-level `parseRoadmap()`/`parsePlan()` imports to DB queries with lazy parser fallback, migrates REPLAN.md and REPLAN-TRIGGER.md flag-file detection in `deriveStateFromDb()` to DB table/column queries, and extends `migrateHierarchyToDb()` to populate v8 planning columns from parsed ROADMAP/PLAN data. - -The work is mechanical — S04 established the `isDbAvailable()` + lazy `createRequire` fallback pattern in 4 hot-path files. S05 applies the identical pattern to 13 warm/cold callers. The flag-file migration is small: only REPLAN.md and REPLAN-TRIGGER.md need DB migration in `deriveStateFromDb()` — CONTINUE.md and CONTEXT-DRAFT.md are deferred to M002 per locked decision D003. ASSESSMENT.md is not used as a phase-detection flag file at all. - -The riskiest sub-task is `auto-prompts.ts` (7 parser calls across 1649 lines, providing context injection for all planning prompts) and the `migrateHierarchyToDb()` extension (must populate v8 columns without breaking existing recovery tests). - -## Recommendation - -Apply the established S04 migration pattern uniformly. Group files by risk: - -1. **First: flag-file migration** — Add `replan_triggered_at` column to slices (schema v10), update `deriveStateFromDb()` to query `replan_history` table and `replan_triggered_at` column instead of disk. This is the architecturally novel work — prove it first. -2. **Second: `migrateHierarchyToDb()` + `gsd recover`** — Extend to populate v8 columns. The parsed `Roadmap` already has `vision`, `successCriteria`, `boundaryMap`. The parsed `SlicePlan` has `goal`. The parsed `TaskPlanEntry` has `files` and `verify`. Best-effort population per D004. -3. **Third: warm/cold caller migration** — Batch the 13 files using the S04 pattern. Some files (like `markdown-renderer.ts` validation) intentionally read disk to compare with DB — those keep parser calls but move to lazy imports. - -**Scope constraint (D003):** CONTINUE.md and CONTEXT-DRAFT.md migration is locked for M002. R011 lists them but D003 (non-revisable) explicitly defers both to M002 with specific schema changes (continue_state JSON column, draft_content column). S05 should NOT create those columns or migrate those flag files. The roadmap description is aspirational; D003 is authoritative. - -## Implementation Landscape - -### Key Files - -**Flag-file migration targets in `state.ts`:** -- `src/resources/extensions/gsd/state.ts` (1367 lines) — `deriveStateFromDb()` has 3 flag-file checks to migrate: - - Line ~642: `resolveSliceFile(... "REPLAN")` → query `replan_history` table for the slice (S03 created `getReplanHistory(db, mid, sid)`) - - Line ~659: `resolveSliceFile(... "REPLAN-TRIGGER")` → check `replan_triggered_at` column on slice row (new column, schema v10) - - Line ~679: `resolveSliceFile(... "CONTINUE")` — **DO NOT TOUCH** per D003 -- The `_deriveStateImpl()` function (filesystem-based fallback at line ~700+) also has matching flag checks at lines ~1266, ~1309, ~1344 — these stay as-is since they're the disk-based fallback path - -**Schema:** -- `src/resources/extensions/gsd/gsd-db.ts` — Add `replan_triggered_at TEXT` column to slices table (schema v10 migration). Add to `SliceRow` interface. Add to CREATE TABLE DDL. - -**Migration extension:** -- `src/resources/extensions/gsd/md-importer.ts` — `migrateHierarchyToDb()` at line 508: extend the `insertMilestone()` call to pass `planning: { vision, successCriteria, boundaryMapMarkdown }` from the already-parsed `roadmap`. Extend `insertSlice()` calls to pass `planning: { goal }` from parsed plan. Extend `insertTask()` calls to pass `files` and `verify` from `TaskPlanEntry`. -- `src/resources/extensions/gsd/commands-maintenance.ts` — `handleRecover()` at line ~463: no code changes needed if `migrateHierarchyToDb()` itself is extended. - -**Warm/cold callers to migrate (S04 pattern: `isDbAvailable()` gate + lazy `createRequire` fallback):** -- `src/resources/extensions/gsd/doctor.ts` — 3 `parseRoadmap` calls + 1 `parsePlan` call. Replace with `getMilestoneSlices()` / `getSliceTasks()`. -- `src/resources/extensions/gsd/doctor-checks.ts` — 2 `parseRoadmap` calls. Replace with `getMilestoneSlices()`. -- `src/resources/extensions/gsd/visualizer-data.ts` — 1 `parseRoadmap` + 1 `parsePlan`. Replace with DB queries. -- `src/resources/extensions/gsd/workspace-index.ts` — 2 `parseRoadmap` + 1 `parsePlan`. Replace with DB queries. -- `src/resources/extensions/gsd/dashboard-overlay.ts` — 1 `parseRoadmap` + 1 `parsePlan`. Replace with DB queries. -- `src/resources/extensions/gsd/auto-dashboard.ts` — 1 `parseRoadmap` + 1 `parsePlan`. Replace with DB queries. -- `src/resources/extensions/gsd/guided-flow.ts` — 2 `parseRoadmap`. Replace with `getMilestoneSlices()`. -- `src/resources/extensions/gsd/reactive-graph.ts` — 1 `parsePlan`. Replace with `getSliceTasks()`. -- `src/resources/extensions/gsd/auto-direct-dispatch.ts` — 2 `parseRoadmap`. Replace with `getMilestoneSlices()`. -- `src/resources/extensions/gsd/auto-worktree.ts` — 1 `parseRoadmap`. Replace with `getMilestoneSlices()`. -- `src/resources/extensions/gsd/auto-recovery.ts` — 1 `parsePlan` (line 370, plan-slice task-plan-file check) + 1 `parseRoadmap` (line 407, already in `!isDbAvailable()` fallback). The `parsePlan` call can use `getSliceTasks()`. -- `src/resources/extensions/gsd/auto-prompts.ts` — 5 `parseRoadmap` + 1 `parsePlan`. All use roadmap slices for prompt context injection. Replace with `getMilestoneSlices()` / `getSliceTasks()`. -- `src/resources/extensions/gsd/markdown-renderer.ts` — 2 `parseRoadmap` + 2 `parsePlan` in staleness validation. These **intentionally** compare disk content to DB state. They should keep the parser calls but move from module-level import to lazy `createRequire`. - -**Not in scope (by design):** -- `src/resources/extensions/gsd/md-importer.ts` — Keeps parser imports; it IS the parser-to-DB migration tool. -- `src/resources/extensions/gsd/files.ts` — Parser definitions themselves. Removed in S06. -- `github-sync.ts` — Listed in R010 but does not exist in the codebase. Stale reference. - -### Build Order - -1. **Schema v10 + flag-file DB migration** — Add `replan_triggered_at` column. Update `deriveStateFromDb()` to use DB queries for REPLAN and REPLAN-TRIGGER detection. Write triage-resolution to set the column. Test: write a derive-state test that seeds DB with replan_history/replan_triggered_at and confirms phase detection without disk files. - -2. **`migrateHierarchyToDb()` v8 column population + `gsd recover` upgrade** — Extend migration to pass planning data. Test: extend `gsd-recover.test.ts` to assert v8 columns are populated (vision, successCriteria, goal, files, verify). - -3. **Warm/cold caller batch migration** — Apply the isDbAvailable + createRequire pattern to all 13 files. This is mechanical. Test: run all existing test suites for these files to confirm no regressions. No new tests needed — existing tests cover the behavior; the migration just changes the data source. - -4. **Integration verification** — Run the full test suite. Grep for remaining module-level `parseRoadmap`/`parsePlan` imports in non-test, non-`md-importer`, non-`files.ts` files. Only lazy fallback references should remain. - -### Verification Approach - -```bash -# 1. New tests pass -node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/.ts -node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/gsd-recover.test.ts - -# 2. No module-level parseRoadmap/parsePlan imports remain in migrated files -# (excluding md-importer.ts, files.ts, tests/*, and lazy createRequire references) -grep -rn 'import.*parseRoadmap\|import.*parsePlan' src/resources/extensions/gsd/*.ts | grep -v '/tests/' | grep -v 'md-importer' | grep -v 'files.ts' -# Expected: only lazy createRequire references or markdown-renderer.ts lazy import - -# 3. Regression suites -node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/doctor.test.ts -node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/auto-recovery.test.ts -node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/workspace-index.test.ts -node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/visualizer-data.test.ts -node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/reactive-graph.test.ts -# ... and all other existing test files for migrated callers -``` - -## Constraints - -- **D003 (locked, non-revisable):** CONTINUE.md and CONTEXT-DRAFT.md migration deferred to M002. Do not create `continue_state` or `draft_content` columns. -- **D004 (locked):** Recovery accepts fidelity loss for tool-only fields (risks, requirementCoverage, proofLevel). `migrateHierarchyToDb()` populates what parsers can extract; tool-only fields stay empty. -- **D007 (from S04):** Use lazy `createRequire` with `.ts/.js` extension fallback, not `dynamic import()`. Keep callers synchronous. -- **Schema v10:** Must add `replan_triggered_at` column to both the migration block AND the initial CREATE TABLE DDL (lesson from S04/T01 — fresh databases skip migrations). -- **`SliceRow` interface:** Must be updated with `replan_triggered_at` field. -- **`markdown-renderer.ts` validation:** Parser calls are intentional (comparing disk vs DB). Migration = move import from module-level to lazy `createRequire`, not replace parser usage. - -## Common Pitfalls - -- **Forgetting initial DDL update** — Schema v10 migration adds `replan_triggered_at` to existing DBs, but fresh databases use CREATE TABLE. Both must include the column (learned in S04/T01). -- **REPLAN detection semantics** — `deriveStateFromDb()` checks REPLAN.md existence to determine if a replan *has already been done* (loop protection). The DB equivalent is checking if `replan_history` has entries for that (milestone, slice) pair. Don't confuse "needs replan" (blocker_discovered) with "replan completed" (replan_history exists). -- **REPLAN-TRIGGER writer lives in `triage-resolution.ts`** — When adding `replan_triggered_at` column, `triage-resolution.ts` must also be updated to write the column instead of (or in addition to) creating the disk file. The disk file write may need to remain during transition for the `_deriveStateImpl()` fallback path. -- **auto-prompts.ts async context** — All functions in `auto-prompts.ts` are already async, so DB queries (which are synchronous) work without issues. But `loadFile` calls that provide roadmap content for parsing are async — the replacement path using DB is simpler (synchronous `getMilestoneSlices()`). -- **`TaskRow.files` is already parsed** — Per KNOWLEDGE.md, `rowToTask()` handles JSON.parse. Don't double-parse when reading from DB. -- **`parsePlan().filesLikelyTouched` aggregation** — Some callers use this field. The DB equivalent requires iterating `getSliceTasks(mid, sid)` and collecting `.files` arrays. This is straightforward but not a single column lookup. - -## Open Risks - -- **Test coverage gaps for warm/cold callers** — Some callers (like `auto-dashboard.ts`, `dashboard-overlay.ts`, `guided-flow.ts`) may have tests that don't exercise the parser paths being changed. If tests pass without actually covering the migrated code, regressions could hide. Run existing tests and check coverage qualitatively. -- **R011 vs D003 scope tension** — R011 lists CONTINUE.md and CONTEXT-DRAFT.md migration. D003 defers them. The planner should mark R011 as partially advanced (REPLAN + REPLAN-TRIGGER migrated) and note the remaining flag files are deferred. R011's status should not be set to "validated" until M002 completes the rest. diff --git a/.gsd/milestones/M001/slices/S05/S05-SUMMARY.md b/.gsd/milestones/M001/slices/S05/S05-SUMMARY.md deleted file mode 100644 index 2bdc4b089..000000000 --- a/.gsd/milestones/M001/slices/S05/S05-SUMMARY.md +++ /dev/null @@ -1,162 +0,0 @@ ---- -id: S05 -parent: M001 -milestone: M001 -provides: - - Zero module-level parseRoadmap/parsePlan/parseRoadmapSlices imports in non-test, non-md-importer, non-files.ts source files - - Schema v10 with replan_triggered_at column on slices - - deriveStateFromDb() uses DB for REPLAN and REPLAN-TRIGGER flag-file detection - - migrateHierarchyToDb() populates v8 planning columns (vision, successCriteria, boundaryMapMarkdown, goal, files, verify) - - All callers use isDbAvailable() + lazy createRequire fallback — no caller depends on parser imports -requires: - - slice: S03 - provides: replan_history table populated with actual replan events, assessments table populated - - slice: S04 - provides: Hot-path callers migrated to DB, isDbAvailable() + lazy createRequire pattern established, sequence-aware query ordering, cross-validation infrastructure - - slice: S01 - provides: Schema v8 migration, insertMilestone/insertSlice/insertTask query functions, renderRoadmapFromDb - - slice: S02 - provides: getSliceTasks/getTask query functions, renderPlanFromDb/renderTaskPlanFromDb -affects: - - S06 -key_files: - - src/resources/extensions/gsd/gsd-db.ts - - src/resources/extensions/gsd/state.ts - - src/resources/extensions/gsd/triage-resolution.ts - - src/resources/extensions/gsd/md-importer.ts - - src/resources/extensions/gsd/doctor.ts - - src/resources/extensions/gsd/doctor-checks.ts - - src/resources/extensions/gsd/visualizer-data.ts - - src/resources/extensions/gsd/workspace-index.ts - - src/resources/extensions/gsd/dashboard-overlay.ts - - src/resources/extensions/gsd/auto-dashboard.ts - - src/resources/extensions/gsd/guided-flow.ts - - src/resources/extensions/gsd/auto-prompts.ts - - src/resources/extensions/gsd/auto-recovery.ts - - src/resources/extensions/gsd/auto-direct-dispatch.ts - - src/resources/extensions/gsd/auto-worktree.ts - - src/resources/extensions/gsd/reactive-graph.ts - - src/resources/extensions/gsd/markdown-renderer.ts - - src/resources/extensions/gsd/tests/flag-file-db.test.ts - - src/resources/extensions/gsd/tests/gsd-recover.test.ts -key_decisions: - - deriveStateFromDb uses getReplanHistory().length for loop protection instead of disk REPLAN.md check - - deriveStateFromDb uses getSlice().replan_triggered_at for trigger detection instead of disk REPLAN-TRIGGER.md check - - triage-resolution.ts DB write is best-effort with silent catch — disk file remains primary for _deriveStateImpl fallback - - v8 planning columns populated only with parser-extractable fields; tool-only fields (keyRisks, requirementCoverage, proofLevel) left empty per D004 - - Boundary map extracted via inline string operations rather than importing extractSection — avoids coupling to unexported function - - All migrated files use file-local lazy parser singletons via createRequire — consistent pattern, no shared utility module - - auto-prompts.ts uses file-local async lazyParseRoadmap/lazyParsePlan helpers to centralize fallback across 6 call sites - - markdown-renderer.ts detectStaleRenders() parser calls kept as-is (intentional disk-vs-DB comparison) — only import moved to lazy createRequire -patterns_established: - - isDbAvailable() + lazy createRequire fallback pattern now applied to ALL non-test, non-md-importer source files — the entire codebase is DB-primary - - File-local lazy parser singletons via createRequire(import.meta.url) with try .ts / catch .js extension resolution — established as the universal fallback pattern - - For async-heavy callers like auto-prompts.ts, file-local async lazyParseRoadmap/lazyParsePlan helpers centralize the createRequire fallback across multiple call sites - - SliceRow.status === 'complete' mapped to .done for backward compatibility in all migrated callers -observability_surfaces: - - SELECT id, replan_triggered_at FROM slices WHERE milestone_id = :mid — shows replan trigger state per slice - - SELECT * FROM replan_history WHERE milestone_id = :mid AND slice_id = :sid — shows completed replans (loop protection) - - SELECT vision, success_criteria, boundary_map_markdown FROM milestones WHERE id = :mid — shows migrated milestone planning columns - - SELECT goal FROM slices WHERE milestone_id = :mid AND id = :sid — shows migrated slice goal - - SELECT files, verify_command FROM tasks WHERE milestone_id = :mid AND slice_id = :sid — shows migrated task planning columns - - isDbAvailable() fallback writes to stderr when DB is unavailable — detectable in runtime logs - - PRAGMA user_version returns 10 confirming schema v10 -drill_down_paths: - - .gsd/milestones/M001/slices/S05/tasks/T01-SUMMARY.md - - .gsd/milestones/M001/slices/S05/tasks/T02-SUMMARY.md - - .gsd/milestones/M001/slices/S05/tasks/T03-SUMMARY.md - - .gsd/milestones/M001/slices/S05/tasks/T04-SUMMARY.md -duration: "" -verification_result: passed -completed_at: 2026-03-23T18:22:06.035Z -blocker_discovered: false ---- - -# S05: Warm/cold callers + flag files + pre-M002 migration - -**All 13 warm/cold parser callers migrated to DB-primary with lazy fallback; schema v10 adds replan_triggered_at column; deriveStateFromDb() uses DB for flag-file detection; migrateHierarchyToDb() populates v8 planning columns — zero module-level parseRoadmap/parsePlan imports remain.** - -## What Happened - -S05 completed the caller migration started in S04, moving all remaining non-hot-path parseRoadmap/parsePlan callers to DB-primary queries with lazy createRequire fallback. - -**T01 — Schema v10 + flag-file DB migration:** Bumped schema to v10 with `replan_triggered_at TEXT DEFAULT NULL` on slices. Rewired `deriveStateFromDb()` to use `getReplanHistory().length > 0` for loop protection (replacing REPLAN.md disk check) and `getSlice().replan_triggered_at` for trigger detection (replacing REPLAN-TRIGGER.md disk check). Updated `triage-resolution.ts executeReplan()` to write the DB column alongside the disk file. The `_deriveStateImpl()` fallback path was left untouched — it still uses disk files. New `flag-file-db.test.ts` with 6 test cases covering all combinations of blocker/trigger/history states plus observability diagnostic. - -**T02 — migrateHierarchyToDb v8 column population:** Extended the migration function to pass `planning: { vision, successCriteria, boundaryMapMarkdown }` to `insertMilestone()`, `planning: { goal }` to `insertSlice()`, and `planning: { files, verify }` to `insertTask()`. Boundary map extracted via inline string operations (indexOf + slice). Plan parsing was restructured to happen before insertSlice so goal is available at insertion time. Tool-only fields (keyRisks, requirementCoverage, proofLevel) intentionally left empty per D004. Extended `gsd-recover.test.ts` with 27 new assertions covering all v8 column populations including SQL-level queryability diagnostics. - -**T03 — Warm/cold callers batch 1 (7 files):** Applied the S04 isDbAvailable() + lazy createRequire pattern to doctor.ts (3 parseRoadmap + 1 parsePlan), doctor-checks.ts (2 parseRoadmap), visualizer-data.ts (1+1), workspace-index.ts (2+1), dashboard-overlay.ts (1+1), auto-dashboard.ts (1+1), guided-flow.ts (2 parseRoadmap). Each file uses file-local lazy parser singletons consistent with dispatch-guard.ts reference pattern. SliceRow.status === 'complete' mapped to .done for all DB paths. - -**T04 — Warm/cold callers batch 2 (6 files) + final verification:** Migrated auto-prompts.ts (6 call sites, most complex), auto-recovery.ts (2), auto-direct-dispatch.ts (2), auto-worktree.ts (1), reactive-graph.ts (1), markdown-renderer.ts (2+2 — parser calls intentionally kept in detectStaleRenders() for disk-vs-DB comparison, import moved to lazy). auto-prompts.ts uses file-local async lazyParseRoadmap/lazyParsePlan helpers to centralize fallback across its 6 call sites. Final grep confirms zero module-level parser imports in the entire codebase (non-test, non-md-importer, non-files.ts). - -## Verification - -All slice-level verification checks passed: - -1. **Zero module-level parser imports:** `grep -rn 'import.*parseRoadmap|import.*parsePlan|import.*parseRoadmapSlices' src/resources/extensions/gsd/*.ts | grep -v '/tests/' | grep -v 'md-importer' | grep -v 'files.ts'` → exit code 1 (no matches). - -2. **flag-file-db.test.ts:** 14 assertions across 6 test cases — blocker+no-history→replanning, blocker+history→loop-protection, trigger+no-history→replanning, trigger+history→loop-protection, baseline→executing, column-queryability diagnostic. All pass. - -3. **gsd-recover.test.ts:** 65 assertions including 27 new v8 column population assertions. All pass. - -4. **Regression suites (all pass):** - - doctor.test.ts: 55 pass - - auto-recovery.test.ts: 33 pass - - auto-dashboard.test.ts: 24 pass - - derive-state-db.test.ts: 105 pass - - derive-state-crossval.test.ts: 189 pass - - planning-crossval.test.ts: 65 pass - - markdown-renderer.test.ts: 106 pass - -5. **Observability surface:** `SELECT id, replan_triggered_at FROM slices WHERE milestone_id = :mid` confirms trigger state is queryable. `SELECT * FROM replan_history WHERE milestone_id = :mid AND slice_id = :sid` confirms replan completion is queryable. - -## Requirements Advanced - -- R011 — REPLAN.md → replan_history table check and REPLAN-TRIGGER.md → replan_triggered_at column check migrated in deriveStateFromDb(). CONTINUE.md and CONTEXT-DRAFT.md deferred per D003. - -## Requirements Validated - -- R010 — All 13 warm/cold caller files migrated. grep returns zero module-level parser imports. doctor.test.ts 55/55, auto-dashboard.test.ts 24/24, auto-recovery.test.ts 33/33, markdown-renderer.test.ts 106/106 all pass. -- R017 — migrateHierarchyToDb() populates vision, successCriteria, boundaryMapMarkdown on milestones; goal on slices; files and verify on tasks. gsd-recover.test.ts 65/65 with 27 new v8 column assertions including SQL-level queryability. - -## New Requirements Surfaced - -None. - -## Requirements Invalidated or Re-scoped - -None. - -## Deviations - -T01: Updated derive-state-db.test.ts Test 16 to seed replan_triggered_at DB column (test was relying on disk-based detection now replaced by DB). T02: parsePlan() preserves backtick formatting in verify fields — adjusted test expectations. Restructured roadmap parsing to avoid double parseRoadmap() call. T03: Replaced isMilestoneComplete(roadmap) with inline check in doctor.ts; adjusted guided-flow.ts guard to allow DB-backed operation without roadmap file. T04: Plan referenced buildResumeContextListing — actual function is buildRewriteDocsPrompt. Plan referenced findStaleArtifacts — actual function is detectStaleRenders. Both migrated correctly despite name mismatches. - -## Known Limitations - -CONTINUE.md and CONTEXT-DRAFT.md flag-file detection NOT migrated to DB per D003 (non-revisable, deferred to M002). R011 is therefore only partially validated. github-sync.ts was listed in R010 but not in the slice plan and not migrated (it's not a parser caller). workspace-index.ts titleFromRoadmapHeader kept as lazy-parser-only (no DB path) because it extracts title from raw markdown header with no direct DB equivalent. - -## Follow-ups - -S06 (parser deprecation + cleanup) is now unblocked — all callers are migrated, parsers can be removed from hot paths. - -## Files Created/Modified - -- `src/resources/extensions/gsd/gsd-db.ts` — Schema v10: added replan_triggered_at TEXT DEFAULT NULL to slices DDL and migration block; updated SliceRow interface and rowToSlice() -- `src/resources/extensions/gsd/state.ts` — deriveStateFromDb() uses getReplanHistory() and getSlice().replan_triggered_at for flag-file detection instead of disk resolveSliceFile() -- `src/resources/extensions/gsd/triage-resolution.ts` — executeReplan() writes replan_triggered_at column via UPDATE alongside disk file, using lazy createRequire + isDbAvailable() gate -- `src/resources/extensions/gsd/md-importer.ts` — migrateHierarchyToDb() passes planning columns to insertMilestone (vision, successCriteria, boundaryMapMarkdown), insertSlice (goal), and insertTask (files, verify) -- `src/resources/extensions/gsd/doctor.ts` — Removed 3 parseRoadmap + 1 parsePlan module-level imports; added isDbAvailable() + lazy createRequire fallback at all call sites -- `src/resources/extensions/gsd/doctor-checks.ts` — Removed 2 parseRoadmap module-level imports; added isDbAvailable() + lazy createRequire fallback for git health checks -- `src/resources/extensions/gsd/visualizer-data.ts` — Removed 1 parseRoadmap + 1 parsePlan module-level imports; added isDbAvailable() + lazy createRequire fallback -- `src/resources/extensions/gsd/workspace-index.ts` — Removed 2 parseRoadmap + 1 parsePlan module-level imports; titleFromRoadmapHeader uses lazy parser only -- `src/resources/extensions/gsd/dashboard-overlay.ts` — Removed 1 parseRoadmap + 1 parsePlan module-level imports; loadData() uses DB-primary path -- `src/resources/extensions/gsd/auto-dashboard.ts` — Removed 1 parseRoadmap + 1 parsePlan module-level imports; updateSliceProgressCache() uses createRequire fallback (synchronous) -- `src/resources/extensions/gsd/guided-flow.ts` — Removed 2 parseRoadmap module-level imports; adjusted guard to allow DB-backed operation without roadmap file -- `src/resources/extensions/gsd/auto-prompts.ts` — Removed parseRoadmap + parsePlan module-level imports; added async lazyParseRoadmap/lazyParsePlan helpers; 6 call sites migrated to DB-primary -- `src/resources/extensions/gsd/auto-recovery.ts` — Removed parseRoadmap + parsePlan module-level imports; 2 call sites migrated to DB-primary with createRequire fallback -- `src/resources/extensions/gsd/auto-direct-dispatch.ts` — Removed parseRoadmap module-level import; 2 call sites use getMilestoneSlices() with createRequire fallback -- `src/resources/extensions/gsd/auto-worktree.ts` — Removed parseRoadmap module-level import; mergeMilestoneToMain uses getMilestoneSlices() with id+title mapping -- `src/resources/extensions/gsd/reactive-graph.ts` — Removed parsePlan module-level import; loadSliceTaskIO uses getSliceTasks() with createRequire fallback -- `src/resources/extensions/gsd/markdown-renderer.ts` — Moved parseRoadmap + parsePlan from module-level import to lazy createRequire inside detectStaleRenders(); parser calls kept (intentional disk-vs-DB comparison) -- `src/resources/extensions/gsd/tests/flag-file-db.test.ts` — New: 6 test cases covering DB-based flag-file detection in deriveStateFromDb() -- `src/resources/extensions/gsd/tests/gsd-recover.test.ts` — Extended with 27 new assertions for v8 column population verification -- `src/resources/extensions/gsd/tests/derive-state-db.test.ts` — Updated Test 16 to seed replan_triggered_at DB column since DB path no longer reads disk flag files diff --git a/.gsd/milestones/M001/slices/S05/S05-UAT.md b/.gsd/milestones/M001/slices/S05/S05-UAT.md deleted file mode 100644 index 5e1f31a70..000000000 --- a/.gsd/milestones/M001/slices/S05/S05-UAT.md +++ /dev/null @@ -1,117 +0,0 @@ -# S05: Warm/cold callers + flag files + pre-M002 migration — UAT - -**Milestone:** M001 -**Written:** 2026-03-23T18:22:06.035Z - -## Preconditions - -- GSD-2 repository checked out on `next` branch -- Node.js 22+ with `--experimental-strip-types` support -- All test commands use the resolver harness: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test` - -## Test Cases - -### TC1: Zero module-level parser imports remain - -**Steps:** -1. Run: `grep -rn 'import.*parseRoadmap\|import.*parsePlan\|import.*parseRoadmapSlices' src/resources/extensions/gsd/*.ts | grep -v '/tests/' | grep -v 'md-importer' | grep -v 'files.ts'` - -**Expected:** Exit code 1 (no matches). Zero module-level parseRoadmap/parsePlan/parseRoadmapSlices imports in any non-test, non-md-importer, non-files.ts source file. - -### TC2: Flag-file DB migration — replan detection without disk files - -**Steps:** -1. Run: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/flag-file-db.test.ts` - -**Expected:** 14 assertions pass across 6 test cases: -- blocker_discovered + no replan_history → phase=replanning-slice -- blocker_discovered + replan_history exists → phase=executing (loop protection) -- replan_triggered_at set + no replan_history → phase=replanning-slice -- replan_triggered_at set + replan_history exists → phase=executing (loop protection) -- no blocker, no trigger → phase=executing (baseline) -- replan_triggered_at column is queryable via SQL - -### TC3: migrateHierarchyToDb v8 column population - -**Steps:** -1. Run: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/gsd-recover.test.ts` - -**Expected:** 65 assertions pass. Test a2 verifies: -- Milestone has non-empty vision, success_criteria, boundary_map_markdown -- Tool-only fields (key_risks, requirement_coverage, proof_level) are empty (per D004) -- Slice goals populated for both S01 and S02 -- Task files arrays populated correctly -- Task verify strings populated (with parser-preserved backtick formatting) -- SQL-level queryability diagnostics pass - -### TC4: deriveStateFromDb regression — DB path matches file path - -**Steps:** -1. Run: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/derive-state-db.test.ts` - -**Expected:** 105 assertions pass (0 regressions). Test 16 (replanning-slice via DB) uses seeded replan_triggered_at column. - -### TC5: Cross-validation parity maintained - -**Steps:** -1. Run: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/derive-state-crossval.test.ts` - -**Expected:** 189 assertions pass (0 regressions). DB state matches filesystem state. - -### TC6: Doctor regression — migrated caller works correctly - -**Steps:** -1. Run: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/doctor.test.ts` - -**Expected:** 55 assertions pass (0 regressions). - -### TC7: Auto-recovery regression — migrated caller works correctly - -**Steps:** -1. Run: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/auto-recovery.test.ts` - -**Expected:** 33 assertions pass (0 regressions). - -### TC8: Auto-dashboard regression — migrated caller works correctly - -**Steps:** -1. Run: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/auto-dashboard.test.ts` - -**Expected:** 24 assertions pass (0 regressions). - -### TC9: Planning cross-validation parity maintained - -**Steps:** -1. Run: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/planning-crossval.test.ts` - -**Expected:** 65 assertions pass — DB→render→parse round-trip parity preserved. - -### TC10: Markdown renderer regression — stale detection works with lazy parser - -**Steps:** -1. Run: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts` - -**Expected:** 106 assertions pass. detectStaleRenders() works correctly with lazy createRequire parser import. - -### TC11: Schema version is 10 - -**Steps:** -1. Open any test DB created by the test suite -2. Run: `PRAGMA user_version` - -**Expected:** Returns 10. - -### TC12: Observability — replan_triggered_at column is queryable - -**Steps:** -1. Seed a test DB with a slice and set `replan_triggered_at = '2026-01-01T00:00:00Z'` -2. Run: `SELECT id, replan_triggered_at FROM slices WHERE milestone_id = 'M001'` - -**Expected:** Returns the slice row with non-null replan_triggered_at. (Covered by flag-file-db.test.ts TC6.) - -## Edge Cases - -- **DB unavailable:** All migrated callers must fall back to lazy createRequire parser without crashing. The isDbAvailable() gate prevents DB calls when provider is null. -- **Empty planning columns after migration:** When no PLAN.md exists for a slice, goal defaults to empty string. When no ROADMAP.md exists, vision/successCriteria/boundaryMapMarkdown remain empty. This is acceptable (best-effort per D004). -- **workspace-index.ts titleFromRoadmapHeader:** Has no DB path — always uses lazy parser because raw markdown header has no direct DB equivalent. Acceptable deviation. -- **markdown-renderer.ts detectStaleRenders:** Parser calls intentionally kept (disk-vs-DB comparison) — only import mechanism changed to lazy. diff --git a/.gsd/milestones/M001/slices/S05/tasks/T01-PLAN.md b/.gsd/milestones/M001/slices/S05/tasks/T01-PLAN.md deleted file mode 100644 index f9b70e930..000000000 --- a/.gsd/milestones/M001/slices/S05/tasks/T01-PLAN.md +++ /dev/null @@ -1,98 +0,0 @@ ---- -estimated_steps: 5 -estimated_files: 4 -skills_used: [] ---- - -# T01: Schema v10 + flag-file DB migration in deriveStateFromDb - -**Slice:** S05 — Warm/cold callers + flag files + pre-M002 migration -**Milestone:** M001 - -## Description - -Add `replan_triggered_at TEXT DEFAULT NULL` column to the slices table (schema v10), then replace the disk-based REPLAN.md and REPLAN-TRIGGER.md detection in `deriveStateFromDb()` with DB queries. Update `triage-resolution.ts` to write the new column when creating a replan trigger. Write a test file proving flag-file phase detection works from DB-only data. - -**Critical semantic note:** In `deriveStateFromDb()`, REPLAN.md detection is **loop protection** — if a replan has already been done (REPLAN.md exists / replan_history has entries), the system should NOT re-enter replanning phase. REPLAN-TRIGGER.md detection triggers replanning when triage creates it. These are distinct checks with different semantics: -- `resolveSliceFile(... "REPLAN")` → checks if replan was already completed → DB equivalent: `getReplanHistory(mid, sid).length > 0` -- `resolveSliceFile(... "REPLAN-TRIGGER")` → checks if triage triggered a replan → DB equivalent: `getSlice(mid, sid)?.replan_triggered_at` is non-null - -**D003 constraint:** Do NOT touch CONTINUE.md detection. It stays as disk-based per locked decision D003. - -## Steps - -1. **Schema v10 migration + DDL update in `gsd-db.ts`:** - - Bump `SCHEMA_VERSION` from 9 to 10 - - Add `replan_triggered_at TEXT DEFAULT NULL` to the CREATE TABLE DDL for `slices` (after the `sequence` column) - - Add a `if (currentVersion < 10)` migration block using `ensureColumn()` to add the column to existing DBs - - Update `SliceRow` interface to include `replan_triggered_at: string | null` - - Update `rowToSlice()` to read the column: `replan_triggered_at: (row["replan_triggered_at"] as string) ?? null` - -2. **Update `deriveStateFromDb()` in `state.ts`:** - - The blocker detection block (around line 640) checks `resolveSliceFile(basePath, activeMilestone.id, activeSlice.id, "REPLAN")` for loop protection. Replace with: import and call `getReplanHistory` from `gsd-db.js`, check if `getReplanHistory(activeMilestone.id, activeSlice.id).length > 0`. If replan history exists, it means replan was already done — don't return `replanning-slice`. - - The REPLAN-TRIGGER detection block (around line 659) checks `resolveSliceFile(basePath, activeMilestone.id, activeSlice.id, "REPLAN-TRIGGER")`. Replace with: import `getSlice` from `gsd-db.js`, check if `getSlice(activeMilestone.id, activeSlice.id)?.replan_triggered_at` is non-null. If set, check loop protection (replan_history) before returning `replanning-slice`. - - Do NOT touch the `_deriveStateImpl()` fallback path (line ~1266+) — that's the disk-based fallback and stays as-is. - - Do NOT touch CONTINUE.md detection (line ~679) — per D003. - -3. **Update `triage-resolution.ts` `executeReplan()`:** - - After writing the disk file (keep the disk write for `_deriveStateImpl()` fallback), also write the DB column: - ```typescript - try { - const { isDbAvailable, _getAdapter } = await import("./gsd-db.js"); - // ... or use a synchronous approach since executeReplan is sync - } - ``` - - Since `executeReplan` is synchronous and `gsd-db.ts` exports are module-level, use a direct import if possible, or use `createRequire` for lazy loading. Check if `gsd-db.ts` is already imported in the file. If not, use the lazy pattern. Write: `UPDATE slices SET replan_triggered_at = :ts WHERE milestone_id = :mid AND id = :sid` - - Note: `_getAdapter()` returns the raw adapter. Or use `isDbAvailable()` check + direct SQL. Follow the pattern used by other callers. - -4. **Write `flag-file-db.test.ts`:** - Test cases: - - "blocker_discovered + no replan_history → phase is replanning-slice" — seed DB with a completed task that has `blocker_discovered=1`, no replan_history entries. Confirm `deriveStateFromDb()` returns `phase: 'replanning-slice'`. - - "blocker_discovered + replan_history exists → loop protection, phase is executing" — seed DB with blocker task AND a replan_history entry for that slice. Confirm `deriveStateFromDb()` returns `phase: 'executing'` (loop protection). - - "replan_triggered_at set + no replan_history → phase is replanning-slice" — seed DB with `replan_triggered_at` on the active slice, no replan_history. Confirm replanning phase. - - "replan_triggered_at set + replan_history exists → loop protection" — seed with both. Confirm executing phase. - - "no blocker, no trigger → phase is executing" — baseline test confirming normal execution. - - Use the test harness pattern from `derive-state-db.test.ts` — create temp dirs, seed DB, call `deriveStateFromDb()`. - -5. **Run verification:** - - Run `flag-file-db.test.ts` - - Run `derive-state-db.test.ts` and `derive-state-crossval.test.ts` for regressions - - Run `schema-v9-sequence.test.ts` (now schema v10 — confirm v9 migration still works) - -## Must-Haves - -- [ ] SCHEMA_VERSION bumped to 10 -- [ ] `replan_triggered_at` column in both CREATE TABLE DDL and v10 migration block -- [ ] `SliceRow` interface and `rowToSlice()` updated -- [ ] `deriveStateFromDb()` uses `getReplanHistory()` for REPLAN loop protection -- [ ] `deriveStateFromDb()` uses `getSlice().replan_triggered_at` for REPLAN-TRIGGER detection -- [ ] `triage-resolution.ts` `executeReplan()` writes `replan_triggered_at` column -- [ ] CONTINUE.md detection untouched per D003 -- [ ] `_deriveStateImpl()` fallback path untouched -- [ ] `flag-file-db.test.ts` with 5 test cases passing - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/flag-file-db.test.ts` — all 5 tests pass -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/derive-state-db.test.ts` — no regressions -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/derive-state-crossval.test.ts` — no regressions - -## Observability Impact - -- Signals added: `replan_triggered_at` column on slices — queryable indicator of triage-initiated replan triggers -- How a future agent inspects this: `SELECT id, replan_triggered_at FROM slices WHERE milestone_id = :mid` -- Failure state exposed: If `deriveStateFromDb()` returns wrong phase, inspect `replan_history` table and `replan_triggered_at` column to diagnose - -## Inputs - -- `src/resources/extensions/gsd/gsd-db.ts` — schema, SliceRow interface, getReplanHistory(), getSlice(), _getAdapter() -- `src/resources/extensions/gsd/state.ts` — deriveStateFromDb() with existing REPLAN/REPLAN-TRIGGER disk checks -- `src/resources/extensions/gsd/triage-resolution.ts` — executeReplan() that writes REPLAN-TRIGGER.md -- `src/resources/extensions/gsd/tests/derive-state-db.test.ts` — test pattern reference for DB-seeded state tests - -## Expected Output - -- `src/resources/extensions/gsd/gsd-db.ts` — schema v10, updated SliceRow, rowToSlice -- `src/resources/extensions/gsd/state.ts` — deriveStateFromDb() using DB queries for flag-file detection -- `src/resources/extensions/gsd/triage-resolution.ts` — executeReplan() also writing replan_triggered_at column -- `src/resources/extensions/gsd/tests/flag-file-db.test.ts` — new test file with 5 flag-file DB migration tests diff --git a/.gsd/milestones/M001/slices/S05/tasks/T01-SUMMARY.md b/.gsd/milestones/M001/slices/S05/tasks/T01-SUMMARY.md deleted file mode 100644 index acf7aab63..000000000 --- a/.gsd/milestones/M001/slices/S05/tasks/T01-SUMMARY.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -id: T01 -parent: S05 -milestone: M001 -key_files: - - src/resources/extensions/gsd/gsd-db.ts - - src/resources/extensions/gsd/state.ts - - src/resources/extensions/gsd/triage-resolution.ts - - src/resources/extensions/gsd/tests/flag-file-db.test.ts - - src/resources/extensions/gsd/tests/derive-state-db.test.ts -key_decisions: - - deriveStateFromDb uses getReplanHistory().length for loop protection instead of disk REPLAN.md check - - deriveStateFromDb uses getSlice().replan_triggered_at for trigger detection instead of disk REPLAN-TRIGGER.md check - - triage-resolution.ts DB write is best-effort with silent catch — disk file remains primary for _deriveStateImpl fallback - - Updated existing Test 16 in derive-state-db.test.ts to seed DB column since the DB path no longer reads disk flag files -duration: "" -verification_result: passed -completed_at: 2026-03-23T17:46:00.398Z -blocker_discovered: false ---- - -# T01: Schema v10 adds replan_triggered_at column; deriveStateFromDb uses DB queries for REPLAN/REPLAN-TRIGGER detection instead of disk files - -**Schema v10 adds replan_triggered_at column; deriveStateFromDb uses DB queries for REPLAN/REPLAN-TRIGGER detection instead of disk files** - -## What Happened - -Implemented schema v10 and migrated flag-file detection from disk-based to DB-based in deriveStateFromDb(). - -**Schema v10 in gsd-db.ts:** -- Bumped SCHEMA_VERSION from 9 to 10 -- Added `replan_triggered_at TEXT DEFAULT NULL` column to slices CREATE TABLE DDL (after `sequence`) -- Added `if (currentVersion < 10)` migration block using `ensureColumn()` for existing DBs -- Updated `SliceRow` interface with `replan_triggered_at: string | null` -- Updated `rowToSlice()` to read the column - -**deriveStateFromDb() in state.ts:** -- Replaced `resolveSliceFile(... "REPLAN")` loop protection with `getReplanHistory(mid, sid).length > 0` — checks if replan was already completed via DB instead of checking for REPLAN.md on disk -- Replaced `resolveSliceFile(... "REPLAN-TRIGGER")` detection with `getSlice(mid, sid)?.replan_triggered_at` non-null check — detects triage-initiated replan trigger from DB column instead of REPLAN-TRIGGER.md on disk -- Added `getReplanHistory` and `getSlice` to the gsd-db.js import -- Left `_deriveStateImpl()` fallback path completely untouched — it still uses disk-based detection -- Left CONTINUE.md detection untouched per D003 - -**triage-resolution.ts executeReplan():** -- After writing the disk REPLAN-TRIGGER.md file (kept for fallback path), also writes `replan_triggered_at` column via `UPDATE slices SET replan_triggered_at = :ts` -- Uses lazy `createRequire(import.meta.url)` pattern (consistent with codebase convention) with `isDbAvailable()` gate -- DB write is best-effort — catches errors silently since disk file is primary for fallback path - -**derive-state-db.test.ts fix:** -- Test 16 ("replanning-slice via DB") was seeding only a REPLAN-TRIGGER.md disk file without setting `replan_triggered_at` in DB. Updated to also seed the DB column so the DB-backed detection works correctly. - -**flag-file-db.test.ts (new, 6 test cases):** -1. blocker_discovered + no replan_history → phase is replanning-slice -2. blocker_discovered + replan_history exists → loop protection, phase is executing -3. replan_triggered_at set + no replan_history → phase is replanning-slice -4. replan_triggered_at set + replan_history exists → loop protection, phase is executing -5. no blocker, no trigger → phase is executing (baseline) -6. Diagnostic: replan_triggered_at column is queryable (observability surface verification) - -## Verification - -All three verification suites pass with zero failures: -- flag-file-db.test.ts: 14 assertions passed across 6 test cases (including diagnostic) -- derive-state-db.test.ts: 105 assertions passed (0 regressions after Test 16 fix) -- derive-state-crossval.test.ts: 189 assertions passed (0 regressions) -- schema-v9-sequence.test.ts: 7 tests passed (v9 migration still works under v10) - -## Verification Evidence - -| # | Command | Exit Code | Verdict | Duration | -|---|---------|-----------|---------|----------| -| 1 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/flag-file-db.test.ts` | 0 | ✅ pass | 2400ms | -| 2 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/derive-state-db.test.ts` | 0 | ✅ pass | 2400ms | -| 3 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/derive-state-crossval.test.ts` | 0 | ✅ pass | 2400ms | -| 4 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts` | 0 | ✅ pass | 2800ms | - - -## Deviations - -Updated derive-state-db.test.ts Test 16 to seed replan_triggered_at DB column — the test was relying on disk-based REPLAN-TRIGGER.md detection which is now replaced by DB queries in deriveStateFromDb(). Added a 6th diagnostic test case in flag-file-db.test.ts beyond the 5 specified in the plan to verify observability surface (column queryability). - -## Known Issues - -None. - -## Diagnostics - -- **Replan trigger state:** `SELECT id, replan_triggered_at FROM slices WHERE milestone_id = ? AND id = ?` — non-null means triage wrote a trigger for this slice. -- **Replan completion (loop protection):** `SELECT COUNT(*) FROM replan_history WHERE milestone_id = ? AND slice_id = ?` — count > 0 means replan already completed, deriveStateFromDb will NOT re-enter replanning phase. -- **Schema version:** `PRAGMA user_version` — should return 10 after this task. -- **Test suite:** `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/flag-file-db.test.ts` — 6 test cases covering all flag-file DB migration scenarios. - -## Files Created/Modified - -- `src/resources/extensions/gsd/gsd-db.ts` -- `src/resources/extensions/gsd/state.ts` -- `src/resources/extensions/gsd/triage-resolution.ts` -- `src/resources/extensions/gsd/tests/flag-file-db.test.ts` -- `src/resources/extensions/gsd/tests/derive-state-db.test.ts` diff --git a/.gsd/milestones/M001/slices/S05/tasks/T01-VERIFY.json b/.gsd/milestones/M001/slices/S05/tasks/T01-VERIFY.json deleted file mode 100644 index e880ec431..000000000 --- a/.gsd/milestones/M001/slices/S05/tasks/T01-VERIFY.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "schemaVersion": 1, - "taskId": "T01", - "unitId": "M001/S05/T01", - "timestamp": 1774287990073, - "passed": false, - "discoverySource": "package-json", - "checks": [ - { - "command": "npm run test", - "exitCode": 1, - "durationMs": 39607, - "verdict": "fail" - } - ], - "retryAttempt": 1, - "maxRetries": 2 -} diff --git a/.gsd/milestones/M001/slices/S05/tasks/T02-PLAN.md b/.gsd/milestones/M001/slices/S05/tasks/T02-PLAN.md deleted file mode 100644 index 4023fdd79..000000000 --- a/.gsd/milestones/M001/slices/S05/tasks/T02-PLAN.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -estimated_steps: 4 -estimated_files: 2 -skills_used: [] ---- - -# T02: Extend migrateHierarchyToDb with v8 column population - -**Slice:** S05 — Warm/cold callers + flag files + pre-M002 migration -**Milestone:** M001 - -## Description - -Extend `migrateHierarchyToDb()` in `md-importer.ts` to populate v8 planning columns from parsed ROADMAP and PLAN files. This ensures pre-M002 projects get meaningful data in the DB planning columns when migrating. Per D004, tool-only fields (risks, requirementCoverage, proofLevel) are not populated — only fields the parsers can extract. Extend `gsd-recover.test.ts` to verify the v8 columns are populated after recovery. - -## Steps - -1. **Extend milestone insertion in `migrateHierarchyToDb()`:** - - The `parseRoadmap(roadmapContent)` call already returns `{ title, vision, successCriteria, slices, boundaryMap }`. - - The `insertMilestone()` call (around line 558) currently passes only `id`, `title`, `status`, `depends_on`. - - Add `planning: { vision: roadmap.vision, successCriteria: roadmap.successCriteria, boundaryMapMarkdown: boundaryMapSection }`. - - For `boundaryMapMarkdown`: extract the raw `## Boundary Map` section from `roadmapContent` using string operations (find `## Boundary Map` heading, take content until next `##` or EOF). The `extractSection()` function from `files.ts` can do this but is not exported — use a simple inline extraction: `const bmIdx = roadmapContent.indexOf('## Boundary Map'); const bmSection = bmIdx >= 0 ? roadmapContent.slice(bmIdx) ... : ''`. - - Note: `successCriteria` from `parseRoadmap()` is already a `string[]` — `insertMilestone()` expects it as `string[]` in the planning object and `JSON.stringify`s it internally. Verify this matches the `MilestonePlanningRecord.successCriteria` type. - -2. **Extend slice insertion:** - - The `insertSlice()` call (around line 574) currently passes `id`, `milestoneId`, `title`, `status`, `risk`, `depends`, `demo`. - - Parse the plan content (which already happens at line ~592: `parsePlan(planContent)`) and add `planning: { goal: plan.goal }` to the `insertSlice()` call. - - The plan parsing happens AFTER slice insertion currently. Restructure: read and parse the plan file BEFORE `insertSlice()`, so the goal is available. Or call `upsertSlicePlanning()` after parsing. The simpler approach: move the plan parse earlier, pass goal into insertSlice. If no plan exists, goal stays empty (the default). - -3. **Extend task insertion:** - - The `insertTask()` call (around line 612) currently passes `id`, `sliceId`, `milestoneId`, `title`, `status`. - - Add `planning: { files: taskEntry.files ?? [], verify: taskEntry.verify ?? '' }`. - - `TaskPlanEntry` from `parsePlan()` has optional `files?: string[]` and `verify?: string` fields. These are populated when the plan markdown has `- Files:` and `- Verify:` lines in task entries. - -4. **Extend `gsd-recover.test.ts`:** - - The existing test writes a ROADMAP.md and PLAN.md, runs `migrateHierarchyToDb()`, then checks counts and status. - - Add assertions after recovery: - - `getMilestonePlanning(mid)` returns non-empty `vision` matching what was in the fixture ROADMAP - - Slice row has non-empty `goal` matching what was in the fixture PLAN - - Task row has populated `files` array and non-empty `verify` string matching fixture data - - The fixture ROADMAP.md must include a `**Vision:**` field and `## Success Criteria` section for this to work. Check the existing fixture — if it doesn't have these, add them. - - The fixture PLAN.md must include `- Files:` and `- Verify:` in task entries. Check and extend if needed. - -## Must-Haves - -- [ ] `insertMilestone()` call in migrateHierarchyToDb passes `planning: { vision, successCriteria, boundaryMapMarkdown }` -- [ ] `insertSlice()` call passes `planning: { goal }` from parsed plan -- [ ] `insertTask()` call passes `planning: { files, verify }` from TaskPlanEntry -- [ ] `gsd-recover.test.ts` asserts v8 columns are populated after recovery -- [ ] Tool-only fields (risks, requirementCoverage, proofLevel) left empty per D004 - -## Verification - -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/gsd-recover.test.ts` — all tests pass including new v8 column assertions -- No regressions in other tests that use migrateHierarchyToDb (check `integration-mixed-milestones.test.ts`) - -## Inputs - -- `src/resources/extensions/gsd/md-importer.ts` — migrateHierarchyToDb() with existing insertMilestone/insertSlice/insertTask calls -- `src/resources/extensions/gsd/gsd-db.ts` — insertMilestone(planning), insertSlice(planning), insertTask(planning) signatures, getMilestonePlanning(), SliceRow, TaskRow interfaces -- `src/resources/extensions/gsd/tests/gsd-recover.test.ts` — existing recovery test to extend -- `src/resources/extensions/gsd/files.ts` — parseRoadmap() return type (vision, successCriteria, boundaryMap), parsePlan() return type (goal, tasks with files/verify) - -## Expected Output - -- `src/resources/extensions/gsd/md-importer.ts` — migrateHierarchyToDb() populates v8 planning columns -- `src/resources/extensions/gsd/tests/gsd-recover.test.ts` — extended with v8 column population assertions - -## Observability Impact - -- **Signals changed:** After migration, `SELECT vision, success_criteria, boundary_map_markdown FROM milestones WHERE id = :mid` returns non-empty values for pre-M002 projects (previously all empty). `SELECT goal FROM slices` and `SELECT files, verify FROM tasks` similarly populated. -- **Inspection:** `getMilestone(id).vision`, `getSlice(mid, sid).goal`, `getTask(mid, sid, tid).files/verify` return meaningful data post-recovery. -- **Failure visibility:** If `parseRoadmap()` or `parsePlan()` returns empty fields (no Vision in markdown, no Goal in plan), planning columns remain empty — detectable by `SELECT COUNT(*) FROM milestones WHERE vision = ''`. diff --git a/.gsd/milestones/M001/slices/S05/tasks/T02-SUMMARY.md b/.gsd/milestones/M001/slices/S05/tasks/T02-SUMMARY.md deleted file mode 100644 index b36db8592..000000000 --- a/.gsd/milestones/M001/slices/S05/tasks/T02-SUMMARY.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -id: T02 -parent: S05 -milestone: M001 -key_files: - - src/resources/extensions/gsd/md-importer.ts - - src/resources/extensions/gsd/tests/gsd-recover.test.ts -key_decisions: - - v8 planning columns populated only with parser-extractable fields; tool-only fields (keyRisks, requirementCoverage, proofLevel) left empty per D004 - - Boundary map extracted via inline string operations (indexOf + slice) rather than importing extractSection from files.ts — avoids coupling to unexported function - - Plan parsing moved before insertSlice to make goal available at insertion time instead of using a post-insert upsert -duration: "" -verification_result: passed -completed_at: 2026-03-23T17:52:14.780Z -blocker_discovered: false ---- - -# T02: Extend migrateHierarchyToDb to populate v8 planning columns (vision, successCriteria, boundaryMapMarkdown on milestones; goal on slices; files/verify on tasks) - -**Extend migrateHierarchyToDb to populate v8 planning columns (vision, successCriteria, boundaryMapMarkdown on milestones; goal on slices; files/verify on tasks)** - -## What Happened - -Extended `migrateHierarchyToDb()` in `md-importer.ts` to populate v8 planning columns from parsed markdown during recovery/migration. - -**Milestone planning columns:** Refactored to parse the roadmap once (not twice) — saved the `parseRoadmap()` result early and reused it. Added inline extraction of the raw `## Boundary Map` section from roadmap markdown (finds heading, takes content until next `##` or EOF). The `insertMilestone()` call now passes `planning: { vision, successCriteria, boundaryMapMarkdown }`. Per D004, tool-only fields (keyRisks, requirementCoverage, proofStrategy, etc.) are left empty. - -**Slice planning columns:** Restructured the loop to parse the plan file *before* `insertSlice()` (previously parsed after). The `insertSlice()` call now passes `planning: { goal: plan.goal }`. When no plan file exists, goal defaults to empty string. - -**Task planning columns:** The `insertTask()` call now passes `planning: { files: taskEntry.files ?? [], verify: taskEntry.verify ?? '' }` from the `TaskPlanEntry` parsed by `parsePlan()`. - -**Test extensions:** Enhanced the `gsd-recover.test.ts` fixtures — added `## Success Criteria` and `## Boundary Map` sections to the ROADMAP fixture, and `- Files:` / `- Verify:` lines to all task entries in both PLAN fixtures. Added a comprehensive test block (Test a2) with 27 assertions verifying: milestone vision matches fixture, success_criteria populated with correct entries, boundary_map_markdown contains expected content, D004 tool-only fields remain empty (key_risks, requirement_coverage, proof_level), slice goals populated for both S01 and S02, task files arrays populated correctly, task verify strings populated (discovered parser preserves backtick formatting), and SQL-level queryability diagnostics for all v8 columns. - -## Verification - -Ran gsd-recover.test.ts — all 65 assertions pass including 27 new v8 column population assertions. Ran 7 regression suites (migrate-hierarchy.test.ts: 57 pass, derive-state-crossval.test.ts: 189 pass, integration-proof.test.ts: 3 pass, derive-state-db.test.ts: 105 pass, doctor.test.ts: 55 pass, auto-recovery.test.ts: 33 pass, auto-dashboard.test.ts: 24 pass, planning-crossval.test.ts: 65 pass, markdown-renderer.test.ts: 106 pass, flag-file-db.test.ts: 14 pass) — zero regressions. - -## Verification Evidence - -| # | Command | Exit Code | Verdict | Duration | -|---|---------|-----------|---------|----------| -| 1 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/gsd-recover.test.ts` | 0 | ✅ pass | 524ms | -| 2 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts` | 0 | ✅ pass | 686ms | -| 3 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/derive-state-crossval.test.ts` | 0 | ✅ pass | 692ms | -| 4 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/integration-proof.test.ts` | 0 | ✅ pass | 756ms | -| 5 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/flag-file-db.test.ts` | 0 | ✅ pass | 176ms | -| 6 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/doctor.test.ts` | 0 | ✅ pass | 1100ms | -| 7 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/auto-recovery.test.ts` | 0 | ✅ pass | 752ms | -| 8 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/derive-state-db.test.ts` | 0 | ✅ pass | 238ms | -| 9 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/auto-dashboard.test.ts` | 0 | ✅ pass | 554ms | -| 10 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/planning-crossval.test.ts` | 0 | ✅ pass | 208ms | -| 11 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts` | 0 | ✅ pass | 257ms | - - -## Deviations - -Discovered that parsePlan() preserves backtick formatting in verify fields (e.g. `` `npm test` `` not `npm test`). Adjusted test expectations to match. Refactored roadmap parsing to avoid double parseRoadmap() call — the function was called once for title and again for slices; now parsed once with result reused. Changed the loop guard from `if (!roadmapContent) continue` to `if (!roadmap) continue` to match the refactored variable. - -## Known Issues - -None. - -## Diagnostics - -- **Milestone planning columns after migration:** `SELECT vision, success_criteria, boundary_map_markdown, key_risks, requirement_coverage, proof_level FROM milestones WHERE id = ?` — vision/success_criteria/boundary_map_markdown populated from parsed ROADMAP; key_risks/requirement_coverage/proof_level empty (tool-only, per D004). -- **Slice goal after migration:** `SELECT id, goal FROM slices WHERE milestone_id = ?` — goal populated from parsed PLAN file; empty when no plan file existed. -- **Task files/verify after migration:** `SELECT id, files, verify_command FROM tasks WHERE milestone_id = ? AND slice_id = ?` — files is JSON array, verify_command is string (may include backtick formatting from parser). -- **Test suite:** `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/gsd-recover.test.ts` — 27 new assertions in Test a2 covering all v8 column populations. - -## Files Created/Modified - -- `src/resources/extensions/gsd/md-importer.ts` -- `src/resources/extensions/gsd/tests/gsd-recover.test.ts` diff --git a/.gsd/milestones/M001/slices/S05/tasks/T02-VERIFY.json b/.gsd/milestones/M001/slices/S05/tasks/T02-VERIFY.json deleted file mode 100644 index a021ab1f0..000000000 --- a/.gsd/milestones/M001/slices/S05/tasks/T02-VERIFY.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "schemaVersion": 1, - "taskId": "T02", - "unitId": "M001/S05/T02", - "timestamp": 1774288367911, - "passed": false, - "discoverySource": "package-json", - "checks": [ - { - "command": "npm run test", - "exitCode": 1, - "durationMs": 39566, - "verdict": "fail" - } - ], - "retryAttempt": 1, - "maxRetries": 2 -} diff --git a/.gsd/milestones/M001/slices/S05/tasks/T03-PLAN.md b/.gsd/milestones/M001/slices/S05/tasks/T03-PLAN.md deleted file mode 100644 index b05031071..000000000 --- a/.gsd/milestones/M001/slices/S05/tasks/T03-PLAN.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -estimated_steps: 4 -estimated_files: 7 -skills_used: [] ---- - -# T03: Migrate warm/cold callers batch 1 — doctor, visualizer, workspace, dashboard, guided-flow - -**Slice:** S05 — Warm/cold callers + flag files + pre-M002 migration -**Milestone:** M001 - -## Description - -Apply the established S04 migration pattern (`isDbAvailable()` gate + lazy `createRequire` fallback) to 7 warm/cold caller files: `doctor.ts`, `doctor-checks.ts`, `visualizer-data.ts`, `workspace-index.ts`, `dashboard-overlay.ts`, `auto-dashboard.ts`, `guided-flow.ts`. These files have straightforward parseRoadmap/parsePlan usage that can be mechanically replaced with DB queries. - -**Pattern reference (from S04 dispatch-guard.ts):** -```typescript -// Remove from module-level import: -// import { parseRoadmap } from "./files.js"; - -// Add to module-level import: -import { isDbAvailable, getMilestoneSlices } from "./gsd-db.js"; - -// At each call site, replace: -// const roadmap = parseRoadmap(content); -// for (const slice of roadmap.slices) { ... } -// With: -if (isDbAvailable()) { - const slices = getMilestoneSlices(mid); - // use slices directly — SliceRow has .id, .title, .status, .risk, .depends, .demo - // .done equivalent: slice.status === 'complete' -} else { - // Lazy fallback - const { createRequire } = await import("node:module"); - const _require = createRequire(import.meta.url); - let parseRoadmap: (c: string) => { slices: Array<{ id: string; done: boolean; title: string; risk: string; depends: string[]; demo: string }> }; - try { - parseRoadmap = _require("./files.ts").parseRoadmap; - } catch { - parseRoadmap = _require("./files.js").parseRoadmap; - } - const roadmap = parseRoadmap(content); - // ... use roadmap.slices -} -``` - -**Key mapping from parsed types to DB types:** -- `roadmap.slices[].done` → `slice.status === 'complete'` -- `roadmap.slices[].id/title/risk/depends/demo` → same field names on `SliceRow` -- `plan.tasks[].done` → `task.status === 'complete' || task.status === 'done'` -- `plan.tasks[].id/title` → same on `TaskRow` -- `plan.tasks[].files` → `task.files` (already parsed as `string[]` by `rowToTask()`) -- `plan.tasks[].verify` → `task.verify` -- `plan.filesLikelyTouched` → aggregate: `sliceTasks.flatMap(t => t.files)` - -**Important:** Some of these files have async functions (doctor.ts, visualizer-data.ts, workspace-index.ts, dashboard-overlay.ts, auto-dashboard.ts). For async callers, `await import("./gsd-db.js")` is cleaner than `createRequire`. For synchronous callers, use `createRequire`. Check each file. - -## Steps - -1. **doctor.ts** (3 parseRoadmap + 1 parsePlan): - - Remove `parseRoadmap`, `parsePlan` from the module-level import from `./files.js`. Keep `loadFile`, `parseSummary`, `saveFile`, `parseTaskPlanMustHaves`, `countMustHavesMentionedInSummary`. - - Add `import { isDbAvailable, getMilestoneSlices, getSliceTasks } from "./gsd-db.js";` - - At line ~216: replace `parseRoadmap(roadmapContent).slices` with `isDbAvailable() ? getMilestoneSlices(mid) : lazyParseRoadmap(roadmapContent).slices`. Map `.done` to `.status === 'complete'`. - - At line ~463: same pattern. - - At line ~582: replace `parsePlan(planContent)` with `isDbAvailable() ? { tasks: getSliceTasks(mid, sid) } : lazyParsePlan(planContent)`. Map task fields accordingly. - - Create a local lazy-parser helper function at the top of the file to avoid repeating the createRequire boilerplate. - -2. **doctor-checks.ts** (2 parseRoadmap): - - Remove `parseRoadmap` from import. Keep `loadFile`. - - Add DB imports. Replace 2 call sites with `getMilestoneSlices()` + fallback. - -3. **visualizer-data.ts** (1 parseRoadmap + 1 parsePlan): - - Remove parser imports. Add DB imports. Replace call sites. - -4. **workspace-index.ts** (2 parseRoadmap + 1 parsePlan): - - Remove parser imports. Add DB imports. Replace 3 call sites. - -5. **dashboard-overlay.ts** (1 parseRoadmap + 1 parsePlan): - - Remove parser imports. Add DB imports. Replace call sites. - -6. **auto-dashboard.ts** (1 parseRoadmap + 1 parsePlan): - - Remove parser imports. Add DB imports. Replace call sites. - -7. **guided-flow.ts** (2 parseRoadmap): - - Remove `parseRoadmap` from import. Keep `loadFile`. Add DB imports. Replace 2 call sites. - -After all changes, run verification grep and existing test suites. - -## Must-Haves - -- [ ] Zero module-level `parseRoadmap`/`parsePlan` imports in all 7 files -- [ ] Each file uses `isDbAvailable()` gate with DB query as primary path -- [ ] Each file has lazy `createRequire` (or dynamic import for async) fallback for parser -- [ ] `SliceRow.status === 'complete'` used instead of `.done` for all DB-path code -- [ ] Existing tests pass for all modified files - -## Verification - -- `grep -n 'import.*parseRoadmap\|import.*parsePlan' src/resources/extensions/gsd/doctor.ts src/resources/extensions/gsd/doctor-checks.ts src/resources/extensions/gsd/visualizer-data.ts src/resources/extensions/gsd/workspace-index.ts src/resources/extensions/gsd/dashboard-overlay.ts src/resources/extensions/gsd/auto-dashboard.ts src/resources/extensions/gsd/guided-flow.ts` — returns zero results -- Run available test suites: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/doctor.test.ts` -- Run `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/auto-dashboard.test.ts` (if exists) - -## Inputs - -- `src/resources/extensions/gsd/doctor.ts` — 3 parseRoadmap + 1 parsePlan calls to migrate -- `src/resources/extensions/gsd/doctor-checks.ts` — 2 parseRoadmap calls -- `src/resources/extensions/gsd/visualizer-data.ts` — 1 parseRoadmap + 1 parsePlan -- `src/resources/extensions/gsd/workspace-index.ts` — 2 parseRoadmap + 1 parsePlan -- `src/resources/extensions/gsd/dashboard-overlay.ts` — 1 parseRoadmap + 1 parsePlan -- `src/resources/extensions/gsd/auto-dashboard.ts` — 1 parseRoadmap + 1 parsePlan -- `src/resources/extensions/gsd/guided-flow.ts` — 2 parseRoadmap -- `src/resources/extensions/gsd/gsd-db.ts` — isDbAvailable(), getMilestoneSlices(), getSliceTasks(), SliceRow, TaskRow interfaces -- `src/resources/extensions/gsd/dispatch-guard.ts` — reference implementation of the migration pattern from S04 - -## Expected Output - -- `src/resources/extensions/gsd/doctor.ts` — module-level parser imports removed, DB queries + lazy fallback -- `src/resources/extensions/gsd/doctor-checks.ts` — same migration -- `src/resources/extensions/gsd/visualizer-data.ts` — same migration -- `src/resources/extensions/gsd/workspace-index.ts` — same migration -- `src/resources/extensions/gsd/dashboard-overlay.ts` — same migration -- `src/resources/extensions/gsd/auto-dashboard.ts` — same migration -- `src/resources/extensions/gsd/guided-flow.ts` — same migration - -## Observability Impact - -- **Signal change:** All 7 migrated files now use `isDbAvailable()` as primary data path. When DB is available, these callers read slice/task data from SQLite instead of parsing markdown. The lazy `createRequire` fallback logs to stderr when it activates, making parser-path usage detectable in logs. -- **Inspection:** `grep -rn 'isDbAvailable' src/resources/extensions/gsd/{doctor,doctor-checks,visualizer-data,workspace-index,dashboard-overlay,auto-dashboard,guided-flow}.ts` shows all gate points. At runtime, DB availability determines which path executes. -- **Failure visibility:** If DB is unavailable, fallback to parser is silent but functional. If parser also fails, existing error handling in each function propagates the failure (most are wrapped in try/catch with non-fatal fallthrough). diff --git a/.gsd/milestones/M001/slices/S05/tasks/T03-SUMMARY.md b/.gsd/milestones/M001/slices/S05/tasks/T03-SUMMARY.md deleted file mode 100644 index d7dfa83f6..000000000 --- a/.gsd/milestones/M001/slices/S05/tasks/T03-SUMMARY.md +++ /dev/null @@ -1,97 +0,0 @@ ---- -id: T03 -parent: S05 -milestone: M001 -key_files: - - src/resources/extensions/gsd/doctor.ts - - src/resources/extensions/gsd/doctor-checks.ts - - src/resources/extensions/gsd/visualizer-data.ts - - src/resources/extensions/gsd/workspace-index.ts - - src/resources/extensions/gsd/dashboard-overlay.ts - - src/resources/extensions/gsd/auto-dashboard.ts - - src/resources/extensions/gsd/guided-flow.ts -key_decisions: - - All 7 files use file-local lazy parser singletons via createRequire rather than a shared utility — consistent with dispatch-guard.ts reference pattern and avoids introducing a new shared module - - workspace-index.ts titleFromRoadmapHeader kept as lazy-parser-only (no DB path) because it extracts title from raw markdown header which has no direct DB equivalent for the formatted title string -duration: "" -verification_result: passed -completed_at: 2026-03-23T18:06:03.490Z -blocker_discovered: false ---- - -# T03: Migrate 7 warm/cold callers (doctor, doctor-checks, visualizer-data, workspace-index, dashboard-overlay, auto-dashboard, guided-flow) from module-level parseRoadmap/parsePlan imports to isDbAvailable() gate + lazy createRequire fallback - -**Migrate 7 warm/cold callers (doctor, doctor-checks, visualizer-data, workspace-index, dashboard-overlay, auto-dashboard, guided-flow) from module-level parseRoadmap/parsePlan imports to isDbAvailable() gate + lazy createRequire fallback** - -## What Happened - -Applied the established S04 migration pattern to all 7 target files. Each file had its module-level `parseRoadmap` and/or `parsePlan` imports removed from `./files.js` and replaced with: - -1. **DB imports:** `isDbAvailable`, `getMilestoneSlices`, `getSliceTasks` from `./gsd-db.js` -2. **Lazy parser helper:** A file-local `getLazyParsers()` (or `lazyParseRoadmap()`) function using `createRequire(import.meta.url)` to resolve `./files.ts` then `./files.js` on demand -3. **isDbAvailable() gate** at each call site: DB path uses `getMilestoneSlices()`/`getSliceTasks()` with `status === "complete"` mapped to `.done`; else-branch uses the lazy parser - -**File-by-file details:** - -- **doctor.ts** (3 parseRoadmap + 1 parsePlan): First call site in `selectDoctorScope()` inlines DB completion check. Second call site in `runDoctor()` normalizes slices into `NormSlice[]` compatible with `detectCircularDependencies` and downstream iteration. Third call site for `parsePlan` normalizes tasks from DB or parser. Replaced `isMilestoneComplete(roadmap)` at end-of-function with inline `roadmap.slices.every(s => s.done)` check since the local `roadmap` object only has `{ slices }`. - -- **doctor-checks.ts** (2 parseRoadmap): Both in `checkGitHealth()` for milestone completion checks (orphaned worktrees, stale branches). Each wrapped with `isDbAvailable()` gate — DB path counts complete slices directly. - -- **visualizer-data.ts** (1 parseRoadmap + 1 parsePlan): `loadVisualizerData()` now builds normalized slice list from DB or parser, then normalizes tasks for active slices similarly. - -- **workspace-index.ts** (2 parseRoadmap + 1 parsePlan): `titleFromRoadmapHeader()` uses lazy parser (sync helper, only called from async context). `indexSlice()` gets tasks from DB or parser. `indexWorkspace()` gets slices from DB or parser. - -- **dashboard-overlay.ts** (1 parseRoadmap + 1 parsePlan): `loadData()` builds normalized slice/task lists from DB or parser. - -- **auto-dashboard.ts** (1 parseRoadmap + 1 parsePlan): `updateSliceProgressCache()` is synchronous — uses `createRequire` for fallback. Both parseRoadmap and parsePlan replaced with DB primary paths. - -- **guided-flow.ts** (2 parseRoadmap): `buildDiscussSlicePrompt()` and `showDiscuss()` both normalize slices from DB or parser. The `showDiscuss()` guard was adjusted to allow DB-backed operation even when roadmap file is missing. - -## Verification - -All 5 must-haves verified: -1. Zero module-level parseRoadmap/parsePlan imports in all 7 files — confirmed by grep returning exit code 1 (no matches) -2. Each file uses isDbAvailable() gate — confirmed 2-3 gates per file -3. Each file has lazy createRequire fallback — confirmed 2 createRequire refs per file (1 import, 1 usage) -4. SliceRow.status === 'complete' used instead of .done for all DB-path code — confirmed in all files -5. All existing tests pass: doctor.test.ts (55 pass), auto-dashboard.test.ts (24 pass), auto-recovery.test.ts (33 pass), derive-state-db.test.ts (105 pass), derive-state-crossval.test.ts (189 pass), planning-crossval.test.ts (65 pass), markdown-renderer.test.ts (106 pass), flag-file-db.test.ts (14 pass), gsd-recover.test.ts (65 pass) — all zero failures - -## Verification Evidence - -| # | Command | Exit Code | Verdict | Duration | -|---|---------|-----------|---------|----------| -| 1 | `grep -n 'import.*parseRoadmap\|import.*parsePlan' src/resources/extensions/gsd/doctor.ts src/resources/extensions/gsd/doctor-checks.ts src/resources/extensions/gsd/visualizer-data.ts src/resources/extensions/gsd/workspace-index.ts src/resources/extensions/gsd/dashboard-overlay.ts src/resources/extensions/gsd/auto-dashboard.ts src/resources/extensions/gsd/guided-flow.ts` | 1 | ✅ pass | 50ms | -| 2 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/doctor.test.ts` | 0 | ✅ pass | 6900ms | -| 3 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/auto-dashboard.test.ts` | 0 | ✅ pass | 6900ms | -| 4 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/auto-recovery.test.ts` | 0 | ✅ pass | 6700ms | -| 5 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/derive-state-db.test.ts` | 0 | ✅ pass | 6700ms | -| 6 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/derive-state-crossval.test.ts` | 0 | ✅ pass | 6700ms | -| 7 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/planning-crossval.test.ts` | 0 | ✅ pass | 6700ms | -| 8 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts` | 0 | ✅ pass | 6700ms | -| 9 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/flag-file-db.test.ts` | 0 | ✅ pass | 6700ms | -| 10 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/gsd-recover.test.ts` | 0 | ✅ pass | 6700ms | - - -## Deviations - -In doctor.ts, replaced `isMilestoneComplete(roadmap)` calls at end-of-function with inline `roadmap.slices.every(s => s.done)` check because the local `roadmap` object was normalized to `{ slices: NormSlice[] }` which doesn't satisfy the full `Roadmap` type signature. The logic is identical. In guided-flow.ts showDiscuss(), adjusted the early return guard from `if (!roadmapContent)` to `if (!roadmapContent && !isDbAvailable())` so the DB path can function even without a roadmap file on disk. - -## Known Issues - -None. - -## Diagnostics - -- **Verify migration pattern applied:** `grep -c 'isDbAvailable' src/resources/extensions/gsd/{doctor,doctor-checks,visualizer-data,workspace-index,dashboard-overlay,auto-dashboard,guided-flow}.ts` — each file should show 2+ occurrences. -- **Verify no module-level parser imports:** `grep -n 'import.*parseRoadmap\|import.*parsePlan' src/resources/extensions/gsd/{doctor,doctor-checks,visualizer-data,workspace-index,dashboard-overlay,auto-dashboard,guided-flow}.ts` — should return no results. -- **Fallback detection:** When DB is unavailable, each file writes to stderr before using lazy createRequire parser — grep runtime logs for "createRequire" calls as fallback indicator. - -## Files Created/Modified - -- `src/resources/extensions/gsd/doctor.ts` -- `src/resources/extensions/gsd/doctor-checks.ts` -- `src/resources/extensions/gsd/visualizer-data.ts` -- `src/resources/extensions/gsd/workspace-index.ts` -- `src/resources/extensions/gsd/dashboard-overlay.ts` -- `src/resources/extensions/gsd/auto-dashboard.ts` -- `src/resources/extensions/gsd/guided-flow.ts` diff --git a/.gsd/milestones/M001/slices/S05/tasks/T03-VERIFY.json b/.gsd/milestones/M001/slices/S05/tasks/T03-VERIFY.json deleted file mode 100644 index 84227a046..000000000 --- a/.gsd/milestones/M001/slices/S05/tasks/T03-VERIFY.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "schemaVersion": 1, - "taskId": "T03", - "unitId": "M001/S05/T03", - "timestamp": 1774289222719, - "passed": false, - "discoverySource": "package-json", - "checks": [ - { - "command": "npm run test", - "exitCode": 1, - "durationMs": 40548, - "verdict": "fail" - } - ], - "retryAttempt": 1, - "maxRetries": 2 -} diff --git a/.gsd/milestones/M001/slices/S05/tasks/T04-PLAN.md b/.gsd/milestones/M001/slices/S05/tasks/T04-PLAN.md deleted file mode 100644 index 4902b06b6..000000000 --- a/.gsd/milestones/M001/slices/S05/tasks/T04-PLAN.md +++ /dev/null @@ -1,131 +0,0 @@ ---- -estimated_steps: 4 -estimated_files: 6 -skills_used: [] ---- - -# T04: Migrate warm/cold callers batch 2 — auto-prompts, auto-recovery, auto-direct-dispatch, auto-worktree, reactive-graph, markdown-renderer + final verification - -**Slice:** S05 — Warm/cold callers + flag files + pre-M002 migration -**Milestone:** M001 - -## Description - -Migrate the remaining 6 files with parseRoadmap/parsePlan imports. `auto-prompts.ts` is the most complex (6 parser calls across 1649 lines, all async functions — use dynamic `import()` pattern already established in that file). `markdown-renderer.ts` is special: its parser calls are intentional disk-vs-DB comparisons in `findStaleArtifacts()` — only move the import from module-level to lazy `createRequire`, don't replace parser usage. Final step: run the comprehensive grep to confirm zero module-level parser imports remain anywhere in the codebase (excluding tests, md-importer, files.ts). - -**Pattern for async callers (already used in auto-prompts.ts for decisions/requirements):** -```typescript -try { - const { isDbAvailable, getMilestoneSlices } = await import("./gsd-db.js"); - if (isDbAvailable()) { - const slices = getMilestoneSlices(mid); - // ... use DB data - return result; - } -} catch { /* fall through */ } -// Filesystem fallback -const roadmapContent = await loadFile(roadmapFile); -if (!roadmapContent) return null; -// lazy-load parser -const { createRequire } = await import("node:module"); -const _require = createRequire(import.meta.url); -let parseRoadmap: Function; -try { parseRoadmap = _require("./files.ts").parseRoadmap; } -catch { parseRoadmap = _require("./files.js").parseRoadmap; } -const roadmap = parseRoadmap(roadmapContent); -``` - -**Key field mappings:** -- `roadmap.slices[].done` → `slice.status === 'complete'` -- `plan.tasks[].done` → `task.status === 'complete' || task.status === 'done'` -- `plan.tasks[].files` → `task.files` (already parsed `string[]` per KNOWLEDGE.md) -- `plan.filesLikelyTouched` → `tasks.flatMap(t => t.files)` -- Slice `depends` field: same on `SliceRow` (already parsed as `string[]`) - -## Steps - -1. **auto-prompts.ts** (5 parseRoadmap + 1 parsePlan — all in async functions): - - Remove `parsePlan`, `parseRoadmap` from the module-level import on line 9. Keep `loadFile`, `parseContinue`, `parseSummary`, `extractUatType`, `loadActiveOverrides`, `formatOverridesSection`, `parseTaskPlanFile`. - - **`inlineDependencySummaries()` (line ~184):** Uses `parseRoadmap(roadmapContent).slices.find(s => s.id === sid)?.depends`. Replace with DB: `const { isDbAvailable, getSlice } = await import("./gsd-db.js"); if (isDbAvailable()) { const slice = getSlice(mid, sid); if (!slice || slice.depends.length === 0) return "- (no dependencies)"; /* use slice.depends */ }`. Fallback: lazy-load parseRoadmap. - - **`checkNeedsReassessment()` (line ~691):** Uses `parseRoadmap().slices` to find completed/incomplete slices. Replace with: `getMilestoneSlices(mid)`, filter by `s.status === 'complete'` vs not. - - **`checkNeedsRunUat()` (line ~732):** Same pattern as checkNeedsReassessment — replace with `getMilestoneSlices(mid)`. - - **`buildCompleteMilestonePrompt()` (line ~1221):** Iterates `roadmap.slices` to inline slice summaries. Replace with `getMilestoneSlices(mid)` to get slice IDs. - - **`buildValidateMilestonePrompt()` (line ~1277):** Same as buildCompleteMilestonePrompt — iterate `getMilestoneSlices(mid)` for slice summary inlining. - - **`buildResumeContextListing()` (line ~1603):** Uses `parsePlan(planContent).tasks` to find incomplete tasks for listing. Replace with `getSliceTasks(mid, sid)`, filter by `task.status !== 'complete' && task.status !== 'done'`. - - Create a local helper `async function lazyParseRoadmap(content: string)` and `async function lazyParsePlan(content: string)` at top of file to centralize the createRequire fallback pattern. - -2. **auto-recovery.ts** (1 parsePlan at line 370, 1 parseRoadmap at line 407): - - Remove `parseRoadmap`, `parsePlan` from module-level import on line 14. Keep `clearParseCache`. - - Line 370 `parsePlan`: Used in plan-slice completion check — gets task list to verify task plan files exist. Replace with `getSliceTasks(mid, sid)` to get task IDs, then check if task plan files exist on disk. Fallback: lazy-load parsePlan. - - Line 407 `parseRoadmap`: Already inside `!isDbAvailable()` block — this IS the fallback path. Just move the import from module-level to lazy `createRequire` at that call site. - - Add `import { isDbAvailable, getSliceTasks } from "./gsd-db.js";` to module-level imports. - -3. **auto-direct-dispatch.ts, auto-worktree.ts, reactive-graph.ts:** - - **auto-direct-dispatch.ts** (2 parseRoadmap at lines 160, 185): Remove `parseRoadmap` from import (keep `loadFile`). Add `isDbAvailable, getMilestoneSlices`. Replace both call sites with `getMilestoneSlices()` + fallback. - - **auto-worktree.ts** (1 parseRoadmap at line 1002): Remove `parseRoadmap` from import. Add DB imports. Replace call site. - - **reactive-graph.ts** (1 parsePlan at line 191): Remove `parsePlan` from import (keep `loadFile`, `parseTaskPlanIO`). Add `isDbAvailable, getSliceTasks`. Replace with `getSliceTasks()` + fallback. Note: `parseTaskPlanIO` is NOT a planning parser — it parses Inputs/Expected Output from task plan files for dependency graphing. Keep it as module-level import. - -4. **markdown-renderer.ts** (2 parseRoadmap + 2 parsePlan in `findStaleArtifacts()`): - - These parser calls are **intentional** — they compare disk content against DB state to detect staleness. Do NOT replace parser usage with DB queries. - - Move `parseRoadmap`, `parsePlan` from module-level import (line 33) to lazy `createRequire` inside `findStaleArtifacts()`. Keep `saveFile`, `clearParseCache` as module-level. - - At the top of `findStaleArtifacts()` (around line 775), add lazy loading: - ```typescript - const { createRequire } = await import("node:module"); - const _require = createRequire(import.meta.url); - let parseRoadmap: Function, parsePlan: Function; - try { - const m = _require("./files.ts"); - parseRoadmap = m.parseRoadmap; parsePlan = m.parsePlan; - } catch { - const m = _require("./files.js"); - parseRoadmap = m.parseRoadmap; parsePlan = m.parsePlan; - } - ``` - - Note: `findStaleArtifacts()` is async, so dynamic import works too. Use whichever is simpler. - -5. **Final verification grep:** - - `grep -rn 'import.*parseRoadmap\|import.*parsePlan\|import.*parseRoadmapSlices' src/resources/extensions/gsd/*.ts | grep -v '/tests/' | grep -v 'md-importer' | grep -v 'files.ts'` - - Expected: ZERO results. No module-level parser imports remain. - - Run `auto-recovery.test.ts` and any other available test suites for modified files. - -## Must-Haves - -- [ ] Zero module-level `parseRoadmap`/`parsePlan` imports in all 6 files -- [ ] `auto-prompts.ts` uses DB queries as primary path for all 6 parser call sites -- [ ] `auto-recovery.ts` parsePlan at line 370 replaced with getSliceTasks() + fallback -- [ ] `markdown-renderer.ts` parser imports moved to lazy loading (parser usage kept) -- [ ] Final grep returns zero module-level parser imports across all non-test source files -- [ ] All existing test suites pass - -## Verification - -- `grep -rn 'import.*parseRoadmap\|import.*parsePlan\|import.*parseRoadmapSlices' src/resources/extensions/gsd/*.ts | grep -v '/tests/' | grep -v 'md-importer' | grep -v 'files.ts'` — returns zero results -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/auto-recovery.test.ts` — passes -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts` — passes -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/planning-crossval.test.ts` — passes - -## Inputs - -- `src/resources/extensions/gsd/auto-prompts.ts` — 5 parseRoadmap + 1 parsePlan calls to migrate (all async functions) -- `src/resources/extensions/gsd/auto-recovery.ts` — 1 parsePlan + 1 parseRoadmap (latter already in !isDbAvailable block) -- `src/resources/extensions/gsd/auto-direct-dispatch.ts` — 2 parseRoadmap calls -- `src/resources/extensions/gsd/auto-worktree.ts` — 1 parseRoadmap call -- `src/resources/extensions/gsd/reactive-graph.ts` — 1 parsePlan call -- `src/resources/extensions/gsd/markdown-renderer.ts` — 2 parseRoadmap + 2 parsePlan (intentional disk-vs-DB comparison) -- `src/resources/extensions/gsd/gsd-db.ts` — isDbAvailable(), getMilestoneSlices(), getSliceTasks(), getSlice(), getTask() -- `src/resources/extensions/gsd/dispatch-guard.ts` — reference for lazy createRequire pattern - -## Expected Output - -- `src/resources/extensions/gsd/auto-prompts.ts` — module-level parser imports removed, 6 call sites use DB queries with lazy fallback -- `src/resources/extensions/gsd/auto-recovery.ts` — module-level parser imports removed, DB + lazy fallback -- `src/resources/extensions/gsd/auto-direct-dispatch.ts` — module-level parseRoadmap removed, DB + fallback -- `src/resources/extensions/gsd/auto-worktree.ts` — module-level parseRoadmap removed, DB + fallback -- `src/resources/extensions/gsd/reactive-graph.ts` — module-level parsePlan removed, DB + fallback -- `src/resources/extensions/gsd/markdown-renderer.ts` — module-level parser imports moved to lazy loading inside findStaleArtifacts() - -## Observability Impact - -- **Fallback visibility:** All 6 migrated files write to `process.stderr` when falling back from DB to lazy parser, matching the pattern established in T03. Detectable via `grep 'falling back to parser' `. -- **Inspection surface:** `isDbAvailable()` gate at each call site means DB-vs-parser path selection is deterministic and inspectable. A future agent can verify which path executed by checking stderr output. -- **Failure state:** If DB is corrupted or unavailable, all call sites gracefully degrade to lazy parser with stderr warning — no silent data loss or hard failure. diff --git a/.gsd/milestones/M001/slices/S05/tasks/T04-SUMMARY.md b/.gsd/milestones/M001/slices/S05/tasks/T04-SUMMARY.md deleted file mode 100644 index d9f998930..000000000 --- a/.gsd/milestones/M001/slices/S05/tasks/T04-SUMMARY.md +++ /dev/null @@ -1,116 +0,0 @@ ---- -id: T04 -parent: S05 -milestone: M001 -key_files: - - src/resources/extensions/gsd/auto-prompts.ts - - src/resources/extensions/gsd/auto-recovery.ts - - src/resources/extensions/gsd/auto-direct-dispatch.ts - - src/resources/extensions/gsd/auto-worktree.ts - - src/resources/extensions/gsd/reactive-graph.ts - - src/resources/extensions/gsd/markdown-renderer.ts -key_decisions: - - auto-prompts.ts uses file-local async lazyParseRoadmap/lazyParsePlan helpers (centralized createRequire fallback within the file) rather than per-callsite inline createRequire — reduces duplication across 6 call sites while keeping the lazy pattern file-local - - markdown-renderer.ts detectStaleRenders() parser calls kept as-is (intentional disk-vs-DB comparison) — only import moved to lazy createRequire inside the function - - auto-worktree.ts mergeMilestoneToMain maps both id and title from SliceRow since downstream code formats commit messages using s.title -duration: "" -verification_result: passed -completed_at: 2026-03-23T18:16:53.812Z -blocker_discovered: false ---- - -# T04: Migrate remaining 6 callers (auto-prompts, auto-recovery, auto-direct-dispatch, auto-worktree, reactive-graph, markdown-renderer) from module-level parseRoadmap/parsePlan imports to DB-primary + lazy fallback — zero module-level parser imports remain - -**Migrate remaining 6 callers (auto-prompts, auto-recovery, auto-direct-dispatch, auto-worktree, reactive-graph, markdown-renderer) from module-level parseRoadmap/parsePlan imports to DB-primary + lazy fallback — zero module-level parser imports remain** - -## What Happened - -Migrated all 6 remaining files with module-level parseRoadmap/parsePlan imports to the established DB-primary + lazy createRequire fallback pattern. - -**auto-prompts.ts** (6 call sites — most complex file): -- Removed `parsePlan` and `parseRoadmap` from module-level import. -- Added `lazyParseRoadmap()` and `lazyParsePlan()` async helper functions at top of file to centralize the createRequire fallback pattern. -- `inlineDependencySummaries()`: DB path uses `getSlice(mid, sid).depends` directly; parser fallback via `lazyParseRoadmap`. -- `checkNeedsReassessment()`: DB path uses `getMilestoneSlices(mid)` filtered by `status === "complete"`; parser fallback via `lazyParseRoadmap`. -- `checkNeedsRunUat()`: Same pattern as checkNeedsReassessment with full DB primary path. -- `buildCompleteMilestonePrompt()`: DB path uses `getMilestoneSlices(mid).map(s => s.id)` for slice ID iteration; parser fallback. -- `buildValidateMilestonePrompt()`: Same pattern as buildCompleteMilestonePrompt. -- `buildRewriteDocsPrompt()` (was misidentified as `buildResumeContextListing` in plan): DB path uses `getSliceTasks(mid, sid)` to find incomplete task IDs; parser fallback via `lazyParsePlan`. - -**auto-recovery.ts** (2 call sites): -- Removed `parseRoadmap` and `parsePlan` from module-level import; added `createRequire` from `node:module` and `getSliceTasks` from `gsd-db.js`. -- Line 370 parsePlan: DB path uses `getSliceTasks(mid, sid)` to get task IDs for verifying task plan files exist; createRequire fallback. -- Line 407 parseRoadmap: Already inside `!isDbAvailable()` block — moved import to lazy createRequire at call site. - -**auto-direct-dispatch.ts** (2 call sites): -- Removed `parseRoadmap` from import; added `isDbAvailable, getMilestoneSlices` from `gsd-db.js`. -- Both call sites (reassess + run-uat dispatches) use `getMilestoneSlices(mid).filter(s => s.status === "complete")` with createRequire fallback. - -**auto-worktree.ts** (1 call site): -- Removed `parseRoadmap` from import; added `createRequire` from `node:module` and `getMilestoneSlices` from `gsd-db.js`. -- `mergeMilestoneToMain()` uses `getMilestoneSlices(milestoneId)` for completed slice listing. Mapped both `id` and `title` since downstream code uses `s.title` for commit message formatting. - -**reactive-graph.ts** (1 call site): -- Removed `parsePlan` from import (kept `parseTaskPlanIO` which is NOT a planning parser); added `isDbAvailable, getSliceTasks` from `gsd-db.js`. -- `loadSliceTaskIO()` uses `getSliceTasks(mid, sid)` to get task entries with status mapping; createRequire fallback for parsePlan. - -**markdown-renderer.ts** (2 parseRoadmap + 2 parsePlan — intentional disk-vs-DB comparison): -- Moved `parseRoadmap` and `parsePlan` from module-level import to lazy `createRequire` inside `detectStaleRenders()`. Parser calls kept as-is because they intentionally compare disk state against DB state for staleness detection. -- Added `createRequire` from `node:module` as module-level import. - -**Final verification:** `grep -rn 'import.*parseRoadmap|import.*parsePlan|import.*parseRoadmapSlices' src/resources/extensions/gsd/*.ts | grep -v '/tests/' | grep -v 'md-importer' | grep -v 'files.ts'` returns zero results — no module-level parser imports remain anywhere in the codebase. - -## Verification - -All 4 verification commands pass: -1. Final grep for module-level parser imports → exit code 1 (no matches found) ✅ -2. auto-recovery.test.ts → 33 pass, 0 fail ✅ -3. markdown-renderer.test.ts → 106 pass, 0 fail ✅ -4. planning-crossval.test.ts → 65 pass, 0 fail ✅ - -Regression suites all pass: -5. doctor.test.ts → 55 pass ✅ -6. auto-dashboard.test.ts → 24 pass ✅ -7. derive-state-db.test.ts → 105 pass ✅ -8. derive-state-crossval.test.ts → 189 pass ✅ -9. flag-file-db.test.ts → 14 pass ✅ -10. gsd-recover.test.ts → 65 pass ✅ - -## Verification Evidence - -| # | Command | Exit Code | Verdict | Duration | -|---|---------|-----------|---------|----------| -| 1 | `grep -rn 'import.*parseRoadmap\|import.*parsePlan\|import.*parseRoadmapSlices' src/resources/extensions/gsd/*.ts | grep -v '/tests/' | grep -v 'md-importer' | grep -v 'files.ts'` | 1 | ✅ pass | 50ms | -| 2 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/auto-recovery.test.ts` | 0 | ✅ pass | 3100ms | -| 3 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/markdown-renderer.test.ts` | 0 | ✅ pass | 3100ms | -| 4 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/planning-crossval.test.ts` | 0 | ✅ pass | 3100ms | -| 5 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/doctor.test.ts` | 0 | ✅ pass | 3700ms | -| 6 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/auto-dashboard.test.ts` | 0 | ✅ pass | 3700ms | -| 7 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/derive-state-db.test.ts` | 0 | ✅ pass | 3700ms | -| 8 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/derive-state-crossval.test.ts` | 0 | ✅ pass | 3700ms | -| 9 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/flag-file-db.test.ts` | 0 | ✅ pass | 3700ms | -| 10 | `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/gsd-recover.test.ts` | 0 | ✅ pass | 3700ms | - - -## Deviations - -Plan referenced `buildResumeContextListing()` at line ~1603 — actual function is `buildRewriteDocsPrompt()` at that location. The parsePlan call site was identical; migrated correctly. Plan referenced `findStaleArtifacts()` in markdown-renderer.ts — actual function is `detectStaleRenders()` (synchronous, not async). Used `createRequire` instead of dynamic `import()` accordingly. - -## Known Issues - -None. - -## Diagnostics - -- **Final parser import audit:** `grep -rn 'import.*parseRoadmap\|import.*parsePlan\|import.*parseRoadmapSlices' src/resources/extensions/gsd/*.ts | grep -v '/tests/' | grep -v 'md-importer' | grep -v 'files.ts'` — zero results confirms all module-level parser imports eliminated. -- **auto-prompts.ts migration:** 6 call sites migrated; each has DB-primary path with lazy async fallback. `grep -c 'isDbAvailable\|lazyParseRoadmap\|lazyParsePlan' src/resources/extensions/gsd/auto-prompts.ts` shows helpers and gates. -- **markdown-renderer.ts:** Parser calls remain in `detectStaleRenders()` (intentional disk-vs-DB comparison) but import is lazy createRequire, not module-level. - -## Files Created/Modified - -- `src/resources/extensions/gsd/auto-prompts.ts` -- `src/resources/extensions/gsd/auto-recovery.ts` -- `src/resources/extensions/gsd/auto-direct-dispatch.ts` -- `src/resources/extensions/gsd/auto-worktree.ts` -- `src/resources/extensions/gsd/reactive-graph.ts` -- `src/resources/extensions/gsd/markdown-renderer.ts` diff --git a/.gsd/milestones/M001/slices/S05/tasks/T04-VERIFY.json b/.gsd/milestones/M001/slices/S05/tasks/T04-VERIFY.json deleted file mode 100644 index 98b75621e..000000000 --- a/.gsd/milestones/M001/slices/S05/tasks/T04-VERIFY.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "schemaVersion": 1, - "taskId": "T04", - "unitId": "M001/S05/T04", - "timestamp": 1774289844615, - "passed": false, - "discoverySource": "package-json", - "checks": [ - { - "command": "npm run test", - "exitCode": 1, - "durationMs": 37218, - "verdict": "fail" - } - ], - "retryAttempt": 1, - "maxRetries": 2 -} diff --git a/.gsd/milestones/M001/slices/S06/S06-PLAN.md b/.gsd/milestones/M001/slices/S06/S06-PLAN.md deleted file mode 100644 index 109202b87..000000000 --- a/.gsd/milestones/M001/slices/S06/S06-PLAN.md +++ /dev/null @@ -1,126 +0,0 @@ -# S06: Parser deprecation + cleanup - -**Goal:** Remove `parseRoadmap()`, `parsePlan()`, and `parseRoadmapSlices()` from the production runtime path. Parser functions survive only in a `parsers-legacy.ts` module used by `md-importer.ts` (migration), `state.ts` (pre-migration fallback), `detectStaleRenders()` (intentional disk-vs-DB comparison), and `commands-maintenance.ts` (cold-path branch cleanup). All 16 lazy `createRequire` fallback paths in migrated callers are stripped. Zero `parseRoadmap`/`parsePlan`/`parseRoadmapSlices` calls remain in the dispatch loop. -**Demo:** `grep -rn 'parseRoadmap\|parsePlan\|parseRoadmapSlices' src/resources/extensions/gsd/{dispatch-guard,auto-dispatch,auto-verification,parallel-eligibility}.ts` returns no matches. `grep -rn 'createRequire' src/resources/extensions/gsd/{dispatch-guard,auto-dispatch,auto-verification,parallel-eligibility,doctor,doctor-checks,visualizer-data,workspace-index,dashboard-overlay,auto-dashboard,guided-flow,auto-prompts,auto-recovery,auto-direct-dispatch,auto-worktree,reactive-graph}.ts` returns no matches. Full test suite passes. - -## Must-Haves - -- `parsers-legacy.ts` module contains `parseRoadmap()`, `parsePlan()`, `parseRoadmapSlices()`, and all supporting impl functions -- `files.ts` no longer exports `parseRoadmap` or `parsePlan` — no longer imports from `roadmap-slices.js` -- `state.ts`, `md-importer.ts`, `commands-maintenance.ts`, and `markdown-renderer.ts` (detectStaleRenders) import parsers from `parsers-legacy.ts` -- All 8 test files that import parsers updated to use `parsers-legacy.ts` -- All 16 migrated caller files have their lazy `createRequire` singletons and fallback `else` branches removed -- Zero `createRequire` imports remain in any of the 16 migrated caller files -- Full test suite passes with no regressions - -## Verification - -```bash -# 1. Zero parser references in dispatch-loop hot-path files -grep -rn 'parseRoadmap\|parsePlan\|parseRoadmapSlices' \ - src/resources/extensions/gsd/dispatch-guard.ts \ - src/resources/extensions/gsd/auto-dispatch.ts \ - src/resources/extensions/gsd/auto-verification.ts \ - src/resources/extensions/gsd/parallel-eligibility.ts -# Must return exit code 1 (no matches) - -# 2. Zero createRequire in any of the 16 migrated caller files -grep -rn 'createRequire' \ - src/resources/extensions/gsd/dispatch-guard.ts \ - src/resources/extensions/gsd/auto-dispatch.ts \ - src/resources/extensions/gsd/auto-verification.ts \ - src/resources/extensions/gsd/parallel-eligibility.ts \ - src/resources/extensions/gsd/doctor.ts \ - src/resources/extensions/gsd/doctor-checks.ts \ - src/resources/extensions/gsd/visualizer-data.ts \ - src/resources/extensions/gsd/workspace-index.ts \ - src/resources/extensions/gsd/dashboard-overlay.ts \ - src/resources/extensions/gsd/auto-dashboard.ts \ - src/resources/extensions/gsd/guided-flow.ts \ - src/resources/extensions/gsd/auto-prompts.ts \ - src/resources/extensions/gsd/auto-recovery.ts \ - src/resources/extensions/gsd/auto-direct-dispatch.ts \ - src/resources/extensions/gsd/auto-worktree.ts \ - src/resources/extensions/gsd/reactive-graph.ts -# Must return exit code 1 (no matches) - -# 3. Parser references only in allowed files (parsers-legacy, md-importer, state, commands-maintenance, markdown-renderer, debug-logger, native-parser-bridge, tests) -grep -rn 'parseRoadmap\|parsePlan\|parseRoadmapSlices' src/resources/extensions/gsd/*.ts \ - | grep -v '/tests/' | grep -v 'parsers-legacy' | grep -v 'md-importer' \ - | grep -v 'debug-logger' | grep -v 'native-parser-bridge' \ - | grep -v 'state.ts' | grep -v 'commands-maintenance' | grep -v 'markdown-renderer' -# Must return exit code 1 (no matches) — files.ts no longer has them - -# 4. Test suite passes -node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test \ - src/resources/extensions/gsd/tests/parsers.test.ts \ - src/resources/extensions/gsd/tests/roadmap-slices.test.ts \ - src/resources/extensions/gsd/tests/planning-crossval.test.ts \ - src/resources/extensions/gsd/tests/markdown-renderer.test.ts \ - src/resources/extensions/gsd/tests/doctor.test.ts \ - src/resources/extensions/gsd/tests/auto-dashboard.test.ts \ - src/resources/extensions/gsd/tests/auto-recovery.test.ts \ - src/resources/extensions/gsd/tests/derive-state-db.test.ts \ - src/resources/extensions/gsd/tests/derive-state-crossval.test.ts \ - src/resources/extensions/gsd/tests/gsd-recover.test.ts \ - src/resources/extensions/gsd/tests/flag-file-db.test.ts \ - src/resources/extensions/gsd/tests/migrate-writer.test.ts \ - src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts \ - src/resources/extensions/gsd/tests/complete-milestone.test.ts -``` - -## Observability / Diagnostics - -- **Failure visibility:** `doctor.test.ts` (and any test exercising the 16 migrated callers' fallback paths) will fail with `TypeError: getLazyParsers(...).parseRoadmap is not a function` after T01 completes — this is expected intermediate breakage that T02 resolves by stripping the fallback paths entirely. -- **Runtime signal:** `clearParseCache()` in `files.ts` invokes all registered cache-clear callbacks via `registerCacheClearCallback()`. If `parsers-legacy.ts` is not loaded (e.g., no consumer imported it), its cache won't be cleared — but this is correct: if nobody imported the parsers, there's nothing cached. -- **Inspection surface:** `grep -rn 'parseRoadmap\|parsePlan' src/resources/extensions/gsd/files.ts` must return exit code 1 (no matches) to confirm parser functions are fully extracted. -- **Diagnostic check:** After both tasks, `grep -rn 'createRequire' src/resources/extensions/gsd/{dispatch-guard,auto-dispatch,...}.ts` returns no matches — confirms all fallback paths removed. - -## Tasks - -- [x] **T01: Create parsers-legacy.ts and relocate all parser functions from files.ts** `est:45m` - - Why: Parser functions must be extracted from `files.ts` into a dedicated legacy module before fallback paths can be stripped — otherwise removing exports from `files.ts` breaks the 4 legitimate consumers and 8 test files simultaneously - - Files: `src/resources/extensions/gsd/parsers-legacy.ts` (new), `src/resources/extensions/gsd/files.ts`, `src/resources/extensions/gsd/state.ts`, `src/resources/extensions/gsd/md-importer.ts`, `src/resources/extensions/gsd/commands-maintenance.ts`, `src/resources/extensions/gsd/markdown-renderer.ts`, `src/resources/extensions/gsd/tests/parsers.test.ts`, `src/resources/extensions/gsd/tests/roadmap-slices.test.ts`, `src/resources/extensions/gsd/tests/planning-crossval.test.ts`, `src/resources/extensions/gsd/tests/auto-recovery.test.ts`, `src/resources/extensions/gsd/tests/markdown-renderer.test.ts`, `src/resources/extensions/gsd/tests/complete-milestone.test.ts`, `src/resources/extensions/gsd/tests/migrate-writer.test.ts`, `src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts` - - Do: Create `parsers-legacy.ts` containing `parseRoadmap()`, `_parseRoadmapImpl()`, `parsePlan()`, `_parsePlanImpl()`, `cachedParse()`, and re-exporting `parseRoadmapSlices` from `roadmap-slices.js`. Import `extractSection`, `parseBullets`, `extractBoldField` from `./files.js`. Import `splitFrontmatter`, `parseFrontmatterMap` from `../shared/frontmatter.js`. Import `nativeParseRoadmap`, `nativeParsePlanFile` from `./native-parser-bridge.js`. Import `debugTime`, `debugCount` from `./debug-logger.js`. Keep `clearParseCache()` exported from `files.ts` (other callers depend on it) — have `parsers-legacy.ts` import it from `./files.js`. Remove `parseRoadmap`, `_parseRoadmapImpl`, `parsePlan`, `_parsePlanImpl` from `files.ts`. Remove `import { parseRoadmapSlices }` and `nativeParseRoadmap`/`nativeParsePlanFile` from `files.ts` imports (keep `nativeExtractSection`/`nativeParseSummaryFile`/`NATIVE_UNAVAILABLE` — used by non-parser functions). Update `state.ts` import to `./parsers-legacy.js`. Update `md-importer.ts` import to `./parsers-legacy.js`. Update `commands-maintenance.ts` dynamic import to `./parsers-legacy.js`. Update `markdown-renderer.ts` detectStaleRenders lazy import to `./parsers-legacy.ts`/`.js`. Update all 8 test files' imports. - - Verify: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/parsers.test.ts src/resources/extensions/gsd/tests/roadmap-slices.test.ts src/resources/extensions/gsd/tests/planning-crossval.test.ts src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/auto-recovery.test.ts src/resources/extensions/gsd/tests/migrate-writer.test.ts src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts src/resources/extensions/gsd/tests/complete-milestone.test.ts` — all pass - - Done when: `parseRoadmap` and `parsePlan` no longer exported from `files.ts`, all consumers import from `parsers-legacy.ts`, all parser/crossval/renderer tests pass - -- [x] **T02: Strip all 16 lazy createRequire fallback paths from migrated callers** `est:35m` - - Why: With parsers relocated, the lazy fallback singletons in all 16 migrated callers are dead code — they imported from `files.ts` which no longer exports parsers. Strip them to complete the parser deprecation. - - Files: `src/resources/extensions/gsd/dispatch-guard.ts`, `src/resources/extensions/gsd/auto-dispatch.ts`, `src/resources/extensions/gsd/auto-verification.ts`, `src/resources/extensions/gsd/parallel-eligibility.ts`, `src/resources/extensions/gsd/doctor.ts`, `src/resources/extensions/gsd/doctor-checks.ts`, `src/resources/extensions/gsd/visualizer-data.ts`, `src/resources/extensions/gsd/workspace-index.ts`, `src/resources/extensions/gsd/dashboard-overlay.ts`, `src/resources/extensions/gsd/auto-dashboard.ts`, `src/resources/extensions/gsd/guided-flow.ts`, `src/resources/extensions/gsd/auto-prompts.ts`, `src/resources/extensions/gsd/auto-recovery.ts`, `src/resources/extensions/gsd/auto-direct-dispatch.ts`, `src/resources/extensions/gsd/auto-worktree.ts`, `src/resources/extensions/gsd/reactive-graph.ts` - - Do: For each of the 16 files: (1) remove `import { createRequire } from "node:module"`, (2) remove the lazy parser singleton declaration and function, (3) replace `if (isDbAvailable()) { ...DB path... } else { ...parser fallback... }` with just the DB path body — when DB unavailable, return early with empty/null/skip. Special cases: `workspace-index.ts` `titleFromRoadmapHeader` was parser-only with no DB equivalent — remove it or return null when DB unavailable. `auto-prompts.ts` has async `lazyParseRoadmap`/`lazyParsePlan` helpers wrapping 6 call sites — remove the helpers entirely and inline the DB-only path. `auto-recovery.ts` has `import { createRequire }` at top and 2 inline `createRequire` usages — remove all. Remove `import { createRequire }` from files that imported it only for parser fallback (check if any remaining non-parser `createRequire` usage exists before removing). - - Verify: Run all 4 grep verification commands from the slice verification section (all must exit 1 = no matches). Run full test suite: `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/doctor.test.ts src/resources/extensions/gsd/tests/auto-dashboard.test.ts src/resources/extensions/gsd/tests/auto-recovery.test.ts src/resources/extensions/gsd/tests/derive-state-db.test.ts src/resources/extensions/gsd/tests/derive-state-crossval.test.ts src/resources/extensions/gsd/tests/gsd-recover.test.ts src/resources/extensions/gsd/tests/flag-file-db.test.ts` - - Done when: All 4 grep checks return exit code 1. All test suites pass. Zero `createRequire` in any of the 16 files. - -## Files Likely Touched - -- `src/resources/extensions/gsd/parsers-legacy.ts` (new) -- `src/resources/extensions/gsd/files.ts` -- `src/resources/extensions/gsd/state.ts` -- `src/resources/extensions/gsd/md-importer.ts` -- `src/resources/extensions/gsd/commands-maintenance.ts` -- `src/resources/extensions/gsd/markdown-renderer.ts` -- `src/resources/extensions/gsd/dispatch-guard.ts` -- `src/resources/extensions/gsd/auto-dispatch.ts` -- `src/resources/extensions/gsd/auto-verification.ts` -- `src/resources/extensions/gsd/parallel-eligibility.ts` -- `src/resources/extensions/gsd/doctor.ts` -- `src/resources/extensions/gsd/doctor-checks.ts` -- `src/resources/extensions/gsd/visualizer-data.ts` -- `src/resources/extensions/gsd/workspace-index.ts` -- `src/resources/extensions/gsd/dashboard-overlay.ts` -- `src/resources/extensions/gsd/auto-dashboard.ts` -- `src/resources/extensions/gsd/guided-flow.ts` -- `src/resources/extensions/gsd/auto-prompts.ts` -- `src/resources/extensions/gsd/auto-recovery.ts` -- `src/resources/extensions/gsd/auto-direct-dispatch.ts` -- `src/resources/extensions/gsd/auto-worktree.ts` -- `src/resources/extensions/gsd/reactive-graph.ts` -- `src/resources/extensions/gsd/tests/parsers.test.ts` -- `src/resources/extensions/gsd/tests/roadmap-slices.test.ts` -- `src/resources/extensions/gsd/tests/planning-crossval.test.ts` -- `src/resources/extensions/gsd/tests/auto-recovery.test.ts` -- `src/resources/extensions/gsd/tests/markdown-renderer.test.ts` -- `src/resources/extensions/gsd/tests/complete-milestone.test.ts` -- `src/resources/extensions/gsd/tests/migrate-writer.test.ts` -- `src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts` diff --git a/.gsd/milestones/M001/slices/S06/S06-RESEARCH.md b/.gsd/milestones/M001/slices/S06/S06-RESEARCH.md deleted file mode 100644 index 8902a7861..000000000 --- a/.gsd/milestones/M001/slices/S06/S06-RESEARCH.md +++ /dev/null @@ -1,133 +0,0 @@ -# S06 — Research - -**Date:** 2026-03-23 - -## Summary - -S06 is the cleanup slice that removes parser code from the production runtime path. All 16+ callers were migrated to DB-primary with lazy `createRequire` parser fallback in S04–S05. S06 removes those lazy fallback paths entirely, making callers DB-only with graceful degradation when DB is unavailable. The parser functions themselves (`parseRoadmap`, `parsePlan`, `parseRoadmapSlices`) are relocated to a `parsers-legacy.ts` module used only by `md-importer.ts` (pre-M002 migration), `state.ts` `_deriveStateImpl()` (pre-migration fallback), `detectStaleRenders()` (intentional disk-vs-DB comparison), and `commands-maintenance.ts` (cold-path branch cleanup). - -This is straightforward mechanical work — the pattern is established, the callers are known, and the verification is simple: grep for imports, run the test suite. The main risk is breaking a fallback path that's hard to test in normal CI (the `isDbAvailable() === false` branch). - -## Recommendation - -Three-task decomposition: - -1. **Create `parsers-legacy.ts`** — Move `parseRoadmap()`, `_parseRoadmapImpl()`, `parsePlan()`, `_parsePlanImpl()` from `files.ts` into a new `parsers-legacy.ts` file. Move `parseRoadmapSlices()`, `expandDependencies()`, and all helper functions from `roadmap-slices.ts` into the same file (or have `parsers-legacy.ts` import from `roadmap-slices.ts` — either works). Update `md-importer.ts`, `state.ts`, `commands-maintenance.ts`, and `markdown-renderer.ts` `detectStaleRenders()` to import from the new location. Update test files that test parsers directly. - -2. **Remove all lazy fallback paths from callers** — Strip the `createRequire` lazy parser singletons and the `else` branches from all 16 migrated callers. Each caller's `if (isDbAvailable()) { ... } else { /* parser fallback */ }` becomes just the DB path with graceful skip/empty-return when DB is unavailable. This is the bulk of the line reduction. - -3. **Final cleanup + verification** — Remove `parseRoadmap`/`parsePlan` exports from `files.ts` (they now live in `parsers-legacy.ts`). Clean up the `roadmap-slices.ts` → `files.ts` import chain. Remove parser counters from `debug-logger.ts` (or keep them — they're still valid if the legacy parsers use them). Run full test suite. Grep verification for zero dispatch-loop parser references. - -## Implementation Landscape - -### Key Files - -- **`src/resources/extensions/gsd/roadmap-slices.ts`** (271 lines) — Contains `parseRoadmapSlices()` with 12 prose variant patterns, `expandDependencies()`, table parser, checkbox parser, prose header parser. The entire file is the removal target. Either absorbed into `parsers-legacy.ts` or kept as-is and only imported by `parsers-legacy.ts`. -- **`src/resources/extensions/gsd/files.ts`** (1170 lines) — Contains `parseRoadmap()` (lines 122–211, ~90 lines), `parsePlan()` (lines 317–443, ~125 lines), and their cached-parse wrappers. These move to `parsers-legacy.ts`. Also imports `parseRoadmapSlices` from `roadmap-slices.js` at line 24 and `nativeParseRoadmap`/`nativeParsePlanFile` from `native-parser-bridge.js` at line 25 — both imports move with the parser functions. -- **`src/resources/extensions/gsd/dispatch-guard.ts`** (106 lines) — Hot path. Has `lazyParseRoadmapSlices()` fallback at lines 13–23. Remove the fallback function and the `else` branch at line 88. When DB unavailable, return `null` (no blocker info available). -- **`src/resources/extensions/gsd/auto-dispatch.ts`** (656 lines) — Hot path. Has `_lazyParseRoadmap` singleton at lines 19–29. Three `if (isDbAvailable())` blocks at lines 192, 532, 600. Remove fallback branches. -- **`src/resources/extensions/gsd/auto-verification.ts`** (233 lines) — Hot path. Has disk fallback at lines 71–83. Remove. -- **`src/resources/extensions/gsd/parallel-eligibility.ts`** — Hot path. Has fallback at lines 42+. Remove. -- **`src/resources/extensions/gsd/doctor.ts`** — Warm path. Has `_lazyParsers` singleton. Remove fallback, keep DB path. -- **`src/resources/extensions/gsd/doctor-checks.ts`** — Warm path. Has `_lazyParseRoadmap`. Remove fallback. -- **`src/resources/extensions/gsd/visualizer-data.ts`** — Warm path. Has `_lazyParsers`. Remove fallback. -- **`src/resources/extensions/gsd/workspace-index.ts`** — Warm path. Has `_lazyParsers`. Note: `titleFromRoadmapHeader` at line 80 is parser-only with no DB path — needs special handling (either add DB path or remove feature when DB unavailable). -- **`src/resources/extensions/gsd/dashboard-overlay.ts`** — Warm path. Has `_lazyParsers`. Remove fallback. -- **`src/resources/extensions/gsd/auto-dashboard.ts`** — Warm path. Has `_lazyParsers`. Remove fallback. -- **`src/resources/extensions/gsd/guided-flow.ts`** — Warm path. Has `_lazyParseRoadmap`. Remove fallback. -- **`src/resources/extensions/gsd/auto-prompts.ts`** — Warm path. Has async `lazyParseRoadmap`/`lazyParsePlan` helpers (6 call sites). Remove fallback branches. -- **`src/resources/extensions/gsd/auto-recovery.ts`** — Warm path. Has 2 inline `createRequire` fallbacks. Remove. -- **`src/resources/extensions/gsd/auto-direct-dispatch.ts`** — Warm path. Has 2 inline `createRequire` fallbacks. Remove. -- **`src/resources/extensions/gsd/auto-worktree.ts`** — Warm path. Has 1 inline `createRequire` fallback. Remove. -- **`src/resources/extensions/gsd/reactive-graph.ts`** — Warm path. Has 1 inline `createRequire` fallback. Remove. -- **`src/resources/extensions/gsd/markdown-renderer.ts`** — `detectStaleRenders()` at line 780 uses lazy parser — keep this one, but change import source to `parsers-legacy.ts`. -- **`src/resources/extensions/gsd/state.ts`** — `_deriveStateImpl()` uses `parseRoadmap`/`parsePlan` at module-level import from `files.js`. Change import source to `parsers-legacy.ts`. -- **`src/resources/extensions/gsd/md-importer.ts`** — Module-level import of `parseRoadmap`/`parsePlan` from `files.js` at line 32. Change import source to `parsers-legacy.ts`. -- **`src/resources/extensions/gsd/commands-maintenance.ts`** — Dynamic import of `parseRoadmap` from `files.js` at line 47. Change import source to `parsers-legacy.ts` or migrate to DB query (cold path, either approach works). -- **`src/resources/extensions/gsd/debug-logger.ts`** — Has `parseRoadmapCalls`/`parsePlanCalls` counters at lines 22–25 and summary output at lines 162–166. Keep — the legacy parsers still call `debugCount()`. -- **`src/resources/extensions/gsd/native-parser-bridge.ts`** — Provides `nativeParseRoadmap()`/`nativeParsePlanFile()` called by `_parseRoadmapImpl()`/`_parsePlanImpl()`. Moves with the parser functions to `parsers-legacy.ts` imports. - -### Callers to Strip (16 files, all have `isDbAvailable()` + lazy fallback pattern) - -| File | Lazy singleton / import to remove | DB function used | -|------|-----------------------------------|------------------| -| `dispatch-guard.ts` | `lazyParseRoadmapSlices()` | `getMilestoneSlices()` | -| `auto-dispatch.ts` | `_lazyParseRoadmap` | `getMilestoneSlices()` | -| `auto-verification.ts` | inline `createRequire` for `parsePlan` | `getTask()` | -| `parallel-eligibility.ts` | inline `createRequire` for `parseRoadmap`/`parsePlan` | `getMilestoneSlices()`/`getSliceTasks()` | -| `doctor.ts` | `_lazyParsers` | `getMilestoneSlices()`/`getSliceTasks()` | -| `doctor-checks.ts` | `_lazyParseRoadmap` | `getMilestoneSlices()` | -| `visualizer-data.ts` | `_lazyParsers` | `getMilestoneSlices()`/`getSliceTasks()` | -| `workspace-index.ts` | `_lazyParsers` | `getMilestoneSlices()`/`getSliceTasks()` | -| `dashboard-overlay.ts` | `_lazyParsers` | `getMilestoneSlices()`/`getSliceTasks()` | -| `auto-dashboard.ts` | `_lazyParsers` | `getMilestoneSlices()`/`getSliceTasks()` | -| `guided-flow.ts` | `_lazyParseRoadmap` | `getMilestoneSlices()` | -| `auto-prompts.ts` | `lazyParseRoadmap()`/`lazyParsePlan()` | `getMilestoneSlices()`/`getSliceTasks()` | -| `auto-recovery.ts` | 2× inline `createRequire` | DB queries | -| `auto-direct-dispatch.ts` | 2× inline `createRequire` | `getMilestoneSlices()` | -| `auto-worktree.ts` | 1× inline `createRequire` | `getMilestoneSlices()` | -| `reactive-graph.ts` | 1× inline `createRequire` | `getSliceTasks()` | - -### Build Order - -1. **T01: Create `parsers-legacy.ts` + relocate parsers** — Move `parseRoadmap()`, `parsePlan()`, supporting functions, and `roadmap-slices.ts` content into `parsers-legacy.ts`. Update the 4 legitimate consumers (`md-importer.ts`, `state.ts`, `commands-maintenance.ts`, `markdown-renderer.ts detectStaleRenders()`) to import from new location. Update test files. Run parser tests + cross-validation tests to confirm nothing broke. This must go first because T02 removes the `files.ts` exports that callers currently fall back to. - -2. **T02: Strip lazy fallback paths from all 16 callers** — Remove `createRequire` imports, lazy parser singletons, and `else` branches from all migrated callers. Each `if (isDbAvailable())` check either becomes: (a) just the DB path with early return/skip when DB unavailable, or (b) the `if` guard is removed entirely if the caller is only reached when DB is active (like hot-path dispatch functions). Remove the `import { createRequire }` from files that no longer need it. Run the full test suite. - -3. **T03: Final cleanup + verification** — Remove `parseRoadmap`/`parsePlan` from `files.ts` exports. Remove `import { parseRoadmapSlices }` from `files.ts`. Clean up `roadmap-slices.ts` (either delete if fully absorbed, or mark as legacy-only). Update `files.ts` to remove the `native-parser-bridge` imports that only the parser functions used. Final grep verification: zero `parseRoadmap`/`parsePlan`/`parseRoadmapSlices` references in dispatch loop files. Run full test suite. - -### Verification Approach - -1. **Grep verification (primary):** - ```bash - # Zero parser references in dispatch loop (excluding comments): - grep -rn 'parseRoadmap\|parsePlan\|parseRoadmapSlices' \ - src/resources/extensions/gsd/dispatch-guard.ts \ - src/resources/extensions/gsd/auto-dispatch.ts \ - src/resources/extensions/gsd/auto-verification.ts \ - src/resources/extensions/gsd/parallel-eligibility.ts - - # Zero createRequire in callers that had fallbacks removed: - grep -rn 'createRequire' src/resources/extensions/gsd/{doctor,doctor-checks,visualizer-data,workspace-index,dashboard-overlay,auto-dashboard,guided-flow,auto-prompts,auto-recovery,auto-direct-dispatch,auto-worktree,reactive-graph,dispatch-guard,auto-dispatch,auto-verification,parallel-eligibility}.ts - - # Parser functions only exist in parsers-legacy.ts, md-importer.ts, and test files: - grep -rn 'parseRoadmap\|parsePlan\|parseRoadmapSlices' src/resources/extensions/gsd/*.ts \ - | grep -v '/tests/' | grep -v 'parsers-legacy' | grep -v 'md-importer' \ - | grep -v 'debug-logger' | grep -v 'native-parser-bridge' \ - | grep -v 'state.ts' | grep -v 'commands-maintenance' | grep -v 'markdown-renderer' - # Should return zero lines - ``` - -2. **Test suite verification:** - - `parsers.test.ts` — all existing parser tests pass (import path updated) - - `roadmap-slices.test.ts` — 16 tests pass (import path updated) - - `planning-crossval.test.ts` — 65 tests pass (import path updated) - - `markdown-renderer.test.ts` — 106 tests pass - - `doctor.test.ts` — 55 tests pass - - `auto-dashboard.test.ts` — 24 tests pass - - `auto-recovery.test.ts` — 33 tests pass - - `derive-state-db.test.ts` — 105 tests pass - - `derive-state-crossval.test.ts` — 189 tests pass - - `gsd-recover.test.ts` — 65 tests pass - - `flag-file-db.test.ts` — 14 tests pass - -3. **`roadmap-slices.ts` line reduction:** Confirm the file is either deleted or reduced to re-export only. - -## Constraints - -- **`_deriveStateImpl()` in `state.ts` MUST keep working** — it's the pre-migration fallback for projects without DB hierarchy data. It imports `parseRoadmap` and `parsePlan` at module level. These imports change from `./files.js` to `./parsers-legacy.js`. -- **`detectStaleRenders()` in `markdown-renderer.ts` intentionally compares disk-parsed vs DB state** — this is by design (S05 decision). It must keep using parsers. Import changes from lazy `createRequire` of `files.ts` to lazy `createRequire` of `parsers-legacy.ts`. -- **`md-importer.ts` is the canonical migration path** — it must keep its `parseRoadmap`/`parsePlan` imports. Import source changes. -- **`commands-maintenance.ts` has a dynamic `await import("./files.js")` for `parseRoadmap`** — this is a cold-path branch-cleanup command. Either migrate to DB query or update import to `parsers-legacy.ts`. -- **`workspace-index.ts` `titleFromRoadmapHeader` uses parser-only path** (line 80) — no DB equivalent was added in S05. Either add a DB path or accept this feature degrades when DB is unavailable. -- **Test files that import parsers** (`parsers.test.ts`, `roadmap-slices.test.ts`, `planning-crossval.test.ts`, `markdown-renderer.test.ts`, `auto-recovery.test.ts`, `complete-milestone.test.ts`, `migrate-writer.test.ts`, `migrate-writer-integration.test.ts`) — import paths must be updated. -- **`native-parser-bridge.ts`** is consumed by `_parseRoadmapImpl()` and `_parsePlanImpl()` in `files.ts` today. When those functions move to `parsers-legacy.ts`, the import follows. `native-parser-bridge.ts` itself stays unchanged — it's also used by `forensics.ts`, `paths.ts`, `session-forensics.ts`, `state.ts` for non-parser functions. - -## Common Pitfalls - -- **Missing a caller** — There are 16+ files with lazy fallbacks. Use the grep verification commands above to confirm zero stragglers. The `commands-maintenance.ts` dynamic import was NOT migrated in S05 and must be handled here. -- **Breaking `_deriveStateImpl()`** — If `parseRoadmap`/`parsePlan` are deleted from `files.ts` without updating `state.ts` imports, the pre-migration fallback path breaks silently (only triggered when DB is empty). -- **Test import path drift** — Many test files import `parseRoadmap`/`parsePlan` from `../files.ts`. If these exports are removed from `files.ts`, every test that imports them breaks. Update test imports to `../parsers-legacy.ts`. -- **`cachedParse()` and `clearParseCache()`** — These are in `files.ts` and used by the parser functions. They need to move with the parsers or be importable from `files.ts` by `parsers-legacy.ts`. `clearParseCache()` is also imported by `cache.ts` and `db-writer.ts` — keep it exported from `files.ts` and have `parsers-legacy.ts` import it. -- **`extractSection()`, `parseBullets()`, `extractBoldField()`** — Utility functions in `files.ts` used by both the parser functions AND other non-parser code (`parseSummary`, `parseContinue`, `parseSecretsManifest`, etc.). These MUST stay in `files.ts`. `parsers-legacy.ts` imports them. -- **`splitFrontmatter`/`parseFrontmatterMap`** — Re-exported from `files.ts`, also used by parser functions. `parsers-legacy.ts` can import from `../shared/frontmatter.js` directly. diff --git a/.gsd/milestones/M001/slices/S06/tasks/T01-PLAN.md b/.gsd/milestones/M001/slices/S06/tasks/T01-PLAN.md deleted file mode 100644 index 8282177a6..000000000 --- a/.gsd/milestones/M001/slices/S06/tasks/T01-PLAN.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -estimated_steps: 6 -estimated_files: 14 -skills_used: [] ---- - -# T01: Create parsers-legacy.ts and relocate all parser functions from files.ts - -**Slice:** S06 — Parser deprecation + cleanup -**Milestone:** M001 - -## Description - -Extract `parseRoadmap()`, `parsePlan()`, and all supporting implementation functions from `files.ts` into a new `parsers-legacy.ts` module. Update the 4 legitimate production consumers and 8 test files to import from the new location. Remove parser exports from `files.ts`. This is the structural foundation — T02 cannot strip fallback paths until parsers live in their own module. - -## Steps - -1. **Create `src/resources/extensions/gsd/parsers-legacy.ts`** with these contents: - - Import `extractSection`, `parseBullets`, `extractBoldField`, `clearParseCache` from `./files.js` (these stay in files.ts — used by non-parser code too) - - Import `splitFrontmatter`, `parseFrontmatterMap` from `../shared/frontmatter.js` - - Import `nativeParseRoadmap`, `nativeParsePlanFile` from `./native-parser-bridge.js` - - Import `debugTime`, `debugCount` from `./debug-logger.js` - - Import `CACHE_MAX` from `./constants.js` - - Import relevant types from `./types.js` (Roadmap, BoundaryMapEntry, SlicePlan, TaskPlanEntry, TaskPlanFrontmatter, etc.) - - Re-export `parseRoadmapSlices` from `./roadmap-slices.js` - - Copy `cachedParse()` function (the caching wrapper used by parseRoadmap/parsePlan — note: `clearParseCache` stays in `files.ts` and clears the cache there; `parsers-legacy.ts` needs its own cache instance OR imports the cache map from `files.ts`. Investigate which approach works — likely need a local `cachedParse` with its own WeakMap/Map since the cache in `files.ts` is module-private) - - Move `_parseRoadmapImpl()` and its `parseRoadmap()` wrapper - - Move `_parsePlanImpl()` and its `parsePlan()` wrapper - - Export `parseRoadmap` and `parsePlan` - -2. **Handle `cachedParse` carefully.** The cache in `files.ts` is module-private (`const parseCache = new Map()`). Options: (a) `parsers-legacy.ts` has its own local cache, (b) export the cache from `files.ts` — option (a) is cleaner. Also export a `clearLegacyParseCache()` from `parsers-legacy.ts` and have `clearParseCache()` in `files.ts` call it (since `clearParseCache` is called by `cache.ts`, `db-writer.ts`, `auto-recovery.ts`, `markdown-renderer.ts` and they expect it to clear parser caches). Alternatively: just duplicate `cachedParse` in `parsers-legacy.ts` with its own `parseCache` Map. The existing `clearParseCache()` in `files.ts` would only clear the `files.ts` caches (parseSummary, parseContinue), and since no production code uses `parseRoadmap`/`parsePlan` from `files.ts` anymore, the old cache entries for those would never accumulate. This is simplest. - -3. **Remove from `files.ts`:** Delete `parseRoadmap()`, `_parseRoadmapImpl()`, `parsePlan()`, `_parsePlanImpl()`. Remove `import { parseRoadmapSlices } from './roadmap-slices.js'` (only used by `_parseRoadmapImpl`). Remove `nativeParseRoadmap` and `nativeParsePlanFile` from the `native-parser-bridge.js` import line (keep `nativeExtractSection`, `nativeParseSummaryFile`, `NATIVE_UNAVAILABLE` — used by `extractSection()` and `parseSummary()`). - -4. **Update production consumers:** - - `state.ts` line 15-16: change `import { parseRoadmap, parsePlan, ... } from './files.js'` → split into `import { parseRoadmap, parsePlan } from './parsers-legacy.js'` + keep remaining imports from `./files.js` - - `md-importer.ts` line 32: change `import { parseRoadmap, parsePlan, parseContextDependsOn } from './files.js'` → `import { parseRoadmap, parsePlan } from './parsers-legacy.js'` + `import { parseContextDependsOn } from './files.js'` - - `commands-maintenance.ts` line 47: change `await import("./files.js")` → `await import("./parsers-legacy.js")` for `parseRoadmap`; keep `loadFile` import from `./files.js` - - `markdown-renderer.ts` ~line 782-788: change lazy `createRequire` import from `./files.ts`/`./files.js` to `./parsers-legacy.ts`/`./parsers-legacy.js` - -5. **Update test file imports:** For each of these 8 test files, change `parseRoadmap`/`parsePlan` imports from `../files.ts` to `../parsers-legacy.ts`: - - `tests/parsers.test.ts` — imports parseRoadmap, parsePlan from `../files.ts` - - `tests/roadmap-slices.test.ts` — imports parseRoadmap from `../files.ts` - - `tests/planning-crossval.test.ts` — imports parsePlan from `../files.ts` - - `tests/auto-recovery.test.ts` — imports parseRoadmap, parsePlan from `../files.ts` - - `tests/markdown-renderer.test.ts` — imports parseRoadmap, parsePlan from `../files.ts` - - `tests/complete-milestone.test.ts` — dynamic `await import("../files.ts")` for parseRoadmap - - `tests/migrate-writer.test.ts` — imports parseRoadmap, parsePlan from `../files.ts` - - `tests/migrate-writer-integration.test.ts` — imports parseRoadmap, parsePlan from `../files.ts` - -6. **Run parser and cross-validation tests** to verify nothing broke. - -## Must-Haves - -- [ ] `parsers-legacy.ts` exists and exports `parseRoadmap`, `parsePlan`, `parseRoadmapSlices` -- [ ] `files.ts` no longer exports `parseRoadmap` or `parsePlan` -- [ ] `files.ts` no longer imports from `roadmap-slices.js` -- [ ] `files.ts` native-parser-bridge import no longer includes `nativeParseRoadmap` or `nativeParsePlanFile` -- [ ] `state.ts` imports `parseRoadmap`/`parsePlan` from `parsers-legacy.js` -- [ ] `md-importer.ts` imports `parseRoadmap`/`parsePlan` from `parsers-legacy.js` -- [ ] `commands-maintenance.ts` dynamic import uses `parsers-legacy.js` -- [ ] `markdown-renderer.ts` detectStaleRenders lazy import uses `parsers-legacy` -- [ ] All 8 test files import from `parsers-legacy.ts` instead of `files.ts` -- [ ] All parser, crossval, and renderer tests pass - -## Verification - -- `grep -n 'export function parseRoadmap\|export function parsePlan' src/resources/extensions/gsd/files.ts` returns exit code 1 (no matches) -- `grep -n 'parseRoadmapSlices' src/resources/extensions/gsd/files.ts` returns exit code 1 -- `grep -n 'export function parseRoadmap' src/resources/extensions/gsd/parsers-legacy.ts` returns match -- `grep -n 'export function parsePlan' src/resources/extensions/gsd/parsers-legacy.ts` returns match -- `node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test src/resources/extensions/gsd/tests/parsers.test.ts src/resources/extensions/gsd/tests/roadmap-slices.test.ts src/resources/extensions/gsd/tests/planning-crossval.test.ts src/resources/extensions/gsd/tests/markdown-renderer.test.ts src/resources/extensions/gsd/tests/auto-recovery.test.ts src/resources/extensions/gsd/tests/migrate-writer.test.ts src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts src/resources/extensions/gsd/tests/complete-milestone.test.ts` — all pass - -## Inputs - -- `src/resources/extensions/gsd/files.ts` — contains `parseRoadmap()`, `_parseRoadmapImpl()`, `parsePlan()`, `_parsePlanImpl()`, `cachedParse()` to extract -- `src/resources/extensions/gsd/roadmap-slices.ts` — contains `parseRoadmapSlices()` to re-export -- `src/resources/extensions/gsd/state.ts` — module-level import of parseRoadmap/parsePlan from files.js at lines 15-16 -- `src/resources/extensions/gsd/md-importer.ts` — imports parseRoadmap/parsePlan from files.js at line 32 -- `src/resources/extensions/gsd/commands-maintenance.ts` — dynamic import of parseRoadmap from files.js at line 47 -- `src/resources/extensions/gsd/markdown-renderer.ts` — lazy createRequire import of parseRoadmap/parsePlan from files at ~line 782 -- `src/resources/extensions/gsd/tests/parsers.test.ts` — imports from ../files.ts -- `src/resources/extensions/gsd/tests/roadmap-slices.test.ts` — imports from ../files.ts -- `src/resources/extensions/gsd/tests/planning-crossval.test.ts` — imports from ../files.ts -- `src/resources/extensions/gsd/tests/auto-recovery.test.ts` — imports from ../files.ts -- `src/resources/extensions/gsd/tests/markdown-renderer.test.ts` — imports from ../files.ts -- `src/resources/extensions/gsd/tests/complete-milestone.test.ts` — dynamic import from ../files.ts -- `src/resources/extensions/gsd/tests/migrate-writer.test.ts` — imports from ../files.ts -- `src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts` — imports from ../files.ts - -## Expected Output - -- `src/resources/extensions/gsd/parsers-legacy.ts` — new module exporting parseRoadmap, parsePlan, parseRoadmapSlices -- `src/resources/extensions/gsd/files.ts` — parser functions and roadmap-slices/native-parser-bridge parser imports removed -- `src/resources/extensions/gsd/state.ts` — import updated to parsers-legacy.js -- `src/resources/extensions/gsd/md-importer.ts` — import updated to parsers-legacy.js -- `src/resources/extensions/gsd/commands-maintenance.ts` — dynamic import updated to parsers-legacy.js -- `src/resources/extensions/gsd/markdown-renderer.ts` — lazy import updated to parsers-legacy -- `src/resources/extensions/gsd/tests/parsers.test.ts` — import updated -- `src/resources/extensions/gsd/tests/roadmap-slices.test.ts` — import updated -- `src/resources/extensions/gsd/tests/planning-crossval.test.ts` — import updated -- `src/resources/extensions/gsd/tests/auto-recovery.test.ts` — import updated -- `src/resources/extensions/gsd/tests/markdown-renderer.test.ts` — import updated -- `src/resources/extensions/gsd/tests/complete-milestone.test.ts` — import updated -- `src/resources/extensions/gsd/tests/migrate-writer.test.ts` — import updated -- `src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts` — import updated diff --git a/.gsd/milestones/M001/slices/S06/tasks/T02-PLAN.md b/.gsd/milestones/M001/slices/S06/tasks/T02-PLAN.md deleted file mode 100644 index c28b7b77f..000000000 --- a/.gsd/milestones/M001/slices/S06/tasks/T02-PLAN.md +++ /dev/null @@ -1,143 +0,0 @@ ---- -estimated_steps: 5 -estimated_files: 16 -skills_used: [] ---- - -# T02: Strip all 16 lazy createRequire fallback paths from migrated callers - -**Slice:** S06 — Parser deprecation + cleanup -**Milestone:** M001 - -## Description - -Remove all `createRequire` imports, lazy parser singletons, and `else` fallback branches from the 16 files that were migrated to DB-primary in S04-S05. Each file currently has an `if (isDbAvailable()) { ...DB path... } else { ...parser fallback via createRequire... }` pattern. The `else` branches are dead code now that parsers are relocated to `parsers-legacy.ts` — the lazy singletons were importing from `files.ts` which no longer exports parsers. Replace each pattern with just the DB path, returning early/empty when DB is unavailable. - -## Steps - -1. **Strip hot-path callers (4 files):** - - `dispatch-guard.ts`: Remove `import { createRequire } from "node:module"` (line 4). Remove the `_lazyParser` variable and `lazyParseRoadmapSlices()` function (lines 10-23). In `getPriorSliceCompletionBlocker()`, remove the `else` branch that reads the roadmap file and calls `lazyParseRoadmapSlices()` — when `!isDbAvailable()`, return `null`. - - `auto-dispatch.ts`: Remove `import { createRequire } from "node:module"` (line 17). Remove `_lazyParseRoadmap` singleton (lines 19-29). At each of the 3 `if (isDbAvailable())` blocks (~lines 192, 532, 600), remove the `else` branch — when DB unavailable, skip/return empty. - - `auto-verification.ts`: Remove `import { createRequire } from "node:module"` (line 16). Remove the inline `createRequire` fallback block (~lines 71-83) — when DB unavailable, return early. - - `parallel-eligibility.ts`: Remove `import { createRequire } from "node:module"` (line 12). Remove the inline `createRequire` fallback block (~line 57+) — when DB unavailable, return empty eligibility. - -2. **Strip warm-path callers batch 1 (7 files):** - - `doctor.ts`: Remove `import { createRequire } from "node:module"` (line 19). Remove `_lazyParsers` singleton (~lines 21-28). At each `else` branch, skip/return empty. - - `doctor-checks.ts`: Remove `import { createRequire } from "node:module"` (line 23). Remove `_lazyParseRoadmap` singleton (~lines 25-32). At each `else` branch, skip/return empty. - - `visualizer-data.ts`: Remove `import { createRequire } from 'node:module'` (line 41). Remove `_lazyParsers` singleton (~lines 43-50). At `else` branches, return empty data. - - `workspace-index.ts`: Remove `import { createRequire } from "node:module"` (line 19). Remove `_lazyParsers` singleton (~lines 21-28). The `titleFromRoadmapHeader` function at line 80 uses parser-only path with no DB equivalent — make it return `null` when DB unavailable (the caller already handles null). - - `dashboard-overlay.ts`: Remove `import { createRequire } from "node:module"` (line 31). Remove `_lazyParsers` singleton (~lines 33-40). At `else` branches, return empty/skip. - - `auto-dashboard.ts`: Remove `import { createRequire } from "node:module"` (line 30). Remove `_lazyParsers` singleton (~lines 32-39). At `else` branches, return empty/skip. - - `guided-flow.ts`: Remove `import { createRequire } from "node:module"` (line 43). Remove `_lazyParseRoadmap` singleton (~lines 45-52). At `else` branches, return empty. - -3. **Strip warm-path callers batch 2 (5 files):** - - `auto-prompts.ts`: Remove both `lazyParseRoadmap()` and `lazyParsePlan()` async helper functions (~lines 32-49). At each of the 6 call sites, replace `lazyParseRoadmap()`/`lazyParsePlan()` calls with just the DB path. When DB unavailable, use empty arrays/null. - - `auto-recovery.ts`: Remove `import { createRequire } from "node:module"` (line 13). Remove both inline `createRequire` fallback blocks (~lines 378-385, ~lines 424-430). Keep the DB path only. - - `auto-direct-dispatch.ts`: Remove both inline `createRequire` + fallback blocks (~lines 164-173, ~lines 199-208). These are `await import("node:module")` style — remove the entire `else` blocks. - - `auto-worktree.ts`: Remove `import { createRequire } from "node:module"` (line 21). Remove the `createRequire` fallback at ~line 1009. Keep DB path. - - `reactive-graph.ts`: Remove the `createRequire` + fallback block (~lines 208-215). Keep DB path. - -4. **Verify: no `createRequire` references remain in any of the 16 files** using the grep commands. - -5. **Run the full test suite** to confirm no regressions — doctor.test.ts, auto-dashboard.test.ts, auto-recovery.test.ts, derive-state-db.test.ts, derive-state-crossval.test.ts, gsd-recover.test.ts, flag-file-db.test.ts, plus the parser/crossval/renderer tests from T01. - -## Must-Haves - -- [ ] Zero `createRequire` references in any of the 16 migrated caller files -- [ ] Zero `parseRoadmap`/`parsePlan`/`parseRoadmapSlices` references in the 4 hot-path files -- [ ] Each `if (isDbAvailable())` pattern simplified to DB-only with early return/skip when unavailable -- [ ] `auto-prompts.ts` `lazyParseRoadmap`/`lazyParsePlan` helper functions removed -- [ ] `workspace-index.ts` `titleFromRoadmapHeader` gracefully returns null when DB unavailable -- [ ] All test suites pass - -## Verification - -```bash -# Zero parser refs in hot-path -grep -rn 'parseRoadmap\|parsePlan\|parseRoadmapSlices' \ - src/resources/extensions/gsd/dispatch-guard.ts \ - src/resources/extensions/gsd/auto-dispatch.ts \ - src/resources/extensions/gsd/auto-verification.ts \ - src/resources/extensions/gsd/parallel-eligibility.ts -# Exit code 1 (no matches) - -# Zero createRequire in all 16 callers -grep -rn 'createRequire' \ - src/resources/extensions/gsd/dispatch-guard.ts \ - src/resources/extensions/gsd/auto-dispatch.ts \ - src/resources/extensions/gsd/auto-verification.ts \ - src/resources/extensions/gsd/parallel-eligibility.ts \ - src/resources/extensions/gsd/doctor.ts \ - src/resources/extensions/gsd/doctor-checks.ts \ - src/resources/extensions/gsd/visualizer-data.ts \ - src/resources/extensions/gsd/workspace-index.ts \ - src/resources/extensions/gsd/dashboard-overlay.ts \ - src/resources/extensions/gsd/auto-dashboard.ts \ - src/resources/extensions/gsd/guided-flow.ts \ - src/resources/extensions/gsd/auto-prompts.ts \ - src/resources/extensions/gsd/auto-recovery.ts \ - src/resources/extensions/gsd/auto-direct-dispatch.ts \ - src/resources/extensions/gsd/auto-worktree.ts \ - src/resources/extensions/gsd/reactive-graph.ts -# Exit code 1 (no matches) - -# Parser only in allowed files -grep -rn 'parseRoadmap\|parsePlan\|parseRoadmapSlices' src/resources/extensions/gsd/*.ts \ - | grep -v '/tests/' | grep -v 'parsers-legacy' | grep -v 'md-importer' \ - | grep -v 'debug-logger' | grep -v 'native-parser-bridge' \ - | grep -v 'state.ts' | grep -v 'commands-maintenance' | grep -v 'markdown-renderer' -# Exit code 1 (no matches) - -# Full test suite -node --import ./src/resources/extensions/gsd/tests/resolve-ts.mjs --experimental-strip-types --test \ - src/resources/extensions/gsd/tests/parsers.test.ts \ - src/resources/extensions/gsd/tests/roadmap-slices.test.ts \ - src/resources/extensions/gsd/tests/planning-crossval.test.ts \ - src/resources/extensions/gsd/tests/markdown-renderer.test.ts \ - src/resources/extensions/gsd/tests/doctor.test.ts \ - src/resources/extensions/gsd/tests/auto-dashboard.test.ts \ - src/resources/extensions/gsd/tests/auto-recovery.test.ts \ - src/resources/extensions/gsd/tests/derive-state-db.test.ts \ - src/resources/extensions/gsd/tests/derive-state-crossval.test.ts \ - src/resources/extensions/gsd/tests/gsd-recover.test.ts \ - src/resources/extensions/gsd/tests/flag-file-db.test.ts -``` - -## Inputs - -- `src/resources/extensions/gsd/parsers-legacy.ts` — T01 output: parser functions now live here (confirms files.ts no longer exports them, so fallback singletons are dead code) -- `src/resources/extensions/gsd/dispatch-guard.ts` — has `_lazyParser`/`lazyParseRoadmapSlices()` at lines 4,10-23,88 -- `src/resources/extensions/gsd/auto-dispatch.ts` — has `_lazyParseRoadmap` at lines 17,19-29; 3 `if/else` blocks at ~192,532,600 -- `src/resources/extensions/gsd/auto-verification.ts` — has inline createRequire at lines 16,74 -- `src/resources/extensions/gsd/parallel-eligibility.ts` — has inline createRequire at lines 12,57 -- `src/resources/extensions/gsd/doctor.ts` — has `_lazyParsers` at lines 19,23 -- `src/resources/extensions/gsd/doctor-checks.ts` — has `_lazyParseRoadmap` at lines 23,27 -- `src/resources/extensions/gsd/visualizer-data.ts` — has `_lazyParsers` at lines 41,45 -- `src/resources/extensions/gsd/workspace-index.ts` — has `_lazyParsers` at lines 19,23; `titleFromRoadmapHeader` at line 80 -- `src/resources/extensions/gsd/dashboard-overlay.ts` — has `_lazyParsers` at lines 31,35 -- `src/resources/extensions/gsd/auto-dashboard.ts` — has `_lazyParsers` at lines 30,34 -- `src/resources/extensions/gsd/guided-flow.ts` — has `_lazyParseRoadmap` at lines 43,47 -- `src/resources/extensions/gsd/auto-prompts.ts` — has async `lazyParseRoadmap`/`lazyParsePlan` at lines 32-49; 6 call sites -- `src/resources/extensions/gsd/auto-recovery.ts` — has `createRequire` at line 13; inline fallbacks at ~380,426 -- `src/resources/extensions/gsd/auto-direct-dispatch.ts` — has inline `createRequire` at ~166-167,201-202 -- `src/resources/extensions/gsd/auto-worktree.ts` — has `createRequire` at line 21; fallback at ~1009 -- `src/resources/extensions/gsd/reactive-graph.ts` — has inline `createRequire` at ~210-211 - -## Expected Output - -- `src/resources/extensions/gsd/dispatch-guard.ts` — lazy parser + createRequire removed, DB-only path -- `src/resources/extensions/gsd/auto-dispatch.ts` — lazy parser + createRequire removed, DB-only path -- `src/resources/extensions/gsd/auto-verification.ts` — createRequire fallback removed, DB-only path -- `src/resources/extensions/gsd/parallel-eligibility.ts` — createRequire fallback removed, DB-only path -- `src/resources/extensions/gsd/doctor.ts` — lazy parsers + createRequire removed, DB-only path -- `src/resources/extensions/gsd/doctor-checks.ts` — lazy parser + createRequire removed, DB-only path -- `src/resources/extensions/gsd/visualizer-data.ts` — lazy parsers + createRequire removed, DB-only path -- `src/resources/extensions/gsd/workspace-index.ts` — lazy parsers + createRequire removed, titleFromRoadmapHeader returns null when no DB -- `src/resources/extensions/gsd/dashboard-overlay.ts` — lazy parsers + createRequire removed, DB-only path -- `src/resources/extensions/gsd/auto-dashboard.ts` — lazy parsers + createRequire removed, DB-only path -- `src/resources/extensions/gsd/guided-flow.ts` — lazy parser + createRequire removed, DB-only path -- `src/resources/extensions/gsd/auto-prompts.ts` — async lazy helpers removed, DB-only paths at all 6 call sites -- `src/resources/extensions/gsd/auto-recovery.ts` — createRequire + fallbacks removed, DB-only path -- `src/resources/extensions/gsd/auto-direct-dispatch.ts` — createRequire + fallbacks removed, DB-only path -- `src/resources/extensions/gsd/auto-worktree.ts` — createRequire + fallback removed, DB-only path -- `src/resources/extensions/gsd/reactive-graph.ts` — createRequire + fallback removed, DB-only path diff --git a/src/resources/extensions/gsd/tools/plan-task.ts b/src/resources/extensions/gsd/tools/plan-task.ts index bd57dd500..94826b4c3 100644 --- a/src/resources/extensions/gsd/tools/plan-task.ts +++ b/src/resources/extensions/gsd/tools/plan-task.ts @@ -1,5 +1,5 @@ import { clearParseCache } from "../files.js"; -import { getSlice, getTask, insertTask, upsertTaskPlanning } from "../gsd-db.js"; +import { transaction, getSlice, getTask, insertTask, upsertTaskPlanning } from "../gsd-db.js"; import { invalidateStateCache } from "../state.js"; import { renderTaskPlanFromDb } from "../markdown-renderer.js"; @@ -75,24 +75,26 @@ export async function handlePlanTask( } try { - if (!getTask(params.milestoneId, params.sliceId, params.taskId)) { - insertTask({ - id: params.taskId, - sliceId: params.sliceId, - milestoneId: params.milestoneId, + transaction(() => { + if (!getTask(params.milestoneId, params.sliceId, params.taskId)) { + insertTask({ + id: params.taskId, + sliceId: params.sliceId, + milestoneId: params.milestoneId, + title: params.title, + status: "pending", + }); + } + upsertTaskPlanning(params.milestoneId, params.sliceId, params.taskId, { title: params.title, - status: "pending", + description: params.description, + estimate: params.estimate, + files: params.files, + verify: params.verify, + inputs: params.inputs, + expectedOutput: params.expectedOutput, + observabilityImpact: params.observabilityImpact ?? "", }); - } - upsertTaskPlanning(params.milestoneId, params.sliceId, params.taskId, { - title: params.title, - description: params.description, - estimate: params.estimate, - files: params.files, - verify: params.verify, - inputs: params.inputs, - expectedOutput: params.expectedOutput, - observabilityImpact: params.observabilityImpact ?? "", }); } catch (err) { return { error: `db write failed: ${(err as Error).message}` };