From 62f5f3b39eb01a78ddaf7eea224510895474c322 Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Tue, 11 Aug 2026 20:06:23 -0400 Subject: [PATCH] fix(#3224): register WINDOWS.md as a canonical .planning/ artifact (#3369) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test(#3224): assert WINDOWS.md is a canonical .planning/ artifact The broken-windows ledger (.planning/WINDOWS.md, written by gsd-core's own windows command) was absent from CANONICAL_EXACT, so validate health flagged it W019 'Unrecognized' with advice to delete a file that can gate /gsd-ship. Add WINDOWS.md to the expected-canonical list + a dedicated predicate test. RED — fails on next; fix follows. * fix(#3224): register WINDOWS.md as a canonical .planning/ artifact CANONICAL_EXACT (src/artifacts.cts) was never updated when the broken-windows capability (#1950/#2441) started writing .planning/WINDOWS.md. validate health therefore flagged the ledger W019 'Unrecognized' with fix advice to archive or delete it — a file gsd-core itself produces (src/broken-windows.cts, LEDGER_FILE_NAME) and that can gate /gsd-ship under workflow.windows_enforce. Add WINDOWS.md to CANONICAL_EXACT, per the registry header's own maintenance mandate ('Add entries here whenever a new workflow produces a .planning/ root file'). isCanonicalPlanningFile now returns true for it, suppressing the false W019. Existing W019 behavior for genuinely-unrecognized files is unchanged. * chore(#3224): add changeset fragment * chore(#3224): backfill changeset PR number (#3369) --------- Co-authored-by: sim --- .changeset/calm-fern-meadow.md | 5 +++++ src/artifacts.cts | 1 + tests/artifacts.test.cjs | 11 ++++++++++- 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 .changeset/calm-fern-meadow.md diff --git a/.changeset/calm-fern-meadow.md b/.changeset/calm-fern-meadow.md new file mode 100644 index 000000000..8ecf68612 --- /dev/null +++ b/.changeset/calm-fern-meadow.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 3369 +--- +**`gsd-tools validate health` no longer flags `.planning/WINDOWS.md` as an unrecognized file** — the broken-windows ledger that gsd-core's own `windows` command writes is now registered as a canonical `.planning/` artifact. Previously the W019 warning advised archiving or deleting a file that, with `workflow.windows_enforce` on, gates `/gsd-ship`. (#3224) diff --git a/src/artifacts.cts b/src/artifacts.cts index 7beea9853..2f2007b2e 100644 --- a/src/artifacts.cts +++ b/src/artifacts.cts @@ -24,6 +24,7 @@ export const CANONICAL_EXACT: ReadonlySet = new Set([ 'config.json', 'CLAUDE.md', 'RETROSPECTIVE.md', + 'WINDOWS.md', // #3224: broken-windows ledger (src/broken-windows.cts, LEDGER_FILE_NAME) ]); // Pattern-match canonical file names (regex tests on the basename) diff --git a/tests/artifacts.test.cjs b/tests/artifacts.test.cjs index 1fcae98e2..4f048e3ad 100644 --- a/tests/artifacts.test.cjs +++ b/tests/artifacts.test.cjs @@ -23,7 +23,7 @@ describe('CANONICAL_EXACT', () => { const expected = [ 'PROJECT.md', 'ROADMAP.md', 'STATE.md', 'REQUIREMENTS.md', 'MILESTONES.md', 'BACKLOG.md', 'LEARNINGS.md', 'THREADS.md', - 'config.json', 'CLAUDE.md', 'RETROSPECTIVE.md', + 'config.json', 'CLAUDE.md', 'RETROSPECTIVE.md', 'WINDOWS.md', ]; for (const name of expected) { assert.ok(CANONICAL_EXACT.has(name), `expected ${name} in CANONICAL_EXACT`); @@ -58,6 +58,15 @@ describe('isCanonicalPlanningFile', () => { assert.strictEqual(isCanonicalPlanningFile('config.json'), true); }); + test('#3224: WINDOWS.md (broken-windows ledger) is a canonical .planning/ artifact', () => { + // gsd-core itself writes .planning/WINDOWS.md (src/broken-windows.cts, + // LEDGER_FILE_NAME = 'WINDOWS.md'). Before #3224 it was absent from the + // registry, so validate health flagged it W019 "Unrecognized" with advice to + // delete a ledger that can gate /gsd-ship under workflow.windows_enforce. + assert.ok(CANONICAL_EXACT.has('WINDOWS.md'), 'WINDOWS.md must be in CANONICAL_EXACT'); + assert.strictEqual(isCanonicalPlanningFile('WINDOWS.md'), true); + }); + test('returns false for unrecognized file', () => { assert.strictEqual(isCanonicalPlanningFile('random-file.md'), false); });