mirror of https://github.com/garrytan/gstack.git
feat(test): validate touchfile dependency paths exist on disk
New guard in touchfiles.test.ts: every non-glob dep path must exist, and every glob's anchor directory must exist. This is the axis the 181-key two-map sync discipline never covered — an entry can point at a long-deleted file and diff-based selection then silently never triggers those tests (the sidebar trio sat rotted for 48 versions). First run immediately caught a fourth rotted entry: 'spec authored quality' referenced test/fixtures/spec/** (directory does not exist) and selected for a judge test that exists nowhere in the repo. Removed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
17a522ed55
commit
a646a32b41
|
|
@ -775,7 +775,6 @@ export const LLM_JUDGE_TOUCHFILES: Record<string, string[]> = {
|
|||
'plan-eng-review/SKILL.md sections': ['plan-eng-review/SKILL.md', 'plan-eng-review/SKILL.md.tmpl'],
|
||||
|
||||
// /spec authored-spec quality (paid LLM-judge — periodic-tier).
|
||||
'spec authored quality': ['spec/SKILL.md', 'spec/SKILL.md.tmpl', 'test/fixtures/spec/**'],
|
||||
'plan-design-review/SKILL.md passes': ['plan-design-review/SKILL.md', 'plan-design-review/SKILL.md.tmpl'],
|
||||
|
||||
// Design skills
|
||||
|
|
|
|||
|
|
@ -330,3 +330,57 @@ describe('TOUCHFILES completeness', () => {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
// --- dependency paths exist on disk ---
|
||||
//
|
||||
// The axis nobody guarded: a dep-list entry can point at a file that was
|
||||
// deleted long ago (browse/src/sidebar-agent.ts sat in three entries for 48
|
||||
// versions), and diff-based selection then silently never triggers those
|
||||
// tests. Globs are skipped (they describe patterns, not files); every literal
|
||||
// path must exist.
|
||||
|
||||
describe('touchfile dependency paths exist', () => {
|
||||
const allEntries: Array<[string, string]> = [];
|
||||
for (const [name, deps] of Object.entries(E2E_TOUCHFILES)) {
|
||||
for (const dep of deps) allEntries.push([name, dep]);
|
||||
}
|
||||
for (const [name, deps] of Object.entries(LLM_JUDGE_TOUCHFILES)) {
|
||||
for (const dep of deps) allEntries.push([name, dep]);
|
||||
}
|
||||
for (const dep of GLOBAL_TOUCHFILES) allEntries.push(['(global)', dep]);
|
||||
|
||||
test('every non-glob dependency path exists', () => {
|
||||
const stale = allEntries
|
||||
.filter(([, dep]) => !dep.includes('*'))
|
||||
.filter(([, dep]) => !fs.existsSync(path.join(ROOT, dep)));
|
||||
if (stale.length > 0) {
|
||||
throw new Error(
|
||||
`Touchfile dep lists reference files that do not exist:\n` +
|
||||
stale.map(([name, dep]) => ` ${name} -> ${dep}`).join('\n') +
|
||||
`\nDelete or update these entries in test/helpers/touchfiles.ts — ` +
|
||||
`diff-based selection silently skips tests whose deps are gone.`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test('every glob dependency anchors to a directory that exists', () => {
|
||||
// Cheap sanity for globs, two shapes: 'dir/**' (prefix ends with '/')
|
||||
// must have the directory itself; 'dir/file-prefix*.ext' must have the
|
||||
// containing directory. Catches 'deleted-dir/**' rot without a full
|
||||
// filesystem walk; deliberately does not chase file-prefix staleness.
|
||||
const stale = allEntries
|
||||
.filter(([, dep]) => dep.includes('*'))
|
||||
.map(([name, dep]) => {
|
||||
const prefix = dep.split('*')[0];
|
||||
const anchor = prefix.endsWith('/') ? prefix.slice(0, -1) : path.dirname(prefix);
|
||||
return [name, dep, anchor] as const;
|
||||
})
|
||||
.filter(([, , anchor]) => anchor.length > 0 && anchor !== '.' && !fs.existsSync(path.join(ROOT, anchor)));
|
||||
if (stale.length > 0) {
|
||||
throw new Error(
|
||||
`Touchfile glob deps whose anchor directory does not exist:\n` +
|
||||
stale.map(([name, dep]) => ` ${name} -> ${dep}`).join('\n'),
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue