sourceFiles walks assets/: a stylesheet there may be the one reference to a plate

Greptile P1 on #599: unreferencedPlates read a plate referenced only from assets/hero.css as unused and the hero gate refused a valid build. The extension filter already keeps binaries out of the walk.

AI-assisted (Claude Code).
This commit is contained in:
Paul Bakaus
2026-08-28 15:04:57 -07:00
parent 3818a5655b
commit 09ddc1758e
2 changed files with 22 additions and 1 deletions
+4 -1
View File
@@ -318,7 +318,10 @@ export function gatePlates(state, { specPath = SPEC_PATH } = {}) {
/** Source files that could reference a plate: bounded walk, skipping deps and build output. */
function sourceFiles(root = '.', limit = 400) {
const out = [];
const skip = new Set(['node_modules', '.git', 'dist', 'build', 'out', '.next', '.svelte-kit', '.impeccable', 'assets', 'coverage']);
// `assets` is walked: the extension filter already keeps binaries out, and
// a stylesheet at assets/hero.css may be the one file that references a
// plate (Greptile P1 on #599: the gate refused a valid build for it).
const skip = new Set(['node_modules', '.git', 'dist', 'build', 'out', '.next', '.svelte-kit', '.impeccable', 'coverage']);
const exts = /\.(html?|css|scss|jsx?|tsx?|svelte|vue|astro|mdx?|php|erb|hbs)$/i;
const walk = (dir, depth) => {
if (out.length >= limit || depth > 6) return;
+18
View File
@@ -462,3 +462,21 @@ describe('build-phase state machine (CLI)', () => {
assert.equal(run(PHASE_SCRIPT, ['dance'], dir).status, 1);
});
});
describe('unreferencedPlates', () => {
it('finds a plate referenced only from a stylesheet under assets/', async () => {
const { unreferencedPlates } = await import('../skill/scripts/build-phase.mjs');
const d = fs.mkdtempSync(path.join(os.tmpdir(), 'unref-'));
const prev = process.cwd();
try {
process.chdir(d);
fs.mkdirSync(path.join(d, 'assets', 'plates'), { recursive: true });
fs.writeFileSync(path.join(d, 'assets', 'plates', 'hero-plate.png'), 'x');
fs.writeFileSync(path.join(d, 'assets', 'hero.css'), ".hero { background-image: url('./plates/hero-plate.png'); }");
const spec = { regions: [{ id: 'hero-art', medium: 'raster', plate: 'assets/plates/hero-plate.png' }] };
assert.deepEqual(unreferencedPlates(spec, null), [], 'the stylesheet under assets counts as a reference');
fs.writeFileSync(path.join(d, 'assets', 'hero.css'), '.hero { background: red; }');
assert.equal(unreferencedPlates(spec, null).length, 1, 'an unreferenced plate is still named');
} finally { process.chdir(prev); fs.rmSync(d, { recursive: true, force: true }); }
});
});