Skip to content

Commit 4c84e79

Browse files
committed
improvement(audits): share rule frontmatter parsing and fail on dead graph guards
check:guidance-refs reuses sync-skills' parseRule, reads workspace manifests once from the root workspaces globs, and matches rule globs against one git listing instead of a filesystem scan per glob (~2.5s to ~0.2s). Markdown links now go through the shared path check. check:application-graph fails when a forbidden prefix matches nothing under apps/sim.
1 parent ddec531 commit 4c84e79

3 files changed

Lines changed: 135 additions & 150 deletions

File tree

‎scripts/check-application-graph.ts‎

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@
6868
* path and one on a once-a-month webhook read identically, which is why the
6969
* deferred check stops at the edge's own target rather than walking past it.
7070
*/
71-
import { existsSync, readFileSync, statSync } from 'node:fs'
72-
import { dirname, relative, resolve } from 'node:path'
71+
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'
72+
import { basename, dirname, relative, resolve } from 'node:path'
7373
import { fileURLToPath } from 'node:url'
7474

7575
const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url))
@@ -283,7 +283,28 @@ export function findViolations({ root, forbidden }: GuardedRoot): GraphViolation
283283
return violations
284284
}
285285

286+
/**
287+
* Whether any path under `apps/sim` starts with `prefix`. A prefix that matches nothing guards
288+
* nothing: the tree was renamed, and the audit would keep passing over it.
289+
*/
290+
function prefixMatchesAnything(prefix: string): boolean {
291+
if (prefix.endsWith('/')) return existsSync(resolve(APP_ROOT, prefix))
292+
const dir = resolve(APP_ROOT, dirname(prefix))
293+
return existsSync(dir) && readdirSync(dir).some((entry) => entry.startsWith(basename(prefix)))
294+
}
295+
286296
function main(): void {
297+
const prefixes = new Set(GUARDED_ROOTS.flatMap((guarded) => Object.keys(guarded.forbidden)))
298+
const dead = [...prefixes].filter((prefix) => !prefixMatchesAnything(prefix))
299+
if (dead.length > 0) {
300+
console.error(
301+
`Application-graph audit forbids prefixes that match nothing under apps/sim: ${dead.join(', ')}\n` +
302+
'The tree was renamed or removed. Point the key at its current path rather than leaving a\n' +
303+
'guard that can never fire.\n'
304+
)
305+
process.exit(1)
306+
}
307+
287308
const violations: GraphViolation[] = []
288309
for (const guarded of GUARDED_ROOTS) {
289310
if (!existsSync(resolve(APP_ROOT, guarded.root))) {
@@ -310,10 +331,9 @@ function main(): void {
310331
process.exit(1)
311332
}
312333

313-
const trees = new Set(GUARDED_ROOTS.flatMap((guarded) => Object.keys(guarded.forbidden)))
314334
console.log(
315335
`✅ Application graph clean: ${GUARDED_ROOTS.length} roots reach none of ` +
316-
`${trees.size} forbidden module trees`
336+
`${prefixes.size} forbidden module trees`
317337
)
318338
}
319339

0 commit comments

Comments
 (0)