import { spawnSync } from "node:child_process"; import fs from "node:fs"; import path from "node:path"; const baseUrl = process.env.PROJECTBRAIN_SMOKE_URL ?? "http://127.0.0.1:5173"; const projectId = process.env.PROJECTBRAIN_SMOKE_PROJECT ?? "widefrog"; const shouldRunSmokes = process.argv.includes("--run-smokes") || process.env.PROJECTBRAIN_PROOF_RUN_SMOKES === "1"; const hasExplicitBaseUrl = Boolean(process.env.PROJECTBRAIN_SMOKE_URL); const shouldWriteReport = process.argv.includes("--write") || process.env.PROJECTBRAIN_PROOF_WRITE === "1"; const explicitOutputArg = process.argv.find((arg) => arg.startsWith("--out=")); const explicitOutputPath = explicitOutputArg?.slice("--out=".length) || process.env.PROJECTBRAIN_PROOF_OUT; const evidenceRows = [ { id: "RC63", label: "Release evidence lane click-through", script: "smoke:rc63-release-evidence-lane", proves: "Release evidence routes are reachable from the operator lane.", }, { id: "RC60", label: "Review decision receipt recovery", script: "smoke:rc60-review-decision-loop", proves: "Review decisions can be recovered and inspected from history.", }, { id: "RC73", label: "Release evidence capture assist", script: "smoke:rc73-release-evidence-capture-assist", proves: "Runtime evidence capture assists the operator instead of leaving proof manual-only.", }, { id: "RC88", label: "Release Center cockpit", script: "smoke:rc88-release-center", proves: "Release Center renders the cockpit, archives, quality and operator actions.", }, { id: "RC99", label: "Release checklist click-through", script: "smoke:rc99-release-checklist-clickthrough", proves: "Checklist links land on exact target sections and expose return paths.", }, ]; const run = (command, args, options = {}) => spawnSync(command, args, { encoding: "utf8", shell: process.platform === "win32", ...options, }); const readPackage = () => { const packageJson = JSON.parse(fs.readFileSync("package.json", "utf8")); return packageJson.scripts ?? {}; }; const getGitCommit = () => { const result = run("git", ["rev-parse", "--short", "HEAD"]); return result.status === 0 ? result.stdout.trim() : "unknown"; }; const createDefaultReportPath = (commit) => { const stamp = new Date().toISOString().replace(/[:.]/g, "-"); return `checkpoints/release-proof/projectbrain-release-proof-${commit}-${stamp}.md`; }; const checkLocalConfiguration = () => { const scripts = readPackage(); const missing = []; if (!scripts["smoke:release-operator"]) missing.push("smoke:release-operator"); if (!scripts["release:proof-report"]) missing.push("release:proof-report"); for (const row of evidenceRows) { if (!scripts[row.script]) missing.push(row.script); } return missing; }; const checkLiveHealth = async () => { try { const response = await fetch(`${baseUrl}/api/health`); const body = await response.text(); return { ok: response.ok, status: response.status, body: body.slice(0, 220), }; } catch (error) { return { ok: false, status: "unreachable", body: error instanceof Error ? error.message : String(error), }; } }; const runOperatorSmoke = () => { const result = run("pnpm", ["run", "smoke:release-operator"], { stdio: "inherit", env: process.env, }); return result.status === 0; }; const formatTable = (rows) => { const header = "| Gate | Smoke | Proof |\n| --- | --- | --- |"; const body = rows.map((row) => `| ${row.id} | \`${row.script}\` | ${row.proves} |`).join("\n"); return `${header}\n${body}`; }; const localMissing = checkLocalConfiguration(); let smokePassed = null; if (shouldRunSmokes) { console.log("Running release operator smoke suite before generating proof report...\n"); smokePassed = runOperatorSmoke(); } const liveHealth = await checkLiveHealth(); const gitCommit = getGitCommit(); const localConfigOk = localMissing.length === 0; const healthGateOk = liveHealth.ok || !hasExplicitBaseUrl; const verdict = localConfigOk && healthGateOk && (smokePassed !== false) ? (smokePassed === true ? "PASS" : "CONFIGURED - SMOKE NOT RUN") : "ATTENTION REQUIRED"; const reportPath = explicitOutputPath || createDefaultReportPath(gitCommit); const report = [ "# ProjectBrain Release Operator Proof Report", "", `Generated: ${new Date().toISOString()}`, `Commit: ${gitCommit}`, `Base URL: ${baseUrl}`, `Project: ${projectId}`, `Verdict: ${verdict}`, "", "## Live Health", "", `- Status: ${liveHealth.status}`, `- Result: ${liveHealth.ok ? "reachable" : hasExplicitBaseUrl ? "not reachable" : "not reachable in local default mode"}`, `- Body: ${liveHealth.body}`, "", "## Proof Coverage", "", formatTable(evidenceRows), "", "## Local Configuration", "", localConfigOk ? "- Required release smoke scripts are registered." : `- Missing scripts: ${localMissing.map((name) => `\`${name}\``).join(", ")}`, `- Smoke execution: ${smokePassed === true ? "passed" : smokePassed === false ? "failed" : "not run"}`, "", "## Operator Commands", "", "```bash", "pnpm run release:proof-report", "pnpm run release:proof-report -- --write", "PROJECTBRAIN_PROOF_RUN_SMOKES=1 pnpm run release:proof-report", "PROJECTBRAIN_PROOF_RUN_SMOKES=1 PROJECTBRAIN_PROOF_WRITE=1 pnpm run release:proof-report", "PROJECTBRAIN_SMOKE_URL=http://127.0.0.1:1209 pnpm run smoke:release-operator", "```", "", "## Remaining Manual Gates", "", "- Confirm the intended release commit/tag.", "- Confirm any environment-specific deployment notes.", "- Confirm operator signoff after the smoke suite is green.", ].join("\n"); console.log(report); if (shouldWriteReport) { fs.mkdirSync(path.dirname(reportPath), { recursive: true }); fs.writeFileSync(reportPath, `${report}\n`, "utf8"); console.log(`\nRelease proof report written to ${reportPath}`); } if (!localConfigOk || !healthGateOk || smokePassed === false) { process.exitCode = 1; }