# configuration/strings/rule.fragment.strings.ts

> 94 lines of code and 7 definitions.

Tree: Site tree
Language: typescript
Layer: product
Canonical: https://banes-lab.com/anatomy/tree#file-configuration-strings-rule-fragment-strings-ts
Source text: https://banes-lab.com/assets/sources/source.435fe0afd4d572fc7caebafeecf23ef1978629928c93b3e8beec56a9f5b7718d.generated.txt

## Definitions

- `RULE_CONTRACT_SHAPE` (lexical_declaration, line 6)
- `FINDING_SHAPE` (lexical_declaration, line 9)
- `SHAPE_DIAGRAM` (lexical_declaration, line 12)
- `TIER_DIAGRAM` (lexical_declaration, line 15)
- `REGISTRATION_DIAGRAM` (lexical_declaration, line 18)
- `SHAPE_SECTION` (lexical_declaration, line 21)
- `SHAPE_SECTIONS` (lexical_declaration, line 101, exported)

## Source

```typescript
import { SHAPE_SECTION_ICON } from "#configuration/icons/build.icons";
import { SHAPE_SECTION_ID } from "#core/ids/build.ids";
import type { Section } from "#types/document.types";
import { TYPESCRIPT_LANGUAGE } from "#configuration/constants/code.constants";

const RULE_CONTRACT_SHAPE =
    'export interface RuleContract<MessageId extends string> {\n    readonly meta: {\n        readonly type: "problem";\n        readonly docs: { readonly description: string };\n        readonly schema: readonly [];\n        readonly messages: Readonly<Record<MessageId, string>>;\n    };\n    readonly create: (context: RuleContext<MessageId>) => RuleListener;\n}\n\nexport default {\n    meta: {\n        type: "problem",\n        docs: { description: "a single-instance resource is reached through its one owner" },\n        schema: [],\n        messages: {\n            directReach: "A single-instance resource must be reached through its owner, which serialises access; route the call through the owner\'s API.",\n        },\n    },\n    create(context) {\n        return listener({\n            callExpression(view, node) {\n                if (reachesSharedInstance(view)) {\n                    context.report({ node, messageId: "directReach" });\n                }\n            },\n        });\n    },\n} satisfies RuleContract<"directReach">;';

const FINDING_SHAPE =
    'export type Severity = "error";\n\nexport interface Remediation<Action extends string> {\n    readonly action: Action;\n    readonly operands: Readonly<Record<string, string>>;\n}\n\nexport interface Finding<Action extends string = string> {\n    readonly rule: string;\n    readonly path: string;\n    readonly locus: { readonly line: number; readonly column: number; readonly member?: string };\n    readonly trail: readonly string[];\n    readonly actual: string;\n    readonly expected: string | null;\n    readonly remediation: Remediation<Action>;\n    readonly healed: boolean;\n    readonly severity: Severity;\n}';

const SHAPE_DIAGRAM =
    'flowchart TB\n    subgraph mechanism["The mechanism · provider-agnostic"]\n        detect["Detect the shape · a tree pattern, a token sequence, a structural relation"]\n        message["State the shape and its one fix, naming no instance"]\n    end\n    subgraph registry["The registry · data"]\n        instances["Verified instances of the shape, one line each"]\n    end\n    detect -- reads --> instances\n    next["The next instance"]\n    next -- one registry line, no new check --> instances';

const TIER_DIAGRAM =
    'flowchart TB\n    shape["A shape to gate"]\n    where{"What does the check need to see?"}\n    perfile["One file\'s syntax tree · a per-file rule dropped into the rule host"]\n    closure["Relations across files · a rule that reads the graph a prior stage wrote"]\n    folder["A folder rather than a file · a rule that walks from the root and anchors its finding"]\n    pipeline["The whole tree, or a rewrite · a stage of its own"]\n    shape --> where\n    where --> perfile\n    where --> closure\n    where --> folder\n    where --> pipeline';

const REGISTRATION_DIAGRAM =
    'flowchart TB\n    file["A rule file dropped into the host"]\n    discover["Discovered by shape · a text match on its contract"]\n    index["The index is re-derived from disk"]\n    active["Active at failure severity, no core file edited"]\n    self["The rule host passes through the gate it enforces"]\n    file --> discover --> index --> active --> self\n    self -. a malformed rule fails at lint, never at load .-> file';

const SHAPE_SECTION: Section = {
    icon: SHAPE_SECTION_ICON,
    id: SHAPE_SECTION_ID,
    intro: "A check enforces the shape of an anti-pattern, never a particular provider, package, filename or threshold. Because of that, the check and its message carry over: the same rule catches every later occurrence of the same shape, whatever library or symbol it involves. It is also how a small number of checks can govern a growing tree without growing with it, since the mechanism stays general and a registry holds the instances, as shown in <cite>mechanism and registry</cite>. Where a check runs depends on what it needs to see, as shown in <cite>placed by sight</cite>, and a check becomes active when its file is dropped in, as shown in <cite>dropped in</cite>. Its contract is typed as shown in <cite>a rule contract</cite>, and the finding it produces as shown in <cite>a finding</cite>. The shapes themselves are catalogued on the architecture page, as described in an anti-pattern is a decay path, and each one carries the control whose absence lets it in.",
    subsections: [
        {
            blocks: [
                {
                    application:
                        "In practice, the check is written for the whole class: it detects a construct in a syntax tree, a token sequence or a structural relation, never a name. The instances are kept as data in a registry the check reads, seeded only with instances verified to have the shape. The message states the shape and its one fix in terms a developer working with a different library would understand unchanged, and a rule becomes active when its file is dropped in.",
                    boundary:
                        "A shape whose defining property is semantic rather than structural may carry a registry of classified instances. The split is then strict: the mechanism reads the registry, the registry is the only place a specific name appears, and the message stays general whatever the registry holds.",
                    cause: "A check that names an instance is correct on the case that motivated it and silent on the next case, which is the one it was written to prevent.",
                    decision: "Constructs are gated rather than literals.",
                    failureMode:
                        "A rule bans one library's direct import by name, a second library with the same hazard arrives, and the rule says nothing because it never knew what it was protecting.",
                    kind: "lesson",
                    principle:
                        "For this reason a check matches a shape rather than a name, its instances are kept as data, and its message states the fix in general terms.",
                    problem:
                        "The obvious check names the thing that went wrong, and the thing that went wrong is one instance of a shape that will recur under other names.",
                    validation:
                        "To check this, read a check's message with the vendor, the path and the symbol removed. If it still says what is wrong and how to fix it, the check matches a shape; if it says nothing, the check matched an instance.",
                },
                { caption: "mechanism and registry", kind: "mermaid", text: SHAPE_DIAGRAM },
            ],
            title: "Mechanism general, data specific",
        },
        {
            blocks: [
                {
                    kind: "text",
                    text: "Two properties decide whether a shape can be gated, and both have to hold. The first is that detection is deterministic: the bad shape can be recognised by static analysis, from an import edge, a manifest field or a path, never by a runtime probe that sometimes fails. Where the only way to catch something is to observe non-determinism at runtime, the work is to trace it back to the static shape that causes the non-determinism and gate that shape instead. The second is that remediation is deterministic: there is one correct fix, and it can be stated without reference to any particular case. Where both hold, the shape is gated. Where either fails, it is raised as a question rather than glossed over, and the honest gaps lists the ones raised so far.",
                },
            ],
            title: "Two properties decide",
        },
        {
            blocks: [
                {
                    kind: "text",
                    text: "Where a check runs depends on what it needs to see. A rule over one file's syntax tree is the lightest kind, and it applies the filesystem is the architecture to the checks themselves. A rule over relations between files reads a graph that an earlier stage wrote, and it fails closed when that graph is missing, so the order of the stages matters rather than being incidental. A rule over a folder rather than a file walks from the root, and it needs an anchor, because a finding has to be reported against a file the rule visits: a placement finding attaches to a file inside the offending folder, and a declaration that points at something absent attaches to the manifest that declared it. A check over the whole tree that does not work file by file becomes a stage of its own, and a rewriter checks its own output by parsing it again before it writes.",
                },
                { caption: "placed by sight", kind: "mermaid", text: TIER_DIAGRAM },
            ],
            title: "Placed by what it needs to see",
        },
        {
            blocks: [
                {
                    kind: "text",
                    text: "The mechanism that discovers rules also works by shape, and that is what lets the core stay untouched. A rule becomes active by declaring a contract that the registry pattern discovers; if any core file has to learn the rule's name, the design is wrong. The gate also checks the contract against itself, so a rule that is missing a message, declares its own severity, or reaches for an untyped escape fails at lint rather than at load. The mechanism that enforces every other rule is the one most likely to decay unnoticed, because nothing else watches it, so the rule host passes through the same gate it enforces.",
                },
                {
                    kind: "text",
                    text: "Matching is exact rather than approximate. A check is derived, never guessed, because a check that is usually right is wrong: its misses are invisible, and its false accusations fall on the developer or the model who did the right thing. The tooling I write matches by walking the syntax tree, comparing tokens or comparing exact strings, never by a pattern language that hides the grammar it implements. A hand-written scanner tells use apart from mention, so a detector never matches its own detection strings inside a report about them. It also tests the form of a call rather than a list of names, because a list of names is a check naming instances, and it stops working the moment one more name exists.",
                },
                { caption: "dropped in", kind: "mermaid", text: REGISTRATION_DIAGRAM },
            ],
            title: "Discovered by shape, matched exactly",
        },
        {
            blocks: [
                {
                    kind: "text",
                    text: "The rule contract is small and typed, and its type safety is what lets the registry discover it and the gate check it. A rule declares its kind, a description, an options schema and its messages, and it exports a function that returns a listener over the syntax tree. The message ids form a closed vocabulary, so a report that names an undeclared message fails to compile, and a declared message that no report uses is a finding against the rule. The rule object is exported directly rather than bound to a name, because the filename is the rule's identity, and a second name would be a second fact that has to agree with it. A rule never declares a severity, because there is only one.",
                },
                {
                    kind: "text",
                    text: "What a rule emits is the finding described in detect, log, fix, in typed form: a closed vocabulary of actions, resolved operands and a flag saying whether it healed.",
                },
                { code: RULE_CONTRACT_SHAPE, kind: "code", language: TYPESCRIPT_LANGUAGE, title: "a rule contract" },
                { code: FINDING_SHAPE, kind: "code", language: TYPESCRIPT_LANGUAGE, title: "a finding" },
            ],
            title: "The contract, typed",
        },
    ],
    title: "A check matches a shape",
};

export const SHAPE_SECTIONS: readonly Section[] = [SHAPE_SECTION];
```
