chore: initialize POM 2 repo (docs guards green; release gates recorded NOT RUN pending install)

This commit is contained in:
Antigravity
2026-08-19 10:31:00 +02:00
commit 7ffd00b5c5
111 changed files with 12522 additions and 0 deletions

409
scripts/check-docs.mjs Normal file
View File

@@ -0,0 +1,409 @@
import { existsSync, readFileSync, readdirSync } from "node:fs";
import { join, relative, resolve } from "node:path";
import { fileURLToPath } from "node:url";
const root = resolve(fileURLToPath(new URL("..", import.meta.url)));
// `/pom resume [state-path]` is documented in the README command map and in the POM.yml
// `commands:` block, but it is deliberately absent from the HELP template literal in
// src/command.ts. HELP is canonical for what the built-in help advertises, so the verb is
// neither removed from the docs nor added to HELP. It is recorded here instead, so the
// divergence stays visible and the parity check still passes deterministically.
// Any command divergence that is not listed here is a failure.
const KNOWN_COMMAND_DIVERGENCES = new Set(["resume"]);
// Roots that src/*.ts loads through `new URL("../<root>", import.meta.url)`. Check 1 derives
// this set from source instead of hardcoding it, so a new bundled-resource root cannot be
// added in code and silently omitted from the published package.
const RESOURCE_SOURCES = ["src/prompts.ts", "src/themes.ts", "src/events.ts"];
const BUNDLED_ROOT = /new URL\(\s*["'`]\.\.\/([A-Za-z0-9._-]+)/g;
// Generated-layout names that drifted in earlier revisions and must never come back.
const FORBIDDEN_LAYOUT_NAMES = ["06_exports", "06_logs"];
const REQUIRED_LAYOUT_NAMES = ["06_ledgers", "07_exports"];
const LAYOUT_DOCS = ["docs/INVENTORY.md", "skills/pom/references/artifacts.md"];
const VERIFICATION_STATUSES = ["PASS", "FAIL", "NOT RUN", "BLOCKED"];
const MARKDOWN_LINK = /\[[^\]]*\]\(\s*([^)\s]+?)(?:\s+"[^"]*")?\s*\)/g;
const NAVIGATION_PAGES = ["index.md", "navigation.md"];
// Canonical project coordinates. These live on infrastructure the maintainer owns
// (loca.zone). There is no public forge mirror, so a plausible-looking third-party URL
// must never be substituted, and the earlier `UNRESOLVED:` placeholders must never return.
const METADATA_FIELDS = ["repository", "homepage", "bugs"];
const CANONICAL_HOST = "loca.zone";
const PLACEHOLDER_MARKER = "UNRESOLVED";
const TOTAL_CHECKS = 7;
const checks = [];
const failed = [];
function text(rel) {
return readFileSync(join(root, rel), "utf8");
}
function lineNumbers(body, pattern) {
return body
.split("\n")
.map((line, index) => (pattern.test(line) ? index + 1 : 0))
.filter(Boolean);
}
/** Blanks fenced blocks and inline code spans so illustrative links are not link-checked. */
function withoutCode(body) {
const blank = (matched) => matched.replace(/[^\n]/g, " ");
return body.replace(/^```[\s\S]*?^```/gm, blank).replace(/`[^`\n]*`/g, blank);
}
/** Reads the indented body of a top-level or nested block key, e.g. `commands:`. */
function blockLines(rel, key) {
const lines = text(rel).split("\n");
const start = lines.findIndex((line) => new RegExp(`^\\s*${key}:\\s*$`).test(line));
if (start < 0) return null;
const indent = lines[start].length - lines[start].trimStart().length;
const body = [];
for (const line of lines.slice(start + 1)) {
if (line.trim() === "") continue;
if (line.length - line.trimStart().length <= indent) break;
body.push(line.trim());
}
return body;
}
/** `/pom` -> `dashboard`; `/pom theme install` -> `theme`. */
function verbOf(command) {
const match = /^\/pom(?:\s+([a-z][a-z0-9-]*))?\b/.exec(command);
if (!match) return null;
return match[1] ?? "dashboard";
}
function check(index, name, run) {
const problems = [];
const notes = [];
try {
run((message) => problems.push(message), (message) => notes.push(message));
} catch (error) {
problems.push(`unexpected error: ${error.message}`);
}
console.log(`${problems.length === 0 ? "PASS" : "FAIL"} check ${index}/${TOTAL_CHECKS} ${name}`);
for (const problem of problems) console.log(` ${problem}`);
for (const note of notes) console.log(` note: ${note}`);
if (problems.length > 0) failed.push(name);
}
// 1. Resource/package parity: every bundled-resource root loaded by source must ship.
checks.push((index) =>
check(index, "resource-package-parity", (fail) => {
const roots = new Map();
for (const rel of RESOURCE_SOURCES) {
if (!existsSync(join(root, rel))) {
fail(`${rel}: resource-loading module is missing; check 1 cannot derive bundled roots from source`);
continue;
}
const body = text(rel);
for (const match of body.matchAll(BUNDLED_ROOT)) {
if (!roots.has(match[1])) roots.set(match[1], new Set());
roots.get(match[1]).add(rel);
}
}
if (roots.size === 0) {
fail(
`no bundled-resource roots discovered in ${RESOURCE_SOURCES.join(", ")}; the ` +
`\`new URL("../<root>", import.meta.url)\` pattern in scripts/check-docs.mjs no longer ` +
"matches source and must be repaired (this is a broken check, not an empty result)",
);
return;
}
const files = JSON.parse(text("package.json")).files;
if (!Array.isArray(files)) {
fail("package.json: `files` must be an array listing every published path");
return;
}
for (const [name, sources] of [...roots].sort(([left], [right]) => left.localeCompare(right))) {
if (!files.includes(name))
fail(`package.json: \`files\` must contain "${name}" because ${[...sources].join(" and ")} load it at runtime`);
if (!existsSync(join(root, name)))
fail(`${name}: directory is loaded by ${[...sources].join(" and ")} but does not exist in the repository`);
}
}),
);
// 2. Command parity: HELP, the README command map, and POM.yml `commands:` must agree.
checks.push((index) =>
check(index, "command-parity", (fail, note) => {
const command = text("src/command.ts");
const help = /const HELP\s*=\s*`([\s\S]*?)`\s*;/.exec(command);
if (!help) {
fail("src/command.ts: could not locate the `const HELP = `...`;` template literal that defines the command surface");
return;
}
const helpVerbs = new Set();
for (const line of help[1].split("\n")) {
const trimmed = line.trim();
if (!trimmed.startsWith("/pom")) continue;
const verb = verbOf(trimmed);
if (verb) helpVerbs.add(verb);
}
const readmeLines = text("README.md").split("\n");
const heading = readmeLines.findIndex((line) => /^##\s+Command map\s*$/.test(line));
if (heading < 0) {
fail("README.md: missing the `## Command map` heading that check 2 reads the command table from");
return;
}
const after = readmeLines.slice(heading + 1);
const end = after.findIndex((line) => /^##\s/.test(line));
const readmeVerbs = new Set();
for (const line of end < 0 ? after : after.slice(0, end)) {
if (!line.trimStart().startsWith("|")) continue;
for (const span of line.match(/`[^`]+`/g) ?? []) {
const verb = verbOf(span.slice(1, -1).trim());
if (verb) readmeVerbs.add(verb);
}
}
const commandBlock = blockLines("POM.yml", "commands");
if (!commandBlock) {
fail("POM.yml: missing the top-level `commands:` block that check 2 reads the command map from");
return;
}
const manifestVerbs = new Set();
for (const entry of commandBlock) {
const value = /:\s*(.+)$/.exec(entry);
if (!value) continue;
const verb = verbOf(value[1].trim().replace(/^["']|["']$/g, ""));
if (verb) manifestVerbs.add(verb);
}
if (helpVerbs.size === 0) fail("src/command.ts: HELP advertises no `/pom` verbs");
if (readmeVerbs.size === 0) fail("README.md: the `## Command map` table lists no `/pom` commands");
if (manifestVerbs.size === 0) fail("POM.yml: the `commands:` block lists no `/pom` commands");
const sources = [
["src/command.ts HELP", helpVerbs],
["README.md `## Command map`", readmeVerbs],
["POM.yml `commands:`", manifestVerbs],
];
const union = [...new Set(sources.flatMap(([, verbs]) => [...verbs]))].sort();
for (const verb of union) {
const missing = sources.filter(([, verbs]) => !verbs.has(verb)).map(([label]) => label);
if (missing.length === 0) continue;
if (KNOWN_COMMAND_DIVERGENCES.has(verb)) {
note(`/pom ${verb} is absent from ${missing.join(", ")}; allowlisted in KNOWN_COMMAND_DIVERGENCES`);
continue;
}
const present = sources.filter(([, verbs]) => verbs.has(verb)).map(([label]) => label);
fail(
`/pom ${verb} is documented in ${present.join(", ")} but absent from ${missing.join(", ")}; ` +
"add it there or record it in KNOWN_COMMAND_DIVERGENCES in scripts/check-docs.mjs",
);
}
for (const verb of KNOWN_COMMAND_DIVERGENCES) {
if (!union.includes(verb))
fail(
`KNOWN_COMMAND_DIVERGENCES lists "${verb}" but no source documents /pom ${verb}; ` +
"remove the stale allowlist entry from scripts/check-docs.mjs",
);
}
}),
);
// 3. Layout contract: the generated project tree names in docs must match src/persistence.ts.
checks.push((index) =>
check(index, "layout-contract", (fail) => {
for (const rel of LAYOUT_DOCS) {
if (!existsSync(join(root, rel))) {
fail(`${rel}: layout documentation is missing`);
continue;
}
const body = text(rel);
for (const name of FORBIDDEN_LAYOUT_NAMES) {
const lines = lineNumbers(body, new RegExp(`\\b${name}\\b`));
if (lines.length > 0)
fail(
`${rel}:${lines.join(",")} names "${name}", which src/persistence.ts bootstrapProject never ` +
`creates; the canonical names are ${REQUIRED_LAYOUT_NAMES.join(" and ")}`,
);
}
}
const inventory = text("docs/INVENTORY.md");
for (const name of REQUIRED_LAYOUT_NAMES) {
if (!new RegExp(`\\b${name}\\b`).test(inventory))
fail(`docs/INVENTORY.md: must document the canonical generated directory "${name}"`);
}
}),
);
// 4. Prompt-order contract: POM.yml must mirror the composition order in src/prompts.ts.
checks.push((index) =>
check(index, "prompt-order-contract", (fail) => {
const items = blockLines("POM.yml", "prompt_precedence");
if (!items) {
fail("POM.yml: missing the `prompt_precedence:` list under `knowledge:`");
return;
}
const entries = items.filter((item) => item.startsWith("- ")).map((item) => item.slice(2).trim());
if (entries.length < 3) {
fail(`POM.yml: \`prompt_precedence\` must list the full composition order, found ${entries.length} entries`);
return;
}
const first = entries[0];
const last = entries[entries.length - 1];
if (!/immutable/i.test(first) || !/law/i.test(first))
fail(
`POM.yml: \`prompt_precedence\` entry 1 must name the immutable POM production law that ` +
`composePromptStack prepends, found "${first}"`,
);
if (!/executable stage contract/i.test(last))
fail(
`POM.yml: \`prompt_precedence\` must end with the executable stage contract appended by ` +
`renderStagePrompt, found "${last}" as the final entry`,
);
const misplaced = entries
.slice(0, -1)
.map((entry, position) => (/executable stage contract/i.test(entry) ? position + 1 : 0))
.filter(Boolean);
if (misplaced.length > 0)
fail(
`POM.yml: \`prompt_precedence\` mentions the executable stage contract at entry ` +
`${misplaced.join(",")}; renderStagePrompt appends it last, so it must be the final entry only`,
);
if (!entries.some((entry) => /replac/i.test(entry) && /\bID\b/i.test(entry)))
fail(
"POM.yml: `prompt_precedence` must state that project-local fragments replace bundled fragments " +
"by matching basename ID, as src/prompts.ts composePromptStack does",
);
}),
);
// 5. Link/orphan check: relative doc links must resolve, and every page must be reachable.
checks.push((index) =>
check(index, "link-and-orphan", (fail) => {
const pages = readdirSync(join(root, "docs"))
.filter((name) => name.endsWith(".md"))
.sort();
if (pages.length === 0) {
fail("docs: contains no Markdown pages");
return;
}
const reachable = new Set();
for (const page of pages) {
const rel = `docs/${page}`;
const body = withoutCode(text(rel));
for (const match of body.matchAll(MARKDOWN_LINK)) {
const target = match[1];
if (/^[a-z][a-z0-9+.-]*:/i.test(target) || target.startsWith("#") || target.startsWith("/")) continue;
const path = target.split("#")[0].split("?")[0];
if (path === "") continue;
const resolved = resolve(join(root, "docs"), path);
if (NAVIGATION_PAGES.includes(page)) reachable.add(resolved);
if (!existsSync(resolved))
fail(
`${rel}: broken relative link \`${target}\` resolves to ${relative(root, resolved)}, ` +
"which does not exist on disk",
);
}
}
for (const page of pages) {
if (page === "index.md") continue;
if (reachable.has(resolve(join(root, "docs", page)))) continue;
fail(
`docs/${page}: unreachable page, no link from ${NAVIGATION_PAGES.map((name) => `docs/${name}`).join(" or ")}; ` +
"add it to the navigation tables so the wiki has no orphans",
);
}
}),
);
// 6. Release-evidence freshness: verification gates must be evidence objects, never literals.
checks.push((index) =>
check(index, "release-evidence", (fail) => {
const release = JSON.parse(text("RELEASE.json"));
const verification = release.verification;
if (verification === undefined || verification === null || typeof verification !== "object" || Array.isArray(verification)) {
fail("RELEASE.json: `verification` must be an object mapping each gate to an evidence object");
return;
}
const gates = Object.entries(verification);
if (gates.length === 0) {
fail("RELEASE.json: `verification` lists no gates");
return;
}
for (const [gate, value] of gates) {
if (typeof value !== "object" || value === null || Array.isArray(value)) {
fail(
`RELEASE.json: verification.${gate} is the bare ${typeof value} ${JSON.stringify(value)}; every gate must ` +
`be an evidence object carrying a \`status\` of ${VERIFICATION_STATUSES.join(" | ")}, never a hard-coded literal`,
);
continue;
}
if (typeof value.status !== "string") {
fail(`RELEASE.json: verification.${gate} is missing a string \`status\` field`);
continue;
}
if (!VERIFICATION_STATUSES.includes(value.status))
fail(
`RELEASE.json: verification.${gate}.status is "${value.status}"; allowed values are ` +
`${VERIFICATION_STATUSES.join(" | ")}`,
);
}
}),
);
// 7. Package metadata: canonical coordinates must stay resolved and stay on owned infrastructure.
checks.push((index) =>
check(index, "package-metadata", (fail, note) => {
const pkg = JSON.parse(text("package.json"));
for (const field of METADATA_FIELDS) {
const value = pkg[field];
if (value === undefined) {
fail(`package.json: \`${field}\` is missing; canonical project coordinates are required`);
continue;
}
const urls = [];
if (typeof value === "string") urls.push(value);
else if (typeof value === "object" && value !== null) {
if (typeof value.url === "string") urls.push(value.url);
else fail(`package.json: \`${field}\` is an object without a string \`url\``);
} else {
fail(`package.json: \`${field}\` must be a string or an object with a \`url\``);
continue;
}
for (const url of urls) {
if (url.includes(PLACEHOLDER_MARKER)) {
fail(
`package.json: \`${field}\` still carries the ${PLACEHOLDER_MARKER} placeholder "${url}"; ` +
"set a real canonical URL before publishing",
);
continue;
}
let host;
try {
host = new URL(url.replace(/^git\+/, "")).host;
} catch {
fail(`package.json: \`${field}\` value "${url}" is not a parseable absolute URL`);
continue;
}
if (host !== CANONICAL_HOST && !host.endsWith(`.${CANONICAL_HOST}`))
fail(
`package.json: \`${field}\` points at "${host}", which is outside the canonical ${CANONICAL_HOST} ` +
"infrastructure; no public forge mirror has been confirmed for this package",
);
}
}
const repository = typeof pkg.repository?.url === "string" ? pkg.repository.url : "";
if (repository.includes(CANONICAL_HOST))
note(`${repository} is reserved on owned infrastructure and is not yet serving Git`);
}),
);
checks.forEach((run, position) => run(position + 1));
if (failed.length === 0) {
console.log("POM docs verification PASS");
} else {
console.log(`POM docs verification FAIL (${failed.length}/${checks.length}: ${failed.join(", ")})`);
process.exitCode = 1;
}