import { AXIS_DOCUMENTS, PRINCIPLE_CATALOG } from "../core/constants/path.constants.ts"; import { type DeclaredRule, readDeclaredRules } from "../core/readers/rule.reader.ts"; import type { RuleContext, RuleDeclaration, RuleResult } from "../core/types/rule.types.ts"; import { UNBUILT_HALF, checkableHalves, inspectDigests } from "../core/validators/coverage.validator.ts"; import { isResolved, slotCount, slotList } from "../../config/surface.config.ts"; import { DIGEST_ROOT } from "../core/constants/template.constants.ts"; import type { Finding } from "../core/types/segment.types.ts"; import { RULE_ROOT } from "../core/constants/layer.constants.ts"; import { identityOf } from "../core/registries/rule.registry.ts"; import { stepEmittedIds } from "../core/validators/governance.validator.ts"; import { walkPrinciples } from "../core/readers/architecture.reader.ts"; const DIGESTS = DIGEST_ROOT; const RULE_SOURCES = RULE_ROOT; const UNGATED = "none"; const CONDUCT = "conduct"; const CONDUCT_REGISTRY = `${DIGEST_ROOT}conduct.rule.md`; const SLOT_SEPARATOR = "."; const SECTIONS = ["project", "surface", "convention", "limits", "execution"] as const; const UNREACHED_FAILS = isResolved("convention", "unreached_gate_fails") ? slotCount("convention", "unreached_gate_fails") !== 0 : false; interface ConditionalSlot { readonly slug: string; readonly section: string; readonly name: string; readonly reached: boolean; } const parseConditional = function parseConditional(entry: string): ConditionalSlot[] { const space = entry.indexOf(" "); const path = entry.slice(space + 1).trim(); const dot = path.indexOf(SLOT_SEPARATOR); const known = SECTIONS.find((one) => one === path.slice(0, dot)); if (space <= 0 || dot <= 0 || known === undefined) { return []; } const name = path.slice(dot + 1); return [{ name, reached: isResolved(known, name), section: known, slug: entry.slice(0, space) }]; }; const conditionalSlot = function conditionalSlot(slug: string): ConditionalSlot | null { const entries = isResolved("convention", "conditional_gates") ? slotList("convention", "conditional_gates") : []; return entries.flatMap(parseConditional).find((entry) => entry.slug === slug) ?? null; }; const finding = function finding( kind: string, path: string, rule: DeclaredRule, actual: string, decide: string, ): Finding { return { actual, expected: null, healed: false, line: rule.line, locus: rule.slug, path, remediation: { action: "declare", decide, deterministic: false, from: rule.slug, target: path, to: null }, rule: `coverage/${kind}`, stack: [ { check: "declared", resolved: rule.slug }, { check: "gate", resolved: rule.gate }, { check: kind, resolved: "failed" }, ], }; }; interface Declaration { readonly path: string; readonly declared: DeclaredRule; } export const DECLARATION_ROUTES = ["conduct", "gated", "ungated"] as const; type DeclarationRoute = (typeof DECLARATION_ROUTES)[number]; interface DeclarationOutcome { readonly route: DeclarationRoute; readonly findings: Finding[]; readonly conditional: ConditionalSlot | null; } const duplicateFindings = function duplicateFindings( { declared, path }: Declaration, prior: readonly Declaration[], ): Finding[] { const previous = prior.findLast((entry) => entry.declared.slug === declared.slug); if (previous === undefined) { return []; } return [ finding( "duplicateSlug", path, declared, `${declared.slug} is also declared in ${previous.path}`, "the slug is the only rule identifier, so two declarations make a search resolve two different rules — merge them or rename one", ), ]; }; const gatedOutcome = function gatedOutcome( { declared, path }: Declaration, registered: ReadonlySet, ): DeclarationOutcome { const needed = conditionalSlot(declared.slug); if (needed !== null) { const unreached = needed.reached || !UNREACHED_FAILS ? [] : [ finding( "unreachedGate", path, declared, `${declared.slug} names gate "${declared.gate}", which registers, and its enforcing branch depends on ${needed.section}.${needed.name}, which does not resolve`, "the rule is GATED-WHEN-RESOLVED and currently UNREACHED, which is a third state rather than either of the two: counting it plainly gated puts a zero-ungated total over a rule nothing enforces, and counting it plainly ungated makes a deployment permanently red on a finding whose only repair is acquiring a host. Resolve the slot the branch reads, or declare that an unreached gate does not fail here — which is the consumer's fact rather than this package's", ), ]; return { conditional: needed, findings: unreached, route: "gated" }; } const unknown = registered.has(declared.gate) ? [] : [ finding( "unknownGate", path, declared, `${declared.slug} names gate "${declared.gate}", which nothing in the pipeline registers`, "register a check with that id, or declare gate: none — a rule naming a gate that does not exist reads as coverage while enforcing nothing. A gate is anything the ONE pipeline runs that emits a report and can fail the run, which is a registered rule OR a pipeline step: scoping the set to one of the two shapes that produce a verdict makes a real gate unnameable, and a transition nothing can spell stays undone however often it is noticed", ), ]; return { conditional: null, findings: unknown, route: "gated" }; }; const declarationOutcome = function declarationOutcome( entry: Declaration, registry: string, registered: ReadonlySet, ): DeclarationOutcome { const { declared, path } = entry; if (declared.gate === UNGATED) { const backlog = finding( "ungatedBacklog", path, declared, `${declared.slug} declares gate: none`, "an ungated rule is unfinished work rather than a status — register a gate that observes it, or declare gate: conduct and write the proof in the conduct registry stating what would have to become observable", ); return { conditional: null, findings: [backlog], route: "ungated" }; } if (declared.gate !== CONDUCT) { return gatedOutcome(entry, registered); } const unproven = registry.includes(`\`${declared.slug}\``) ? [] : [ finding( "unprovenConduct", path, declared, `${declared.slug} declares gate: conduct but ${CONDUCT_REGISTRY} carries no proof for it`, `a conduct declaration is a claim that no artifact observes the rule, and an unproven claim is an escape hatch — state in ${CONDUCT_REGISTRY} what would have to be observable for it to be gated, or gate it`, ), ]; return { conditional: null, findings: unproven, route: "conduct" }; }; const unbuiltFinding = function unbuiltFinding(half: { readonly slug: string; readonly line: number }): Finding { return finding( "unbuiltCheckableHalf", CONDUCT_REGISTRY, { gate: UNBUILT_HALF, line: half.line, locked: false, slug: half.slug }, `${half.slug} declares a checkable half that no gate observes`, "the entry states that this half is decidable from an artifact and that nothing decides it, which is enforcement debt rather than a settled question — build the check and name it here, or, if the comparison turns out not to be decidable after all, correct the entry so it claims only what is true. A half described in prose is visible to a reader and invisible to every count, which is how a named-but-unbuilt check sits outside the backlog forever while the roster reads as complete", ); }; const principleWalkOf = function principleWalkOf(context: RuleContext, digests: readonly string[]): object { if (PRINCIPLE_CATALOG === null) { return { meaning: "no principle catalog is declared, so the branch that walks one does not " + "run. A consumer treating an absent slot as a value manufactures a demand " + "nothing can satisfy, and a fabricated pass reads exactly like a real one", state: "ABSENT", }; } const walk = walkPrinciples( context.read(PRINCIPLE_CATALOG), digests.map((path) => context.read(path)), ); return { cited: walk.cited, danglingCitations: walk.danglingCitations, declared: walk.declared, meaning: "citation measures whether the catalog has been WALKED at a decision point, never " + "whether a principle holds — an uncited record may already be satisfied by the tree " + "and a cited one may be cited without being enforced. It is a drainable worklist of " + "principles nothing has yet been reasoned against, not a count of unenforced ones", uncited: walk.uncited, }; }; const listed = function listed(entry: Declaration): { slug: string; axis: string; locked: boolean } { return { axis: entry.path, locked: entry.declared.locked, slug: entry.declared.slug }; }; const countByGate = function countByGate(gates: readonly string[]): Record { const byGate: Record = {}; for (const gate of gates) { byGate[gate] = (byGate[gate] ?? 0) + 1; } return byGate; }; export const rule: RuleDeclaration = { check(context: RuleContext, fix: boolean): RuleResult { const digests = context.paths.filter((path) => path.startsWith(DIGESTS)); const registered = new Set([ ...context.paths.filter((path) => path.startsWith(RULE_SOURCES)).map(identityOf), ...stepEmittedIds(context.repoRoot), ]); const registry = context.paths.includes(CONDUCT_REGISTRY) ? context.read(CONDUCT_REGISTRY) : ""; const entries: Declaration[] = AXIS_DOCUMENTS.filter((path) => context.paths.includes(path)).flatMap((path) => readDeclaredRules(context.read(path)).map((declared) => ({ declared, path })), ); const outcomes = entries.map((entry) => ({ entry, ...declarationOutcome(entry, registry, registered) })); const routed = (route: DeclarationRoute): Declaration[] => outcomes.filter((outcome) => outcome.route === route).map((outcome) => outcome.entry); const gated = routed("gated").map(({ declared, path }) => ({ axis: path, gate: declared.gate, slug: declared.slug })); const ungated = routed("ungated").map(listed); const conduct = routed("conduct").map(listed); const conditional = outcomes.flatMap(({ conditional: needed, entry }) => needed === null ? [] : [{ reached: needed.reached, slot: `${needed.section}.${needed.name}`, slug: entry.declared.slug }], ); const halves = checkableHalves(registry, registered); const unbuilt = halves.filter((half) => half.gate === UNBUILT_HALF); const slugs = new Set(entries.map((entry) => entry.declared.slug)); const digestResult = inspectDigests(context.repoRoot, digests, slugs, fix); const findings = [ ...outcomes.flatMap((outcome, index) => [ ...duplicateFindings(outcome.entry, entries.slice(0, index)), ...outcome.findings, ]), ...unbuilt.map(unbuiltFinding), ...digestResult.findings, ]; const lockedUngated = ungated.filter((entry) => entry.locked); return { derivations: { byGate: countByGate(gated.map((entry) => entry.gate)), checkableHalvesObserved: halves.filter((half) => half.gate !== UNBUILT_HALF), checkableHalvesUnbuilt: unbuilt, conditional, conditionalReading: "a rule here names a REGISTERED gate whose enforcing branch depends on a slot, so it is GATED-WHEN-RESOLVED rather than gated or ungated. Where the slot resolves it is reached and enforced; where it does not, it is UNREACHED and counted in neither the gated total's claim nor the ungated backlog — because counting it gated puts a zero-ungated total over a rule nothing enforces, and counting it ungated makes a deployment permanently red on a finding whose only repair is acquiring a host. Whether an unreached gate FAILS is the consumer's declaration and is read from its own slot rather than guessed here", conduct, counts: { conduct: conduct.length, declared: gated.length + conduct.length + ungated.length, gated: gated.length, lockedUngated: lockedUngated.length, unbuiltCheckableHalves: unbuilt.length, ungated: ungated.length, }, expanded: digestResult.expanded, gated, lockedUngated, principleWalk: principleWalkOf(context, digests), registeredGates: [...registered].toSorted((left, right) => left.localeCompare(right, "en")), ungated, }, findings, healed: [...digestResult.healed], }; }, extensions: [".md", ".ts"], heals: true, invariant: "every declared rule across every governing surface carries a registered gate or a proven conduct claim, and an ungated rule fails", jurisdiction: "taxonomy", kinds: [ "digestDeclares", "duplicateSlug", "unbuiltCheckableHalf", "undeclaredExpansion", "ungatedBacklog", "unknownGate", "unprovenConduct", "unreachedGate", ], reads: PRINCIPLE_CATALOG === null ? AXIS_DOCUMENTS : [...AXIS_DOCUMENTS, PRINCIPLE_CATALOG], stage: "meta", wholeScopeOnly: true, };