109 lines
4.7 KiB
JavaScript
109 lines
4.7 KiB
JavaScript
import { spawnSync } from "node:child_process";
|
|
import { createHash } from "node:crypto";
|
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
import { resolve } from "node:path";
|
|
|
|
import { validateTddTrace } from "./lib/tdd-trace.mjs";
|
|
import { buildWp706PrefreezeReport, REQUIRED_UPSTREAM } from "./lib/wp7-06-prefreeze.mjs";
|
|
|
|
const runId = process.env.DADA_TDD_RUN_ID ?? `wp7-06-prefreeze-${new Date().toISOString().replace(/[^0-9]/g, "")}`;
|
|
const runDirectory = resolve("artifacts", "tdd", runId);
|
|
const caseDirectory = resolve(runDirectory, "cases", "TDD-WP7-AC-001-trace-structure");
|
|
if (existsSync(runDirectory)) throw new Error(`Evidence run already exists: ${runId}`);
|
|
mkdirSync(caseDirectory, { recursive: true });
|
|
|
|
function writeJson(path, value) {
|
|
writeFileSync(path, `${JSON.stringify(value, null, 2)}\n`);
|
|
}
|
|
|
|
function git(args) {
|
|
const result = spawnSync("git", args, { encoding: "utf8", timeout: 60_000 });
|
|
if ((result.status ?? 1) !== 0) throw new Error(`WP7_06_GIT_COMMAND_FAILED:${args[0]}`);
|
|
return result.stdout.trim();
|
|
}
|
|
|
|
function runCommand(name, command) {
|
|
const startedAt = new Date().toISOString();
|
|
const result = spawnSync(process.env.ComSpec ?? "cmd.exe", ["/d", "/s", "/c", command], {
|
|
encoding: "utf8",
|
|
env: process.env,
|
|
maxBuffer: 64 * 1024 * 1024,
|
|
});
|
|
if (result.stdout) process.stdout.write(result.stdout);
|
|
if (result.stderr) process.stderr.write(result.stderr);
|
|
return {
|
|
command,
|
|
exit_code: result.status ?? 1,
|
|
finished_at: new Date().toISOString(),
|
|
name,
|
|
started_at: startedAt,
|
|
};
|
|
}
|
|
|
|
const commands = [
|
|
runCommand("prefreeze-unit", "node --test tests/package/wp7-06-prefreeze.test.mjs"),
|
|
runCommand("tdd-trace", "pnpm validate:tdd-trace"),
|
|
];
|
|
if (commands.some((command) => command.exit_code !== 0)) {
|
|
writeJson(resolve(caseDirectory, "commands.json"), { commands, run_id: runId, schema_version: "1.0" });
|
|
process.exit(1);
|
|
}
|
|
|
|
const trace = validateTddTrace();
|
|
const currentCommit = git(["rev-parse", "HEAD"]);
|
|
const remoteLines = git(["ls-remote", "--heads", "origin", "codex/wp7-01", "codex/wp7-02", "codex/wp7-03", "codex/wp7-04", "codex/wp7-05"])
|
|
.split(/\r?\n/)
|
|
.filter(Boolean);
|
|
const remoteHeads = Object.fromEntries(remoteLines.map((line) => {
|
|
const [head, reference] = line.split(/\s+/);
|
|
return [reference.replace("refs/heads/", ""), head];
|
|
}));
|
|
const upstream = Object.fromEntries(Object.entries(REQUIRED_UPSTREAM).map(([taskId, status]) => {
|
|
const branch = taskId.replace("TASK-", "codex/").toLowerCase();
|
|
const head = remoteHeads[branch];
|
|
const ancestry = spawnSync("git", ["merge-base", "--is-ancestor", head ?? "missing", "HEAD"], { encoding: "utf8", timeout: 30_000 });
|
|
return [taskId, { branch, head, merged: ancestry.status === 0, status }];
|
|
}));
|
|
const report = buildWp706PrefreezeReport({
|
|
currentCommit,
|
|
releaseExists: existsSync(resolve("RELEASE.json")),
|
|
trace,
|
|
upstream,
|
|
});
|
|
|
|
const result = {
|
|
acceptance_criteria: Array.from({ length: 56 }, (_, index) => index + 1)
|
|
.filter((number) => ![8, 26, 37, 54].includes(number))
|
|
.map((number) => `AC-${String(number).padStart(2, "0")}`),
|
|
automation: ["automated", "manual_review"],
|
|
commit: currentCommit,
|
|
evidence_refs: ["commands.json", "trace-summary.json", "upstream-lineage.json", "deferred-external.json"],
|
|
finished_at: new Date().toISOString(),
|
|
manifest: {
|
|
path: "tasks.manifest.json",
|
|
sha256: createHash("sha256").update(readFileSync("tasks.manifest.json")).digest("hex").toUpperCase(),
|
|
},
|
|
missing_evidence: [],
|
|
release_gate: ["release:P0-A"],
|
|
requirements: ["NFR-05"],
|
|
run_id: runId,
|
|
schema_version: "1.0",
|
|
status: report.status,
|
|
task_id: "TASK-WP7-06",
|
|
test_id: "TDD-WP7-AC-001-trace-structure",
|
|
work_package: "WP-7",
|
|
};
|
|
|
|
writeJson(resolve(caseDirectory, "commands.json"), { commands, run_id: runId, schema_version: "1.0" });
|
|
writeJson(resolve(caseDirectory, "trace-summary.json"), { status: trace.status, summary: trace.summary, schema_version: "1.0" });
|
|
writeJson(resolve(caseDirectory, "upstream-lineage.json"), { current_commit: currentCommit, tasks: report.upstream, schema_version: "1.0" });
|
|
writeJson(resolve(caseDirectory, "deferred-external.json"), {
|
|
policy: "product_owner_first_version_nonblocking",
|
|
tasks: report.deferred_external_tasks,
|
|
treated_as_real_provider_pass: false,
|
|
schema_version: "1.0",
|
|
});
|
|
writeJson(resolve(caseDirectory, "result.json"), result);
|
|
writeJson(resolve(runDirectory, "evidence.json"), { cases: [{ missing_evidence: [], status: result.status, test_id: result.test_id }], run_id: runId, status: result.status, schema_version: "1.0" });
|
|
console.log(JSON.stringify({ deferred_external_tasks: report.deferred_external_tasks, next_task: report.next_task, run_id: runId, status: report.status }, null, 2));
|