feat(health): canonical artifact registry and W019 unrecognized-file lint (#2448) (#2488)

Adds artifacts.cjs with canonical .planning/ root file names, W019 warning
in gsd-health that flags unrecognized .md files at the .planning/ root, and
templates/README.md as the authoritative artifact index for agents and humans.

Closes #2448
This commit is contained in:
Tom Boucher
2026-04-20 18:21:23 -04:00
committed by GitHub
parent f19d0327b2
commit cfe4dc76fd
7 changed files with 275 additions and 1 deletions

View File

@@ -0,0 +1,52 @@
/**
* Canonical GSD artifact registry.
*
* Enumerates the file names that gsd workflows officially produce at the
* .planning/ root level. Used by gsd-health (W019) to flag unrecognized files
* so stale or misnamed artifacts don't silently mislead agents or reviewers.
*
* Add entries here whenever a new workflow produces a .planning/ root file.
*/
'use strict';
// Exact-match canonical file names at .planning/ root
const CANONICAL_EXACT = new Set([
'PROJECT.md',
'ROADMAP.md',
'STATE.md',
'REQUIREMENTS.md',
'MILESTONES.md',
'BACKLOG.md',
'LEARNINGS.md',
'THREADS.md',
'config.json',
'CLAUDE.md',
]);
// Pattern-match canonical file names (regex tests on the basename)
// Each pattern includes the name of the workflow that produces it as a comment.
const CANONICAL_PATTERNS = [
/^v\d+\.\d+(?:\.\d+)?-MILESTONE-AUDIT\.md$/i, // gsd-complete-milestone (pre-archive)
/^v\d+\.\d+(?:\.\d+)?-.*\.md$/i, // other version-stamped planning docs
];
/**
* Return true if `filename` (basename only, no path) matches a canonical
* .planning/ root artifact — either an exact name or a known pattern.
*
* @param {string} filename - Basename of the file (e.g. "STATE.md")
*/
function isCanonicalPlanningFile(filename) {
if (CANONICAL_EXACT.has(filename)) return true;
for (const pattern of CANONICAL_PATTERNS) {
if (pattern.test(filename)) return true;
}
return false;
}
module.exports = {
CANONICAL_EXACT,
CANONICAL_PATTERNS,
isCanonicalPlanningFile,
};

View File

@@ -903,6 +903,22 @@ function cmdValidateHealth(cwd, options, raw) {
}
} catch { /* intentionally empty — milestone sync check is advisory */ }
// ─── Check 13: Unrecognized .planning/ root files (W019) ──────────────────
try {
const { isCanonicalPlanningFile } = require('./artifacts.cjs');
const entries = fs.readdirSync(planBase, { withFileTypes: true });
for (const entry of entries) {
if (!entry.isFile()) continue;
if (!entry.name.endsWith('.md')) continue;
if (!isCanonicalPlanningFile(entry.name)) {
addIssue('warning', 'W019',
`Unrecognized .planning/ file: ${entry.name} — not a canonical GSD artifact`,
'Move to .planning/milestones/ archive subdir or delete if stale. See templates/README.md for the canonical artifact list.',
false);
}
}
} catch { /* artifact check is advisory — skip on error */ }
// ─── Perform repairs if requested ─────────────────────────────────────────
const repairActions = [];
if (options.repair && repairs.length > 0) {