/*
Autonomy guard for the Werkstatt engine (RFC-0772). Scans packages/werkstatt/src/**
for @warpgogol/* import specifiers that indicate stack-plugin coupling. Excludes
self-imports (@warpgogol/werkstatt-engine) and shared infrastructure packages (@warpgogol/werkstatt-shared/*)
which are not stack plugins.
- Do not scan test files — tests may import from any package.
- Do not scan node_modules — only engine source is checked.
- Do not block on @warpgogol/werkstatt-shared/* — these are shared infrastructure packages.
- RFC-0772: initial autonomy guard implementation modeled on forge.doctor precedent.
- RFC-0868: refactor to use shared import-scan-util.ts, removing duplicated scanning logic.
- RFC-1097: step 6 — compass.migrate codemod run
Mechanical v1 to v2 header migration across the workspace: 942 files rewritten — CHANGE_SUMMARY windows collapsed into history, forbidden v1 blocks stripped, KEY_DECISIONS seeded from @ai-invariant comments (5 files) or TODO placeholders (103 files), blocks reordered to canonical order.
- RFC-1097: sweep — werkstatt-engine clean
Sweep batch 4: 73 Compass headers on headerless engine files (certification, component-runtime, isolation, evolution, testing), real KEY_DECISIONS on 75 files (kernel, cache, dht, swim, gitmesh, runtime), ~80 purpose expansions (CONTRACT-02/PURPOSE-02), non-goals on 13 CONTRACT-03 files, CS-07 history literal fix repo-wide (253 files). Policy: .template.ts/.template.astro excludedPaths. werkstatt-engine now 0 diagnostics.
- RFC-1248: VITE-CLIENT-DEP-02 lazy-import gate + SCAN-02 validator reads-root existence check (RFC-1248)
*/
import { join } from "node:path";
import { scanDirectoryForImports } from "./import-scan-util.ts";
/**
* Packages that are exempt from the autonomy guard.
* - @warpgogol/werkstatt-engine: self-imports (engine importing its own subpaths)
* - @warpgogol/werkstatt-shared: shared infrastructure package (not a stack plugin)
* - @warpgogol/forge: governance package (not a stack plugin)
*
* Stack-specific packages that SHOULD be flagged (not exempt):
* - @warpgogol/werkstatt-site (stack plugin — engine MUST NOT import)
*
* RFC-0868 extracted shared infrastructure into @warpgogol/werkstatt-shared.
* The engine now imports from @warpgogol/werkstatt-shared/* for shared schemas
* and through plugin hooks for stack logic.
*/
const EXEMPT_PREFIXES = [
"@warpgogol/werkstatt-engine",
"@warpgogol/werkstatt-shared",
"@warpgogol/forge",
];
export interface AutonomyViolation {
file: string;
specifier: string;
}
export interface AutonomyValidateResult {
command: string;
status: "pass" | "fail";
violations: AutonomyViolation[];
scannedFiles: number;
}
/**
* Check if a specifier is exempt (self-import or shared schema package).
*/
function isExempt(specifier: string): boolean {
return EXEMPT_PREFIXES.some(
(prefix) => specifier === prefix || specifier.startsWith(prefix + "/"),
);
}
/**
* Run the autonomy validation. Scans packages/werkstatt/src/** for forbidden
* @warpgogol/* imports (excluding self-imports and shared schema packages).
*/
export async function runAutonomyValidate(workspaceRoot: string): Promise {
const engineSrcDir = join(workspaceRoot, "packages", "werkstatt-engine", "src");
const { violations, scannedFiles } = await scanDirectoryForImports(
engineSrcDir,
workspaceRoot,
(specifier) => specifier.startsWith("@warpgogol/") && !isExempt(specifier),
);
return {
command: "werkstatt.autonomy.validate",
status: violations.length === 0 ? "pass" : "fail",
violations,
scannedFiles,
};
}