import { createHash } from "node:crypto"; import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs"; import { resolve } from "node:path"; import matter from "gray-matter"; import { knowledgeContentDigest, parseKnowledgeDocument } from "../src/knowledge.ts"; import { loadKnowledgePolicy, scanKnowledgeDraft } from "./knowledge-policy.ts"; function option(name: string): string | undefined { const index = process.argv.indexOf(name); return index >= 0 ? process.argv[index + 1] : undefined; } function main(): void { const slug = process.argv.slice(2).find((arg) => !arg.startsWith("--")); const reviewBasis = option("--review-basis") ?? "exact-render-review"; const reviewedBy = option("--reviewed-by"); const implementationReviewedBy = option("--implementation-reviewed-by"); const reviewedContentDigest = option("--content-digest"); const reviewReceiptDigest = option("--review-receipt-digest"); const authorizedBy = option("--authorized-by"); const authorizationRecordedAt = option("--authorization-recorded-at"); const authorizationRoute = option("--authorization-route"); const authorizationReceiptPath = option("--authorization-receipt-path"); const confirmed = process.argv.includes("--confirm-public"); if (!slug || !reviewedContentDigest || !reviewReceiptDigest || !confirmed) { throw new Error("promotion requires slug, content digest, receipt digest, and --confirm-public"); } if (reviewBasis !== "exact-render-review" && reviewBasis !== "technical-publication-authorization") { throw new Error(`unsupported review basis: ${reviewBasis}`); } if (reviewBasis === "exact-render-review" && !reviewedBy) { throw new Error("exact-render review requires --reviewed-by"); } if (reviewBasis === "technical-publication-authorization" && ( !implementationReviewedBy || !authorizedBy || !authorizationRecordedAt || !authorizationRoute || !authorizationReceiptPath )) { throw new Error( "technical authorization requires implementation reviewer, authorizer, recorded time, route, and receipt path", ); } const digestPattern = /^sha256:[a-f0-9]{64}$/; if (!digestPattern.test(reviewedContentDigest) || !digestPattern.test(reviewReceiptDigest)) { throw new Error("content and review receipt digests must be sha256:<64 lowercase hex characters>"); } if (reviewBasis === "technical-publication-authorization") { if (!/^knowledge\/receipts\/technical-publication\/[a-z0-9-]+\.json$/.test(authorizationReceiptPath!)) { throw new Error("authorization receipt path must be a repository technical-publication receipt"); } const receiptPath = resolve(process.cwd(), authorizationReceiptPath!); const receiptBytes = readFileSync(receiptPath); const actualReceiptDigest = `sha256:${createHash("sha256").update(receiptBytes).digest("hex")}`; if (actualReceiptDigest !== reviewReceiptDigest) { throw new Error(`authorization receipt digest mismatch: ${actualReceiptDigest}`); } const receipt = JSON.parse(receiptBytes.toString("utf8")) as { kind?: string; entrySlug?: string; route?: string; authorizedBy?: string; recordedAt?: string; scope?: string; exactRenderReviewed?: boolean; implementationReviewedBy?: string; }; if ( receipt.kind !== "technical-publication-authorization" || receipt.entrySlug !== slug || receipt.route !== authorizationRoute || receipt.authorizedBy !== authorizedBy || receipt.recordedAt !== authorizationRecordedAt || receipt.scope !== "technical-publication" || receipt.exactRenderReviewed !== false || receipt.implementationReviewedBy !== implementationReviewedBy ) { throw new Error("authorization receipt fields do not match the promotion arguments"); } } const stagedPath = resolve(process.cwd(), "knowledge/staged", `${slug}.md`); if (!existsSync(stagedPath)) throw new Error(`staged entry not found: ${slug}`); const source = readFileSync(stagedPath, "utf8"); const draft = parseKnowledgeDocument(source, `${slug}.md`, true); const actualContentDigest = knowledgeContentDigest(draft); if (actualContentDigest !== reviewedContentDigest) { throw new Error( `reviewed content changed: expected ${reviewedContentDigest}, found ${actualContentDigest}`, ); } const policy = loadKnowledgePolicy(); const findings = scanKnowledgeDraft(draft.body, policy); const blocking = findings.filter((finding) => finding.severity === "block"); if (blocking.length > 0) throw new Error(`blocked findings remain: ${JSON.stringify(blocking)}`); if (draft.kind === "person" && !policy.allowedPeopleSlugs.includes(draft.slug)) { throw new Error(`person entry is not explicitly allowlisted: ${draft.slug}`); } if (draft.kind === "person" && draft.claimMode !== "factual") { throw new Error("person entries must remain factual"); } if (draft.claimMode !== "perspective" && draft.sources.length === 0) { throw new Error("factual and mixed entries require at least one public source"); } const parsed = matter(source); const existingPublishedPath = resolve(process.cwd(), "knowledge/published", `${slug}.md`); const previousPublishedAt = existsSync(existingPublishedPath) ? matter(readFileSync(existingPublishedPath, "utf8")).data.publishedAt : undefined; const reviewedAt = new Date().toISOString(); const { reviewedBy: _oldReviewedBy, reviewedAt: _oldReviewedAt, implementationReviewedBy: _oldImplementationReviewedBy, implementationReviewedAt: _oldImplementationReviewedAt, publicationAuthorization: _oldPublicationAuthorization, reviewBasis: _oldReviewBasis, ...baseMetadata } = parsed.data; const reviewMetadata = reviewBasis === "exact-render-review" ? { reviewBasis, reviewedBy, reviewedAt, } : { reviewBasis, implementationReviewedBy, implementationReviewedAt: reviewedAt, publicationAuthorization: { kind: "technical-publication-authorization", authorizedBy, recordedAt: authorizationRecordedAt, route: authorizationRoute, scope: "technical-publication", exactRenderReviewed: false, receiptPath: authorizationReceiptPath, receiptDigest: reviewReceiptDigest, }, }; const approved = { ...baseMetadata, reviewStatus: "approved", ...reviewMetadata, publishedAt: previousPublishedAt ?? reviewedAt, reviewedContentDigest, reviewReceiptDigest, }; const output = matter.stringify(`${draft.body}\n`, approved); parseKnowledgeDocument(output, `${slug}.md`, false); const publishedDirectory = resolve(process.cwd(), "knowledge/published"); mkdirSync(publishedDirectory, { recursive: true }); const outputPath = resolve(publishedDirectory, `${slug}.md`); writeFileSync(outputPath, output, "utf8"); unlinkSync(stagedPath); console.log(JSON.stringify({ decision: "promoted", slug, reviewBasis, ...(reviewBasis === "exact-render-review" ? { reviewedBy } : { implementationReviewedBy }), reviewedContentDigest, reviewReceiptDigest, outputPath, }, null, 2)); } try { main(); } catch (error) { console.error(error instanceof Error ? error.message : error); process.exit(1); }