Lines 1-65javascript
2// The refusal demo (C7) — proves the gates REFUSE real violations, each named
3// and blocking, rather than merely asserting it in prose.
5// node qa/refusal-demo.mjs
7// Operates on a throwaway scaffolded app in a temp dir (never this template,
8// never the calling repo). For each of the four canonical violations
9// (docs/M4-ENFORCEMENT-DESIGN.md §B):
11// 1. inject the violation into the scaffold
12// 2. run the narrowest gate that should catch it
13// 3. assert the gate verdict is FAIL and the expected clause id appears in
15// 4. assert `qa/receipt-check.mjs` goes INVALID (violation blocks "done")
16// 5. `git checkout -- .` to revert before the next violation
18// Emits a summary table and exits non-zero if ANY assertion fails — i.e. if a
19// gate did NOT catch its violation. That is the actual finding this script
20// exists to surface; it must never be papered over.
22import { execFileSync, spawnSync } from "node:child_process";
23import fs from "node:fs";
HighChild Process
Package source references child process execution.
template/qa/refusal-demo.mjsView on unpkg · L21 24import os from "node:os";
25import path from "node:path";
26import { fileURLToPath } from "node:url";
28const TEMPLATE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
29const REPO_ROOT = path.resolve(TEMPLATE_ROOT, "..");
30// Scaffolding the throwaway app: inside the create-cmp dev tree the engine sits at
31// ../bin relative to the template — use it directly (fast, offline, tests the local
32// code). In a real generated repo that path doesn't exist, so fall back to the
33// published CLI via npx (needs network on first run).
34const LOCAL_ENGINE = path.join(REPO_ROOT, "bin", "create-cmp.mjs");
35const SCAFFOLD_CMD = fs.existsSync(LOCAL_ENGINE)
36 ? `node "${LOCAL_ENGINE}"`
37 : "npx --yes create-cmp-cli@latest";
38const GRADLEW = process.platform === "win32" ? "gradlew.bat" : "./gradlew";
HighRuntime Package Install
Package source invokes a package manager install command at runtime.
template/qa/refusal-demo.mjsView on unpkg · L21 41 process.stdout.write(`${msg}\n`);
44function sh(cmd, cwd, opts = {}) {
45 const res = spawnSync(cmd, {
49 maxBuffer: 64 * 1024 * 1024,
52 return { ok: res.status === 0 && !res.error, status: res.status, out: `${res.stdout ?? ""}${res.stderr ?? ""}` };
55function git(cwd, args) {
56 return execFileSync("git", args, { cwd, encoding: "utf8" }).trim();
59// ── Step 0: scaffold a throwaway app ────────────────────────────────────────
62 const tmpBase = fs.mkdtempSync(path.join(os.tmpdir(), "cmp-refusal-demo-"));
63 const projectDir = path.join(tmpBase, "RefusalDemo");
64 log(`Scaffolding a throwaway app at ${projectDir} (never touching ${TEMPLATE_ROOT})…`);