import { type Slot, type SlotValue, type SurfaceConfig, config } from "../../../config/surface.config.ts"; import { BINDING_PATH } from "../constants/binding.constants.ts"; import { writeRepair } from "../writers/repair.writer.ts"; const SECTIONS: readonly (keyof SurfaceConfig)[] = ["project", "surface", "convention", "limits", "execution"]; const HEADING: Readonly> = { convention: "Convention slots", execution: "Execution", limits: "Limits", project: "Project slots — what the host supplies", surface: "Surface slots — what this package owns", }; const MARKER = ""; const renderValue = function renderValue(value: SlotValue): string { if (value === null) { return "—"; } if (typeof value === "number") { return `\`${String(value)}\``; } if (typeof value === "string") { return `\`${value}\``; } if (value.length === 0) { return "`[]` — declared and empty"; } return value.map((entry) => `\`${entry}\``).join(" · "); }; const renderRow = function renderRow(section: string, name: string, slot: Slot): string { return `| \`{${section}.${name}}\` | ${slot.state} | ${renderValue(slot.value)} | ${slot.note} |`; }; export const renderBinding = function renderBinding(): string { const lines: string[] = [ MARKER, "---", "name: adapter-project-binding", "type: binding", "summary: Resolves every abstract slot the reasoning templates and the placement standard declare, against this deployment. A slot is RESOLVED, ABSENT or DEFERRED — never silently faked.", "concern: binding", "status: current", "---", "", "# Adapter — project binding", "", "The reasoning templates and the placement standard are runtime-neutral cores. They carry no paths,", "no commands and no model, and instead declare `{slots}` an adapter resolves against the host. This", "document is that adapter, and it is RENDERED from the surface configuration — the values live there,", "so a hand edit here is a second truth that disagrees the moment one of them moves.", "", "## Resolution states", "", "Every slot resolves to exactly one of three states. The third is the one that matters.", "", "| state | meaning | consequence |", "|---|---|---|", "| `RESOLVED` | a real value exists here | the branch using it runs |", "| `ABSENT` | this deployment has no analogue | **the branch using it does not run, and that is declared** |", "| `DEFERRED` | it will exist; it does not yet | the branch is blocked, not skipped |", "", "`ABSENT` is a first-class answer. A consumer gating on a build command in a deployment with no build", "reports that it cannot gate, never invents a substitute and never quietly passes. **An adapter that", "resolves everything is an adapter that is lying about something.**", "", ]; for (const section of SECTIONS) { const slots = config[section]; const names = Object.keys(slots).toSorted((left, right) => left.localeCompare(right, "en")); if (names.length === 0) { continue; } lines.push(`## ${HEADING[section] ?? section}`, "", "| slot | state | value | why |", "|---|---|---|---|"); for (const name of names) { const slot = slots[name]; if (slot === undefined) { continue; } lines.push(renderRow(section, name, slot)); } lines.push(""); } const counts = SECTIONS.map((section) => { const slots = config[section]; const values = Object.values(slots); const resolved = values.filter((slot) => slot.state === "RESOLVED").length; const absent = values.filter((slot) => slot.state === "ABSENT").length; const deferred = values.filter((slot) => slot.state === "DEFERRED").length; return `| \`${section}\` | ${String(resolved)} | ${String(absent)} | ${String(deferred)} |`; }); lines.push( "## Resolution census", "", "Derived on render, so it cannot disagree with the table above.", "", "| section | RESOLVED | ABSENT | DEFERRED |", "|---|---|---|---|", ...counts, "", ); return `${lines.join("\n")}\n`; }; export const writeBinding = function writeBinding(repoRoot: string, rendered: string, declared = ""): string | null { return writeRepair({ declared, repoRoot }, BINDING_PATH, rendered).refusal; };