import { access, mkdir, readFile } from "node:fs/promises"; import { ROUTE_REGISTRY } from "../src/features/installed-feature-contracts.ts"; import { documentationReviewArtifactSchema } from "./contracts/release-artifacts.ts"; import { writeValidatedJsonArtifact } from "./lib/validated-json-artifact.ts"; /** * Documents that state the review scope. The route registry is the source of * truth for what that scope is, so these have to enumerate exactly the * installed routes. * * Both said "six routes" while ten were registered: the four newest — the * platform overview and three reference-resource screens — were outside the * declared manual accessibility scope without anybody deciding they should be. * A hand-typed count drifts silently, so it is derived here instead. */ const ROUTE_SCOPE_DOCUMENTS = Object.freeze([ "README.md", "docs/accessibility/manual-checklist.md", ]); type DocumentationReview = Readonly<{ sourcePath: string; sha256: string; thresholdSatisfied: boolean; verdict: string; score: number; }>; type ReviewLedger = Readonly<{ evidenceReport: Readonly<{ repoPath: string; upstreamCanonicalPath: string; canonicalSha256: string; }>; reviews: Record; reviewer: string; standard: string; status: string; }>; const ledger = JSON.parse( await readFile("docs/architecture/review-ledger.json", "utf8"), ) as ReviewLedger; const evidence = await readFile(ledger.evidenceReport.repoPath, "utf8"); const results = []; for (const [diagram, review] of Object.entries(ledger.reviews)) { const sourceReferenced = evidence.includes(review.sourcePath); const digestReferenced = /^[0-9a-f]{64}$/.test(review.sha256) && evidence.includes(review.sha256); const scorePass = review.thresholdSatisfied === true && review.verdict === "PASS" && typeof review.score === "number" && evidence.includes(`| ${review.score} | PASS |`); results.push({ diagram, sourcePath: review.sourcePath, sha256: review.sha256, sourceReferenced, digestReferenced, reviewer: ledger.reviewer, score: review.score, scorePass, passed: sourceReferenced && digestReferenced && ledger.reviewer === "wiki-diagram-reviewer" && ledger.standard === "rules/diagram-standards.md v2" && scorePass && ledger.status === "PASS_SCOPED", }); } const reportDigestValid = /^[0-9a-f]{64}$/.test(ledger.evidenceReport.canonicalSha256) && evidence.includes(ledger.evidenceReport.canonicalSha256); const installedRouteIds = Object.values(ROUTE_REGISTRY) .map((route) => route.routeId) .sort(); const routeScope = []; for (const path of ROUTE_SCOPE_DOCUMENTS) { let text: string; try { await access(path); text = await readFile(path, "utf8"); } catch { routeScope.push({ path, missingRouteIds: [...installedRouteIds], documented: false }); continue; } const missingRouteIds = installedRouteIds.filter( (routeId) => !text.includes(routeId), ); routeScope.push({ path, missingRouteIds, documented: missingRouteIds.length === 0 }); } const routeScopeDocumented = routeScope.every((entry) => entry.documented); const passed = reportDigestValid && routeScopeDocumented && results.length === 2 && results.every((result) => result.passed); await mkdir("artifacts/quality", { recursive: true }); await writeValidatedJsonArtifact({ path: "artifacts/quality/documentation-review.json", schema: documentationReviewArtifactSchema, value: { schemaVersion: 1, generatedAt: new Date().toISOString(), status: ledger.status, reviewer: ledger.reviewer, standard: ledger.standard, evidenceReport: ledger.evidenceReport, reportDigestValid, routeScope, routeScopeDocumented, results, passed, }, }); if (!passed) { process.stderr.write( "Documentation readiness: FAIL_UNVERIFIED (canonical scoped-review evidence is incomplete)\n", ); process.exit(1); } process.stdout.write("Documentation readiness: PASS_SCOPED\n");