From c11595cf22116e1018d99dbc8bfa5978c52ca75d Mon Sep 17 00:00:00 2001 From: Mikael Hugo Date: Sat, 2 May 2026 19:18:50 +0200 Subject: [PATCH] feat(sf): DB migration v22 adds is_sketch + sketch_scope columns (ADR-011) Mirrors gsd-2's slices schema for progressive planning. Three changes to sf-db.ts: 1. Fresh-install CREATE TABLE for slices (line 312) gains: - is_sketch INTEGER NOT NULL DEFAULT 0 -- 1 = awaiting refine - sketch_scope TEXT NOT NULL DEFAULT '' -- 2-3 sentence scope hint 2. Schema version 22 migration: ensureColumn for both fields so existing installs upgrade without data loss. Wrapped in the same currentVersion < N guard pattern as v6, v7, v8 ... v21. 3. rowToSlice() returns sketch_scope and is_sketch on the SliceRow so the dispatch rule from 0c78b0038 can read them via getSlice(). End-to-end verified: fresh DB has both columns at defaults; getSlice() returns is_sketch=0, sketch_scope='' on a freshly-inserted slice. Closes the DDL-migration gap from the progressive-planning rollout plan in fef2e4b6f. Remaining: plan-milestone tool needs to write is_sketch=1 + sketch_scope when emitting sketches; refine-slice tool needs to clear is_sketch=0 when persisting the full plan. Until those land, the dispatch rule still falls through (sketches never created). Co-Authored-By: Claude Opus 4.7 (1M context) --- src/resources/extensions/sf/sf-db.ts | 29 ++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/resources/extensions/sf/sf-db.ts b/src/resources/extensions/sf/sf-db.ts index 1c7fe8a9a..f5ee72d2b 100644 --- a/src/resources/extensions/sf/sf-db.ts +++ b/src/resources/extensions/sf/sf-db.ts @@ -332,6 +332,8 @@ function initSchema(db: DbAdapter, fileBacked: boolean): void { planning_meeting_json TEXT NOT NULL DEFAULT '', sequence INTEGER DEFAULT 0, -- Ordering hint: tools may set this to control execution order replan_triggered_at TEXT DEFAULT NULL, + is_sketch INTEGER NOT NULL DEFAULT 0, -- ADR-011: 1 = slice is a sketch awaiting refine-slice + sketch_scope TEXT NOT NULL DEFAULT '', -- ADR-011: 2-3 sentence scope hint from plan-milestone PRIMARY KEY (milestone_id, id), FOREIGN KEY (milestone_id) REFERENCES milestones(id) ) @@ -1396,6 +1398,31 @@ function migrateSchema(db: DbAdapter): void { }); } + if (currentVersion < 22) { + // ADR-011: progressive planning. is_sketch=1 means the slice is a 2-3 + // sentence sketch awaiting refine-slice expansion; refine fills in the + // real plan and clears the flag. sketch_scope holds the milestone + // planner's stored scope hint that refine treats as a hard boundary. + ensureColumn( + db, + "slices", + "is_sketch", + `ALTER TABLE slices ADD COLUMN is_sketch INTEGER NOT NULL DEFAULT 0`, + ); + ensureColumn( + db, + "slices", + "sketch_scope", + `ALTER TABLE slices ADD COLUMN sketch_scope TEXT NOT NULL DEFAULT ''`, + ); + db.prepare( + "INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)", + ).run({ + ":version": 22, + ":applied_at": new Date().toISOString(), + }); + } + db.exec("COMMIT"); } catch (err) { db.exec("ROLLBACK"); @@ -2355,6 +2382,8 @@ function rowToSlice(row: Record): SliceRow { planning_meeting: parsePlanningMeeting(row["planning_meeting_json"]), sequence: (row["sequence"] as number) ?? 0, replan_triggered_at: (row["replan_triggered_at"] as string) ?? null, + sketch_scope: (row["sketch_scope"] as string) ?? "", + is_sketch: (row["is_sketch"] as number) ?? 0, }; }