From 3687e87c7562ce4c49c8a04512732ab5834e3bfb Mon Sep 17 00:00:00 2001 From: Simon Axelsson Date: Wed, 16 Sep 2026 15:36:43 +0200 Subject: [PATCH] ci: add canonical architecture policy validator --- scripts/validate-canonical-architecture.mjs | 50 +++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 scripts/validate-canonical-architecture.mjs diff --git a/scripts/validate-canonical-architecture.mjs b/scripts/validate-canonical-architecture.mjs new file mode 100644 index 0000000..e3febc3 --- /dev/null +++ b/scripts/validate-canonical-architecture.mjs @@ -0,0 +1,50 @@ +import { readFile, access } from "node:fs/promises"; + +const requiredFiles = [ + "docs/MASTERPLAN.md", + "docs/STANDARDS.md", + "docs/AUTOMATIONS.md", + "docs/UPSTREAM-CAPABILITY-MATRIX.md", + "docs/spec/DIGITAL-TWIN-SPEC.md", + "packages/types/src/index.ts", +]; + +for (const path of requiredFiles) { + await access(path).catch(() => { + throw new Error(`Missing canonical C0PY artifact: ${path}`); + }); +} + +const types = await readFile("packages/types/src/index.ts", "utf8"); +const requiredContracts = [ + "CapabilityDisposition", + "EvidenceConfidence", + "EvidenceRecord", + "CaptureProfile", + "ProductWorkflow", + "FidelityVector", + "ReconstructionSpec", +]; + +for (const contract of requiredContracts) { + if (!types.includes(` ${contract}`)) { + throw new Error(`Missing canonical contract: ${contract}`); + } +} + +const masterplan = await readFile("docs/MASTERPLAN.md", "utf8"); +for (const disposition of [ + "CORE", + "DEPENDENCY", + "CHERRY_PICK", + "ADAPTER", + "REIMPLEMENT", + "REFERENCE_ONLY", + "DROP", +]) { + if (!masterplan.includes(`\`${disposition}\``)) { + throw new Error(`Masterplan is missing capability disposition: ${disposition}`); + } +} + +console.log("C0PY canonical architecture policy: OK");