# configuration/strings/failure.strings.ts

> 275 lines of code and 12 definitions.

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

## Definitions

- `DECAY_SHAPE` (lexical_declaration, line 18)
- `PAIR_SHAPE` (lexical_declaration, line 21)
- `DECAY_DIAGRAM` (lexical_declaration, line 24)
- `PROPAGATION_DIAGRAM` (lexical_declaration, line 27)
- `CONTROL_DIAGRAM` (lexical_declaration, line 30)
- `PAIR_DIAGRAM` (lexical_declaration, line 33)
- `CONSEQUENCE_DIAGRAM` (lexical_declaration, line 36)
- `DECAY_SECTION` (lexical_declaration, line 39)
- `CONTROL_SECTION` (lexical_declaration, line 99)
- `PAIR_SECTION` (lexical_declaration, line 170)
- `CONSEQUENCE_SECTION` (lexical_declaration, line 228)
- `FAILURE_SECTIONS` (lexical_declaration, line 287, exported)

## Source

```typescript
import { ALGO_DOMAIN_FACE, ALGO_FACE, KIND_FACE, LAYER_FACE } from "@govlab/constants";
import {
    CONSEQUENCE_SECTION_ICON,
    CONTROL_SECTION_ICON,
    DECAY_SECTION_ICON,
    PAIR_SECTION_ICON,
} from "#configuration/icons/architecture.icons";
import {
    CONSEQUENCE_SECTION_ID,
    CONTROL_SECTION_ID,
    DECAY_SECTION_ID,
    PAIR_SECTION_ID,
} from "#core/ids/architecture.ids";
import type { Section } from "#types/document.types";
import { TYPESCRIPT_LANGUAGE } from "#configuration/constants/code.constants";
import { faceLink } from "#domain/converters/ontology.converter";

const DECAY_SHAPE =
    'export const CONTROLS = ["boundary", "contract", "ownership", "versioning", "observability", "state-isolation", "enforcement"] as const;\nexport type Control = (typeof CONTROLS)[number];\n\nexport const PROPAGATION = ["shortcut", "repetition", "normalisation", "dependency-formation", "institutionalisation", "high-cost-repair"] as const;\nexport type Stage = (typeof PROPAGATION)[number];\n\nexport const REMEDIATION = ["missing-control", "inverse-control", "migration", "absence-check", "prevention-gate"] as const;\nexport type Repair = (typeof REMEDIATION)[number];\n\nexport interface AntiPattern {\n    readonly id: AntiPatternId;\n    readonly absentControl: Control;\n    readonly path: readonly { readonly stage: Stage; readonly change: string }[];\n    readonly presentsAs: string;\n    readonly violates: readonly PrincipleId[];\n    readonly detectedBy: readonly SignalId[];\n    readonly repairs: readonly { readonly step: Repair; readonly action: string }[];\n}';

const PAIR_SHAPE =
    "export interface Inversion {\n    readonly refused: { readonly construct: Construct; readonly borrowsAgainst: Consequence };\n    readonly required: { readonly construct: Construct; readonly buys: Consequence };\n}\n\nexport const inversionOf = (refused: Construct, required: Construct, debt: Consequence, leverage: Consequence): Inversion => ({\n    refused: { borrowsAgainst: debt, construct: refused },\n    required: { buys: leverage, construct: required },\n});\n\nexport const asFinding = (rule: Inversion, at: Location): Finding => ({\n    at,\n    reported: rule.refused.construct,\n    remediation: rule.required.construct,\n    reason: rule.refused.borrowsAgainst,\n});";

const DECAY_DIAGRAM =
    'flowchart TB\n    control["A control is absent · boundary, contract, ownership, versioning, observability, state isolation, enforcement"]\n    step1["A local shortcut lands · nothing refuses it"]\n    step2["It is repeated under pressure and becomes convention"]\n    step3["Dependent code forms around it · a boundary or contract erodes"]\n    presents["Systemic fragility · the anti-pattern, reproducible, named, detectable"]\n    repair["The repair · install the inverse control, migrate the dependents, check the absence, gate the recurrence"]\n    control --> step1 --> step2 --> step3 --> presents --> repair';

const PROPAGATION_DIAGRAM =
    "stateDiagram-v2\n    [*] --> Shortcut : a control is absent\n    Shortcut --> Repetition : nothing refuses it\n    Repetition --> Convention : delivery pressure\n    Convention --> Dependency : code forms around it\n    Dependency --> Fragility : the boundary erodes\n    Fragility --> Repair : the pattern is named\n    Repair --> [*] : inverse control installed · dependents migrated · recurrence gated\n    Repair --> Shortcut : one call site removed · the path stays open";

const CONTROL_DIAGRAM =
    'flowchart LR\n    boundary["boundary absent · a foreign model leaks in"]\n    contract["contract absent · a consumer depends on a promise that was never made"]\n    ownership["ownership absent · two writers, the last one wins"]\n    versioning["versioning absent · a breaking change ships as ordinary"]\n    observability["observability absent · the first signal is a customer"]\n    isolation["state isolation absent · a side effect crosses a boundary"]\n    enforcement["enforcement absent · a rule decays at the rate of attention"]\n    decay["One decay class per control · placed by what was missing, never by how it looked"]\n    boundary --> decay\n    contract --> decay\n    ownership --> decay\n    versioning --> decay\n    observability --> decay\n    isolation --> decay\n    enforcement --> decay';

const PAIR_DIAGRAM =
    'flowchart TB\n    refused["A construct is refused · with the debt it borrows against"]\n    required["Its replacement is required · with the leverage it buys"]\n    refused -- one inversion, two consequences --> required\n    check["A check reports the refused construct where it lands"]\n    refused -.-> check\n    remedy["The finding names the required construct as its remediation"]\n    check --> remedy\n    required -.-> remedy';

const CONSEQUENCE_DIAGRAM =
    'flowchart TB\n    construct["A construct under review"]\n    lender{"Whom does it borrow from?"}\n    reader["the next reader"]\n    operator["the developer, later and elsewhere"]\n    change["every future change"]\n    nobody["no lender · it is not a debt"]\n    replacement["What stands in its place, and what does that buy?"]\n    rule["A rule · two constructs, two consequences"]\n    construct --> lender\n    lender --> reader --> replacement\n    lender --> operator --> replacement\n    lender --> change --> replacement\n    lender --> nobody\n    replacement --> rule';

const DECAY_SECTION: Section = {
    icon: DECAY_SECTION_ICON,
    id: DECAY_SECTION_ID,
    intro: `This section covers how an anti-pattern forms. A decay starts as a local shortcut that nothing refused, and it becomes dangerous the moment the shortcut becomes infrastructure, as shown in <cite>a decay path</cite> and <cite>the propagation</cite>. The canon carries the class as a ${faceLink(ALGO_FACE, "architecture-anti-pattern", "contract of its own")}, and every anti-pattern it names is a ${faceLink(KIND_FACE, "anti-pattern", "kind")} a principle may point at and nothing else may.`,
    subsections: [
        {
            blocks: [
                {
                    application:
                        "In practice, an anti-pattern is named by the control whose absence causes it, and its decay path is recorded as the sequence of stages that produces it, so it can be reproduced rather than argued about. The record also holds how it presents, which principles it violates, which signals detect it, which repairs reverse it and which gate prevents its return.",
                    boundary:
                        "A decay path is a class, never an incident. The catalogue carries the shape, how it starts, how it presents and what was missing, and never which file or which developer, because a class transfers to a tree with nothing else in common and an incident makes the next project inherit another project's history as law.",
                    cause: "A shortcut is cheap where it is taken and expensive where it is depended on, so blaming the first change finds a small thing, and the control whose absence let it through is invisible because absent things do not appear in reviews.",
                    decision:
                        "The control is repaired rather than the change that revealed it, because the next change will reveal it again.",
                    failureMode:
                        "A module gains a second writer, then a third, each with a good reason, and by the time two of them disagree about its state no reviewer can say which change was the wrong one, because none of them was.",
                    kind: "lesson",
                    principle:
                        "For this reason an anti-pattern is a reproducible decay path caused by the absence of a specific control.",
                    problem:
                        "Anti-patterns are usually catalogued by how they look, and how they look is the last stage of a process that started with something missing.",
                    validation:
                        "To check this, take an anti-pattern you have met and name the control whose presence would have made the first step of its decay path fail. If you cannot name one, you have named the symptom rather than the pattern.",
                },
                { caption: "a decay path", kind: "mermaid", text: DECAY_DIAGRAM },
            ],
            title: "An absent control, a reproducible path",
        },
        {
            blocks: [
                {
                    kind: "text",
                    text: `A decay path is recorded as reproduction rather than description, and the ${faceLink(ALGO_FACE, "anti-pattern-propagation-kernel", "propagation")} runs through the same stages every time. A local shortcut lands and nothing refuses it, which is where the missing control is named. The shortcut is repeated under delivery pressure until it is a convention, dependent code forms around it, and the repair is now expensive in proportion to what depends on it.`,
                },
                {
                    kind: "text",
                    text: "Recorded that way, the pattern becomes a test. Once the control is installed and the path replayed, the first stage should fail. Lava flow is what a path looks like once it can no longer be replayed, as code kept because no reader knows what depends on it, and temporal coupling is a path whose stages are hidden in the order things happen to be called.",
                },
                { caption: "the propagation", kind: "mermaid", text: PROPAGATION_DIAGRAM },
            ],
            title: "The path",
        },
        {
            blocks: [
                {
                    kind: "text",
                    text: `The ${faceLink(ALGO_FACE, "anti-pattern-remediation-algebra", "repair")} follows the same algebra in reverse. The missing control is named, its inverse is introduced, the dependents are migrated off the shortcut, the old shape is verified absent, and its recurrence is gated.`,
                },
                {
                    kind: "text",
                    text: "A repair that removes one call site leaves the propagation path open and the pattern returns somewhere else. Shotgun surgery is the shape of that failed repair, one change spread across many files because the control was never installed, and divergent change is its mirror, one file changed for many reasons because its concern was never split.",
                },
            ],
            title: "The repair",
        },
    ],
    title: "An anti-pattern is a decay path",
};

const CONTROL_SECTION: Section = {
    icon: CONTROL_SECTION_ICON,
    id: CONTROL_SECTION_ID,
    intro: `This section covers the seven controls, each of which owns a decay class, as shown in <cite>seven controls</cite> and typed in <cite>an anti-pattern record</cite>. The seven are a boundary, a contract, an ownership, a versioning, an observability, a state isolation and an enforcement, and the ${faceLink(ALGO_FACE, "architecture-anti-pattern", "anti-pattern record")} holds as its invariant that every decay path is caused by the absence of one of them. The same idea generalises past architecture, since a ${faceLink(ALGO_FACE, "smell-taxonomy", "taxonomy of smells")} groups any bad practice by the control it lacks rather than by how it looks, and a catalogue organised that way answers a question a gallery of symptoms cannot, which is what to install.`,
    subsections: [
        {
            blocks: [
                {
                    application:
                        "In practice, every anti-pattern is placed under the one control whose absence lets it start, and the catalogue is read as seven classes rather than as a list. When a new pattern appears, the first question is which of the seven was missing, and only then what it looks like, because the answer names the repair.",
                    boundary:
                        "The seven controls classify absence and never presence. A tree that has all seven is not thereby well designed. It is a tree in which the decay classes have something to refuse them, and what it refuses is still decided by the principles the controls hold.",
                    cause: "A catalogue of symptoms grows without bound and teaches recognition, while a catalogue of absent controls stays small and teaches repair, because the number of ways to look wrong is unbounded and the number of things that can be missing is not.",
                    decision: "A catalogue of absences is kept rather than a gallery of symptoms.",
                    failureMode:
                        "A team keeps a growing list of things that went wrong, each with its own fix, and the next failure fits none of the entries because it was filed by appearance and appears differently this time.",
                    kind: "lesson",
                    principle:
                        "For this reason seven controls own seven decay classes, and an anti-pattern is placed by the control it lacks.",
                    problem: "A catalogue organised by appearance grows without bound and never says what to install.",
                    validation:
                        "To check this, take any three anti-patterns you know and name the control each lacks. If two of them lack the same control, they are one class with two faces, and one check covers both.",
                },
                { caption: "seven controls", kind: "mermaid", text: CONTROL_DIAGRAM },
            ],
            title: "Placed by what was missing",
        },
        {
            blocks: [
                {
                    kind: "text",
                    text: "A missing boundary lets a foreign model leak into yours until the two are one tangled model, which shows as boundary leakage, framework leakage and the anemic domain model that follows. A missing contract lets a consumer depend on a behaviour that was never promised, an implicit contract, so the next change breaks it silently. A missing ownership lets two parties write shared mutable state, and the write that lands last wins with no report, which is the lost update.",
                },
                {
                    kind: "text",
                    text: "A missing versioning lets an unversioned breaking change ship as an ordinary one, and schema drift follows. A missing observability lets a system run with opaque runtime behavior, so the first sign of an unobservable failure is a customer reporting it. A missing state isolation lets a hidden side effect reach across a boundary it should not see, and action at a distance is its name once the cause can no longer be found. A missing enforcement is manual-only governance, a rule the whole team agreed to, decaying at the rate of attention.",
                },
            ],
            title: "The seven, each with its class",
        },
        {
            blocks: [
                {
                    kind: "text",
                    text: `Two questions decide whether a catalogue entry is real. Can the path be replayed from its first stage, so that a reader with a different tree reproduces the decay rather than recognising the picture? And does the entry name what it violates by identity, so that a finding on the ${faceLink(LAYER_FACE, "enforcement-core", "enforcement layer")} resolves to the principle, its severity and the repair in one lookup?`,
                },
                {
                    kind: "text",
                    text: `An anti-pattern held as a ${faceLink(ALGO_FACE, "anti-pattern-relationship-record", "typed relationship record")} answers both, and a smell ${faceLink(ALGO_FACE, "anti-pattern-rule-compiler", "compiles into a rule")} only once it does. Pattern cargo cult and the golden hammer are what a catalogue of appearances produces, which is a shape applied because it was recognised, never because its absent control was named.`,
                },
                { code: DECAY_SHAPE, kind: "code", language: TYPESCRIPT_LANGUAGE, title: "an anti-pattern record" },
            ],
            title: "When an entry is real",
        },
        {
            blocks: [
                {
                    kind: "text",
                    text: "For a model-authored codebase the decay classes are the same and the rate is different. A model tends to take a shortcut as readily as a developer under a deadline, and it rarely objects to its own, so a system with an absent control decays at the model's speed rather than a team's.",
                },
                {
                    kind: "text",
                    text: "A control that exists only as a reviewer's habit is absent for every change the reviewer did not see. Installing the seven as checks before the model writes anything is what makes them present for every change rather than for the ones a reviewer happened to read.",
                },
            ],
            title: "The same classes at a model's speed",
        },
    ],
    title: "Seven controls, seven classes",
};

const PAIR_SECTION: Section = {
    icon: PAIR_SECTION_ICON,
    id: PAIR_SECTION_ID,
    intro: `This section covers why every avoidance rule is written as a pair, as shown in <cite>one inversion</cite>. A rule that only says never leaves an empty action set the moment the forbidden thing is the obvious thing, and an empty action set is how the forbidden thing gets written anyway. The canon holds every inversion as a ${faceLink(ALGO_DOMAIN_FACE, "architectural-rules", "contract with an invariant")}, and the practice for the pairs that recur most is described in fail at the boundary on the methodology page.`,
    subsections: [
        {
            blocks: [
                {
                    application:
                        "In practice, the consequences are kept as the rule's reason, so the rule carries its own justification and is never re-argued. A check reports the refused construct where it lands and names the required one as the remediation, and what the replacement supersedes is deleted in the same change, because a marker on the old path keeps two paths alive under one label.",
                    boundary:
                        "An inversion governs living code on one forward path, meaning anything something else depends on, where a shortcut taken today is read as a decision by the next developer or model to find it. It says nothing about how strict a rule is, and it is not a threshold. A bound lives where the check reads it, and the inversion only says that the bound exists.",
                    cause: "A prohibition without its replacement names what to avoid and not what to do, so under pressure the avoided thing is the only thing the developer or the model knows how to write.",
                    decision: "The replacement is written before the prohibition, so the rule is never a bare never.",
                    failureMode:
                        "A rule says no fallbacks, a value is missing at boot, the author has nowhere to go, and the fallback is written with a comment apologising for it.",
                    kind: "lesson",
                    principle:
                        "For this reason an avoidance rule is an inversion that pairs a refused construct and the debt it borrows against with a required construct and the leverage it buys.",
                    problem:
                        "Avoidance rules written as a list of don'ts are obeyed until the first moment the don't is convenient.",
                    validation:
                        "To check this, cover the second half of any rule you hold and ask what you would write instead. If nothing comes, the rule was a prohibition and the debt is already in the tree somewhere.",
                },
                { caption: "one inversion", kind: "mermaid", text: PAIR_DIAGRAM },
            ],
            title: "Half a rule",
        },
        {
            blocks: [
                {
                    kind: "text",
                    text: "The generalised form is a small derivation, and it can be run on any construct in any tree. It asks what the construct borrows against and from whom, names the construct that would stand in its place, and asks what that one buys.",
                },
                {
                    kind: "text",
                    text: "If the second half comes, the pair is a rule and the consequences are its reason. If it does not, the construct is either not a debt or not yet understood, and either way it is not a rule.",
                },
            ],
            title: "The derivation",
        },
        {
            blocks: [
                {
                    kind: "text",
                    text: "Only living code on a single forward path survives that reading. A deprecation marker, a tombstone, a compatibility shim and zombie code are each a refused construct whose replacement is deletion in the same edit. Backward compatibility is a contract a boundary declares, never a second path kept alive inside one.",
                },
                {
                    kind: "text",
                    text: "An export exists only while another file imports it now, unless it is staged behind a drift check that holds it to that promise. A utility dump and a repository dump are the same debt at the scale of a folder, a home for constructs whose replacement was never named, and so a place where every one of them is kept.",
                },
            ],
            title: "One forward path",
        },
    ],
    title: "Never and always",
};

const CONSEQUENCE_SECTION: Section = {
    icon: CONSEQUENCE_SECTION_ICON,
    id: CONSEQUENCE_SECTION_ID,
    intro: "This section covers the consequence on each side of an inversion, which lets the rule survive the moment it is inconvenient. The consequences are derived by the two questions shown in <cite>lender and replacement</cite>, and they turn the pair into a finding a check can print, in the record typed in <cite>an inversion record</cite>.",
    subsections: [
        {
            blocks: [
                {
                    application:
                        "In practice, the refused consequence is derived by asking whom the construct borrows from, whether the next reader, the developer who meets the failure later, or every future change that has to keep two paths alive. The required consequence is derived by asking what holds without attention once the replacement is in place. Both are named, so the rule can be pointed at when it is questioned, and the same two names become the message a check prints and the remediation it proposes.",
                    boundary:
                        "A consequence names a lender or a purchase and never a severity. How strictly a rule binds is a separate fact held beside it, so two rules with the same consequence can bind differently, and a consequence never argues for its own rule's rank.",
                    cause: "A rule whose reason is an adjective is re-argued because an adjective cannot be pointed at, while a rule whose reason names a lender ends the argument by naming who pays.",
                    decision: "A rule is justified by who pays rather than by an adjective.",
                    failureMode:
                        "A rule is defended as good practice, the defence convinces no reviewer under deadline, and the construct it refused is written because no reviewer could say who would pay for it.",
                    kind: "lesson",
                    principle:
                        "For this reason a consequence is a named lender or a named purchase, and a pair with both is already a finding.",
                    problem:
                        "Rules are justified with adjectives, and an adjective is re-argued every time the rule is inconvenient.",
                    validation:
                        "To check this, take any rule you hold and name who pays when it is broken and what is bought when it is kept. A rule where either answer is an adjective has no consequence yet, and it will lose the next argument it is in.",
                },
                { caption: "lender and replacement", kind: "mermaid", text: CONSEQUENCE_DIAGRAM },
            ],
            title: "A lender and a purchase",
        },
        {
            blocks: [
                {
                    kind: "text",
                    text: `The same question derives the refused consequence every time, which is whom the construct borrows from. A shortcut borrows from the next reader. A ${faceLink(ALGO_FACE, "no-fallback", "fallback pattern")} borrows from the developer, because it converts a loud failure into a quiet wrong answer that surfaces later and elsewhere. A ${faceLink(ALGO_FACE, "no-deprecation", "deprecation")} borrows from every future change, because it keeps two paths alive so the choice can be put off.`,
                },
                {
                    kind: "text",
                    text: `A ${faceLink(ALGO_FACE, "no-dual-path", "second path")} borrows from every reader, who now has to decide which one is real. Deferring borrows from the developer who will not remember. ${faceLink(ALGO_FACE, "no-shared-ownership", "Shared mutable state")} borrows from the developer who has to find out which writer won, and silent data corruption from the developer who meets the failure it hid.`,
                },
            ],
            title: "The lender",
        },
        {
            blocks: [
                {
                    kind: "text",
                    text: `The required consequence names what the replacement buys, and the purchase is what makes the rule worth keeping. A ${faceLink(ALGO_FACE, "no-shortcuts", "constraint")} is leverage because it holds without attention. Fail fast is clarity, because the failure lands where its cause is. Explicit removal is coherence, because a removed path cannot be taken.`,
                },
                {
                    kind: "text",
                    text: `A single path is determinism. A single owner is auditability. A bounded lifetime is deterministic release. ${faceLink(ALGO_FACE, "no-callbacks", "An emitted event")} is loose coupling, and ${faceLink(ALGO_FACE, "no-convention-enforcement", "policy as code")} is an automated gate. Because each consequence is named this way, the same record serves the developer reading the rule and the check enforcing it, and the two never drift apart.`,
                },
                { code: PAIR_SHAPE, kind: "code", language: TYPESCRIPT_LANGUAGE, title: "an inversion record" },
            ],
            title: "The purchase",
        },
    ],
    title: "Debt and leverage",
};

export const FAILURE_SECTIONS: readonly Section[] = [DECAY_SECTION, CONTROL_SECTION, PAIR_SECTION, CONSEQUENCE_SECTION];
```
