const assert = require("assert"); const fs = require("fs"); const path = require("path"); const CRITERION_HEADING = /^## \*\*(Passed|Partial|Open):\*\* (P3-[A-Z]+-\d{3}):/gm; function readPhase3Ledger(repo) { return fs.readFileSync(path.join(repo, "phase_3_acceptance_criteria.md"), "utf8"); } function criterionStatuses(source) { return [...source.matchAll(CRITERION_HEADING)].map((match) => ({ status: match[1], id: match[2], })); } function statusCounts(criteria) { return Object.fromEntries( ["Passed", "Partial", "Open"].map((status) => [ status, criteria.filter((criterion) => criterion.status === status).length, ]) ); } function assertCompleteCriterionSet(criteria) { assert.strictEqual(criteria.length, 191, "Phase 3 ledger must contain 191 criteria"); assert.strictEqual( new Set(criteria.map((criterion) => criterion.id)).size, 191, "Phase 3 criterion ids must be unique" ); } function assertPreFinalLedger(source) { const criteria = criterionStatuses(source); assertCompleteCriterionSet(criteria); const counts = statusCounts(criteria); assert.deepStrictEqual( counts, { Passed: 0, Partial: 181, Open: 10 }, "the public-release E2E requires the independently reset 181 Partial / 10 Open ledger" ); const expectedOpen = Array.from( { length: 10 }, (_, index) => `P3-GATE-${String(index + 1).padStart(3, "0")}` ); assert.deepStrictEqual( criteria .filter((criterion) => criterion.status === "Open") .map((criterion) => criterion.id), expectedOpen, "only the ten final P3-GATE criteria may be Open in the reset ledger" ); return counts; } function assertFinalLedger(source) { const criteria = criterionStatuses(source); assertCompleteCriterionSet(criteria); const counts = statusCounts(criteria); assert.deepStrictEqual( counts, { Passed: 191, Partial: 0, Open: 0 }, "final release evidence requires all 191 Phase 3 criteria to be Passed" ); return counts; } function assertPreFinalOrFinalLedger(source) { const criteria = criterionStatuses(source); assertCompleteCriterionSet(criteria); const counts = statusCounts(criteria); if (counts.Open === 10) { return assertPreFinalLedger(source); } return assertFinalLedger(source); } module.exports = { assertFinalLedger, assertPreFinalLedger, assertPreFinalOrFinalLedger, criterionStatuses, readPhase3Ledger, statusCounts, };