# tools/rules/coverage.rule.ts

> 286 lines of code and 55 definitions.

Tree: Coordination tree
Language: typescript
Canonical: https://banes-lab.com/anatomy/coordination#file-coordination-tools-rules-coverage-rule-ts
Source text: https://banes-lab.com/assets/sources/source.fc5cd9dbd6af3d006760d653292a7c6718a92ad75e4c4c1b3e7d14a834a62ce9.generated.txt

## Definitions

- `finding` (lexical_declaration, line 56)
- `gatedOutcome` (lexical_declaration, line 114)
- `principleWalkOf` (lexical_declaration, line 194)
- `countByGate` (lexical_declaration, line 226)
- `check` (method_definition, line 235, exported)
- `parseConditional` (lexical_declaration, line 38)
- `duplicateFindings` (lexical_declaration, line 95)
- `declarationOutcome` (lexical_declaration, line 149)
- `unbuiltFinding` (lexical_declaration, line 184)
- `DIGESTS` (lexical_declaration, line 13)
- `RULE_SOURCES` (lexical_declaration, line 15)
- `UNGATED` (lexical_declaration, line 17)
- `CONDUCT` (lexical_declaration, line 19)
- `CONDUCT_REGISTRY` (lexical_declaration, line 21)
- `SLOT_SEPARATOR` (lexical_declaration, line 23)
- `SECTIONS` (lexical_declaration, line 25)
- `UNREACHED_FAILS` (lexical_declaration, line 27)
- `ConditionalSlot` (interface_declaration, line 31)
- `space` (lexical_declaration, line 39)
- `path` (lexical_declaration, line 40)
- `dot` (lexical_declaration, line 41)
- `known` (lexical_declaration, line 42)
- `name` (lexical_declaration, line 47)
- `conditionalSlot` (lexical_declaration, line 51)
- `Declaration` (interface_declaration, line 80)
- `DECLARATION_ROUTES` (lexical_declaration, line 85, exported)
- `DeclarationRoute` (type_alias_declaration, line 87)
- `DeclarationOutcome` (interface_declaration, line 89)
- `previous` (lexical_declaration, line 99)
- `needed` (lexical_declaration, line 118)
- `unreached` (lexical_declaration, line 120)
- `unknown` (lexical_declaration, line 135)
- `{ declared, path }` (lexical_declaration, line 154)
- `backlog` (lexical_declaration, line 156)
- `unproven` (lexical_declaration, line 170)
- `walk` (lexical_declaration, line 205)
- `listed` (lexical_declaration, line 222)
- `byGate` (lexical_declaration, line 227)
- `rule` (lexical_declaration, line 234, exported)
- `digests` (lexical_declaration, line 236, exported)
- `registered` (lexical_declaration, line 237, exported)
- `registry` (lexical_declaration, line 241, exported)
- `entries` (lexical_declaration, line 243, exported)
- `outcomes` (lexical_declaration, line 246, exported)
- `routed` (lexical_declaration, line 247, exported)
- `gated` (lexical_declaration, line 250, exported)
- `ungated` (lexical_declaration, line 251, exported)
- `conduct` (lexical_declaration, line 252, exported)
- `conditional` (lexical_declaration, line 253, exported)
- `halves` (lexical_declaration, line 259, exported)
- `unbuilt` (lexical_declaration, line 260, exported)
- `slugs` (lexical_declaration, line 261, exported)
- `digestResult` (lexical_declaration, line 262, exported)
- `findings` (lexical_declaration, line 264, exported)
- `lockedUngated` (lexical_declaration, line 272, exported)

## Uses

- [config/surface.config.ts](https://banes-lab.com/source/coordination/config/surface.config.ts.md)

## Source

```typescript
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<string>,
): 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<string>,
): 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<string, number> {
    const byGate: Record<string, number> = {};
    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,
};
```
