diff --git a/src/resources/extensions/gsd/gsd-db.ts b/src/resources/extensions/gsd/gsd-db.ts index fdb53492a..933b3d32e 100644 --- a/src/resources/extensions/gsd/gsd-db.ts +++ b/src/resources/extensions/gsd/gsd-db.ts @@ -1119,7 +1119,9 @@ export function insertMilestone(m: { ).run({ ":id": m.id, ":title": m.title ?? "", - ":status": m.status ?? "active", + // Default to "queued" — never auto-create milestones as "active" (#3380). + // Callers that need "active" must pass it explicitly. + ":status": m.status ?? "queued", ":depends_on": JSON.stringify(m.depends_on ?? []), ":created_at": new Date().toISOString(), ":vision": m.planning?.vision ?? "", diff --git a/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts b/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts new file mode 100644 index 000000000..97c12b4a3 --- /dev/null +++ b/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts @@ -0,0 +1,39 @@ +/** + * Regression test for #3695 — insertMilestone defaults status to "queued" + * + * Milestones were being auto-created with status "active", causing phantom + * milestones to appear as active work. The fix defaults to "queued" so + * new milestones must be explicitly activated. + */ + +import { describe, test } from 'node:test'; +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname, join } from 'node:path'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const dbSrc = readFileSync( + join(__dirname, '..', 'gsd-db.ts'), + 'utf-8', +); + +describe('insertMilestone defaults status to queued (#3695)', () => { + test('insertMilestone function exists', () => { + assert.match(dbSrc, /export function insertMilestone\(/, + 'insertMilestone should be exported from gsd-db.ts'); + }); + + test('default status is "queued" not "active"', () => { + // The status parameter should default to "queued" via nullish coalescing + assert.match(dbSrc, /m\.status\s*\?\?\s*"queued"/, + 'insertMilestone should default status to "queued"'); + }); + + test('comment explains the rationale', () => { + assert.match(dbSrc, /never auto-create milestones as "active"/i, + 'should have a comment explaining why default is queued'); + }); +});