# tools/rules/checklist.rule.ts

> 213 lines of code and 40 definitions.

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

## Definitions

- `checklistFinding` (lexical_declaration, line 66)
- `basenameOf` (lexical_declaration, line 17)
- `breachFinding` (lexical_declaration, line 99)
- `directoryOf` (lexical_declaration, line 26)
- `isUpstream` (lexical_declaration, line 42)
- `isSealed` (lexical_declaration, line 118)
- `countScan` (lexical_declaration, line 115)
- `undeclaredFinding` (lexical_declaration, line 128)
- `planningSurfaces` (lexical_declaration, line 31, exported)
- `isRewritable` (lexical_declaration, line 38)
- `authoredSurfaces` (lexical_declaration, line 58, exported)
- `spentFinding` (lexical_declaration, line 141)
- `byName` (lexical_declaration, line 22)
- `slash` (lexical_declaration, line 27)
- `prefix` (lexical_declaration, line 43)
- `roots` (lexical_declaration, line 44)
- `activeVenues` (lexical_declaration, line 51, exported)
- `Breach` (type_alias_declaration, line 97)
- `SEALED_REASON` (lexical_declaration, line 103)
- `CountScan` (interface_declaration, line 110)
- `sealed` (lexical_declaration, line 116)
- `breaches` (lexical_declaration, line 117)
- `Distribution` (type_alias_declaration, line 139)
- `rule` (lexical_declaration, line 152, exported)
- `check` (method_definition, line 153, exported)
- `read` (lexical_declaration, line 154, exported)
- `contract` (lexical_declaration, line 155, exported)
- `active` (lexical_declaration, line 156, exported)
- `fields` (lexical_declaration, line 157, exported)
- `authored` (lexical_declaration, line 159, exported)
- `planning` (lexical_declaration, line 160, exported)
- `counts` (lexical_declaration, line 161, exported)
- `reports` (lexical_declaration, line 162, exported)
- `live` (lexical_declaration, line 167, exported)
- `declaredSet` (lexical_declaration, line 168, exported)
- `declaring` (lexical_declaration, line 169, exported)
- `undeclared` (lexical_declaration, line 170, exported)
- `spentSet` (lexical_declaration, line 173, exported)
- `findings` (lexical_declaration, line 175, exported)
- `derivations` (lexical_declaration, line 182, exported)

## Uses

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

## Source

```typescript
import { BLOCKING_SUFFIX, VENUE_ARCHIVE } from "../core/constants/blocking.constants.ts";
import { DECIDE, PLANNING_ROOTS } from "../core/constants/checklist.constants.ts";
import type { RuleContext, RuleDeclaration, RuleResult } from "../core/types/rule.types.ts";
import {
    activeSet,
    contractOf,
    countBreaches,
    inspectSurface,
    rowMarkersOf,
} from "../core/coordinators/checklist.coordinator.ts";
import { contentIsImmutable, regionAdmitsRewrite, slotList, surfacePrefix } from "../../config/surface.config.ts";
import { declaresContract, taskBlocks } from "../core/validators/checklist.validator.ts";
import type { Finding } from "../core/types/segment.types.ts";
import { declaredDistributions } from "../core/validators/converge.validator.ts";
import { itemSpanFlags } from "../core/analyzers/board.analyzer.ts";

const basenameOf = function basenameOf(path: string): string {
    const slash = path.lastIndexOf("/");
    return slash === -1 ? path : path.slice(slash + 1);
};

const byName = function byName(left: string, right: string): number {
    return left.localeCompare(right, "en");
};

const directoryOf = function directoryOf(path: string): string {
    const slash = path.lastIndexOf("/");
    return slash === -1 ? "." : path.slice(0, slash);
};

export const planningSurfaces = function planningSurfaces(paths: readonly string[]): string[] {
    return paths
        .filter((path) => path.endsWith(".md"))
        .filter((path) => PLANNING_ROOTS.includes(directoryOf(path)))
        .toSorted(byName);
};

const isRewritable = function isRewritable(path: string): boolean {
    return !contentIsImmutable(path);
};

const isUpstream = function isUpstream(path: string): boolean {
    const prefix = surfacePrefix();
    const roots = [
        ...slotList("surface", "upstream").map((tail) => (prefix.length === 0 ? tail : `${prefix}/${tail}`)),
        ...slotList("project", "upstream_roots"),
    ];
    return roots.some((root) => path.startsWith(`${root}/`));
};

export const activeVenues = function activeVenues(paths: readonly string[]): string[] {
    return paths
        .filter((path) => path.endsWith(BLOCKING_SUFFIX))
        .filter((path) => !path.startsWith(VENUE_ARCHIVE))
        .toSorted(byName);
};

export const authoredSurfaces = function authoredSurfaces(paths: readonly string[]): string[] {
    return paths
        .filter((path) => path.endsWith(".md"))
        .filter((path) => !isUpstream(path))
        .filter(isRewritable)
        .toSorted(byName);
};

const checklistFinding = function checklistFinding(
    kind: string,
    path: string,
    line: number,
    locus: string,
    actual: string,
    expected: string,
): Finding {
    return {
        actual,
        expected,
        healed: false,
        line,
        locus,
        path,
        remediation: {
            action: "declare",
            decide: DECIDE[kind] ?? kind,
            deterministic: false,
            from: locus,
            target: path,
            to: null,
        },
        rule: `checklist/${kind}`,
        stack: [
            { check: "checklist", resolved: basenameOf(path) },
            { check: kind, resolved: locus },
        ],
    };
};

type Breach = ReturnType<typeof countBreaches>[number];

const breachFinding = function breachFinding(path: string, breach: Breach): Finding {
    return checklistFinding(breach.kind, path, breach.line, breach.locus, breach.actual, breach.expected);
};

const SEALED_REASON =
    " sits inside an item span, and this surface declares that region APPEND-ONLY — " +
    "the remediation for this kind is a REWRITE, so a finding here offers the one operation the " +
    "region forbids, to every party, on every run, forever. A report nobody can drain trains every " +
    "reader to discount the color and the cost lands on the findings beside it, so the standing is " +
    "WITHDRAWN and the observation is published rather than raised";

interface CountScan {
    readonly findings: Finding[];
    readonly withdrawn: [string, string][];
}

const countScan = function countScan(path: string, source: string): CountScan {
    const sealed = regionAdmitsRewrite(path, "item") ? [] : itemSpanFlags(source);
    const breaches = countBreaches(source.split("\n"));
    const isSealed = (breach: Breach): boolean => sealed[breach.line - 1] === true;

    return {
        findings: breaches.filter((breach) => !isSealed(breach)).map((breach) => breachFinding(path, breach)),
        withdrawn: breaches
            .filter(isSealed)
            .map((breach) => [`${path}:${String(breach.line)}`, `${breach.locus}${SEALED_REASON}`]),
    };
};

const undeclaredFinding = function undeclaredFinding(path: string): Finding {
    return checklistFinding(
        "undeclaredDistribution",
        path,
        1,
        basenameOf(path),
        "this planning surface carries task rows and declares no distribution, so it is held to neither the phase contract nor the spent check — both key on that one declaration",
        "the venue this surface distributes, declared in its own header, or the surface retired",
    );
};

type Distribution = ReturnType<typeof declaredDistributions>[number];

const spentFinding = function spentFinding({ declares, line, path }: Distribution): Finding {
    return checklistFinding(
        "spentDistribution",
        path,
        line,
        declares,
        `this planning surface declares ${declares} and the active tree holds no venue by that name, so its distribution is SPENT`,
        "the surface retired where its dependencies allow, or its own header recording that it is spent and why",
    );
};

export const rule: RuleDeclaration = {
    check(context: RuleContext): RuleResult {
        const read = (target: string): string => context.read(target);
        const contract = contractOf(context.repoRoot);
        const active = activeSet(context.repoRoot);
        const fields = rowMarkersOf(context.repoRoot);

        const authored = authoredSurfaces(context.paths);
        const planning = planningSurfaces(context.paths);
        const counts = authored.map((path) => countScan(path, read(path)));
        const reports = planning.map((path) => ({
            path,
            report: inspectSurface(path, read(path).split("\n"), contract, active, fields),
        }));

        const live = activeVenues(context.paths);
        const declaredSet = declaredDistributions(planning, read);
        const declaring = new Set(declaredSet.map((entry) => entry.path));
        const undeclared = planning.filter(
            (path) => !declaring.has(path) && declaresContract(taskBlocks(read(path).split("\n")), fields),
        );
        const spentSet = declaredSet.filter(({ declares }) => !live.some((venue) => venue.endsWith(declares)));

        const findings = [
            ...counts.flatMap((scan) => scan.findings),
            ...reports.flatMap(({ path, report }) => report.breaches.map((breach) => breachFinding(path, breach))),
            ...undeclared.map(undeclaredFinding),
            ...spentSet.map(spentFinding),
        ];

        const derivations: Record<string, unknown> = {
            activeAgents: [...active],
            contract,
            contractReached: planning,
            countReached: authored,
            rowMarkers: fields,
            withdrawnInSealedRegion: Object.fromEntries(counts.flatMap((scan) => scan.withdrawn)),
            ...Object.fromEntries(reports.map(({ path, report }) => [path, report.derivations])),
            activeVenues: live,
            declaredDistributions: declaredSet.map(({ declares, path }) => `${path} · ${declares}`),
            spentDistributionOperands:
                "both operands are DECLARED and neither is a reading of the surface's contents: the header naming a venue, " +
                "and the set of venue files in the active tree. A spent distribution is a STATE rather than an error — the " +
                "work it distributed is either built or blocked — so the finding names the two dispositions and decides " +
                "between them for nobody. What it answers is the question a reader opening the planning directory cannot: " +
                "which surface distributes a venue that is still being argued. A surface whose own retirement condition is " +
                "decidable and whose state nothing derives can only be closed by somebody remembering to look.",
            spentDistributions: spentSet.map(({ declares, path }) => `${path} · ${declares}`),
            undeclaredDistributions: undeclared,
        };

        return { derivations, findings, healed: [] };
    },
    extensions: [".md"],
    heals: false,
    invariant:
        "a planning surface carries tasks and their contracts, current and future only, and one carrying the " +
        "checklist concern answers to the template's rendered contract — axes and ripple read at the phase level " +
        "because that is where the render emits them, whatever level the model attaches them to; and the " +
        "transcribed-count half binds EVERY authored surface rather than the planning ones alone, because a " +
        "surface stating how many of a derived set exists has copied a fact the pipeline computes wherever it " +
        "sits, with the frozen and upstream surfaces outside the population by derivation from their declared " +
        "lifetime rather than by a list, since a finding on a surface nothing may rewrite is a repair nobody can " +
        "reach",
    jurisdiction: "all",
    kinds: [
        "notAChecklist",
        "gateUnnamed",
        "axesMissing",
        "rippleMissing",
        "genesisMissing",
        "precheckedGate",
        "contractIncomplete",
        "history",
        "literalCount",
        "phaseWithoutTask",
        "danglingBinding",
        "danglingReference",
        "duplicateId",
        "closureBeforeItsDependencies",
        "spentDistribution",
        "undeclaredDistribution",
    ],
    stage: "content",

    wholeScopeOnly: true,
};
```
