# tools/rules/slot.rule.ts

> 113 lines of code and 18 definitions.

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

## Definitions

- `pathsOn` (lexical_declaration, line 107, exported)
- `namingFinding` (lexical_declaration, line 60)
- `check` (method_definition, line 105, exported)
- `slotOutcome` (lexical_declaration, line 90)
- `remediate` (lexical_declaration, line 10)
- `expected` (lexical_declaration, line 18)
- `{ parsed }` (lexical_declaration, line 19)
- `variant` (lexical_declaration, line 21)
- `decideBy` (lexical_declaration, line 33)
- `SlotRoute` (type_alias_declaration, line 52)
- `SlotOutcome` (interface_declaration, line 54)
- `name` (lexical_declaration, line 66)
- `verdict` (lexical_declaration, line 67)
- `remediation` (lexical_declaration, line 72)
- `governed` (lexical_declaration, line 91)
- `placement` (lexical_declaration, line 96)
- `rule` (lexical_declaration, line 104, exported)
- `outcomes` (lexical_declaration, line 106, exported)

## Source

```typescript
import type { Finding, Remediation } from "../core/types/segment.types.ts";

import type { RuleContext, RuleDeclaration, RuleResult } from "../core/types/rule.types.ts";
import { basename, dirname } from "node:path";
import { checkNaming, checkPlacement, parseFilename } from "../core/validators/taxonomy.validator.ts";
import { NAMING_CODES } from "../core/types/taxonomy.types.ts";
import type { TaxonomyData } from "../core/types/taxonomy.types.ts";
import { governedPath } from "../core/resolvers/taxonomy.resolver.ts";

const remediate = function remediate(
    code: string,
    path: string,
    name: string,
    parentFolder: string,
    data: TaxonomyData,
): Remediation {
    if (code === "concernMismatch") {
        const expected = data.folderToTag[parentFolder];
        const { parsed } = parseFilename(name, data);
        if (expected !== undefined && parsed !== null) {
            const variant = parsed.variant === null ? "" : `${parsed.variant}.`;
            return {
                action: "rename",
                decide: "both operands are computed and this still does NOT heal, which is a property of the OPERATION rather than of the derivation: renaming a file changes what every importer of it resolves, so the repair is not confined to the artifact the remediation names and applying it alone breaks the tree. A remediation heals where its effect is bounded by its own operands; this one is deterministic and unbounded, and the missing half is a reference rewrite this package does not perform. Take the rename and the importers together, by hand, in one change",
                deterministic: true,
                from: name,
                target: dirname(path),
                to: `${parsed.subject}.${variant}${expected}.${parsed.ext}`,
            };
        }
    }

    const decideBy: Record<string, string> = {
        subjectEqualsConcern:
            "the subject carries no information when it equals the concern — name what the file serves",
        undeclaredSlot:
            "work the vocabulary ladder: pick an existing word, else reason it by the is-a test, else the filename is wrong",
        unparsable:
            "name it <subject>[.<variant>].<concern>.<ext> — read the file, take the narrowest accurate concern, use a declared subject",
    };

    return {
        action: code === "undeclaredSlot" ? "declare" : "rename",
        decide: decideBy[code] ?? `resolve naming code ${code}`,
        deterministic: false,
        from: name,
        target: path,
        to: null,
    };
};

type SlotRoute = "outside" | "reached" | "unplaceable";

interface SlotOutcome {
    readonly path: string;
    readonly route: SlotRoute;
    readonly finding: Finding | null;
}

const namingFinding = function namingFinding(
    path: string,
    root: string,
    parentFolder: string,
    data: TaxonomyData,
): Finding | null {
    const name = basename(path);
    const verdict = checkNaming(name, parentFolder, data);
    if (verdict.ok) {
        return null;
    }

    const remediation = remediate(verdict.code ?? "", path, name, parentFolder, data);
    return {
        actual: name,
        expected: remediation.to,
        healed: false,
        line: 0,
        locus: verdict.evidence,
        path,
        remediation,
        rule: `slot/${verdict.code ?? ""}`,
        stack: [
            { check: "jurisdiction", resolved: `root=${root}` },
            { check: "concernFolder", resolved: parentFolder },
            { check: "naming", resolved: verdict.code ?? "fail" },
        ],
    };
};

const slotOutcome = function slotOutcome(path: string, data: TaxonomyData): SlotOutcome {
    const governed = governedPath(path, data);
    if (governed === null) {
        return { finding: null, path, route: "outside" };
    }

    const placement = checkPlacement(governed.root, governed.segments, data);
    if (!placement.ok || placement.foreign === true) {
        return { finding: null, path, route: "unplaceable" };
    }

    return { finding: namingFinding(path, governed.root, placement.concernFolder ?? "", data), path, route: "reached" };
};

export const rule: RuleDeclaration = {
    check(context: RuleContext): RuleResult {
        const outcomes = context.paths.map((path) => slotOutcome(path, context.taxonomy));
        const pathsOn = (route: SlotRoute): string[] =>
            outcomes.filter((outcome) => outcome.route === route).map((outcome) => outcome.path);

        return {
            derivations: {
                reached: pathsOn("reached"),
                skippedAsOutsideJurisdiction: pathsOn("outside"),
                skippedAsUnplaceable: pathsOn("unplaceable"),
            },
            findings: outcomes.flatMap((outcome) => (outcome.finding === null ? [] : [outcome.finding])),
            healed: [],
        };
    },
    extensions: [],
    heals: false,
    invariant: "every filename slot draws from its closed array and the concern tag matches the parent folder",
    jurisdiction: "taxonomy",
    kinds: [...NAMING_CODES],

    stage: "structure",
};
```
