# tools/rules/claim.rule.ts

> 99 lines of code and 12 definitions.

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

## Definitions

- `finding` (lexical_declaration, line 11)
- `check` (method_definition, line 42, exported)
- `BOARD` (lexical_declaration, line 9)
- `rule` (lexical_declaration, line 41, exported)
- `findings` (lexical_declaration, line 43, exported)
- `fanIn` (lexical_declaration, line 44, exported)
- `surfaces` (lexical_declaration, line 46, exported)
- `modified` (lexical_declaration, line 50, exported)
- `absolute` (lexical_declaration, line 51, exported)
- `withdrawn` (lexical_declaration, line 55, exported)
- `walked` (lexical_declaration, line 58, exported)
- `permanent` (lexical_declaration, line 59, exported)

## Source

```typescript
import { BLOCKING_SUFFIX, VENUE_ARCHIVE } from "../core/constants/blocking.constants.ts";

import { type Contention, citedAbsolute, contendedCitations } from "../core/validators/claim.validator.ts";
import type { RuleContext, RuleDeclaration, RuleResult } from "../core/types/rule.types.ts";
import { lifetimeOf, surfacePath } from "../../config/surface.config.ts";
import type { Finding } from "../core/types/segment.types.ts";
import { statSync } from "node:fs";

const BOARD = surfacePath("board");

const finding = function finding(path: string, contention: Contention): Finding {
    return {
        actual: `${contention.key} cites ${contention.cited}, which moved after the claim landed`,
        expected: "a citation whose surface has not moved since the claim was written",
        healed: false,
        line: 0,
        locus: contention.key,
        path,
        remediation: {
            action: "declare",
            decide:
                "the claim's OPERANDS are untouched and what is withdrawn is its STANDING to be quoted — a stale claim " +
                "arrives marked rather than refused, so it costs a reader a glance instead of a read and a reply. Re-read " +
                "the cited surface and either restate the claim against what it now says or leave it standing as a record " +
                "of what was true when it landed. THE STAMP RECORDS WHEN THE TOOL OBSERVED THE SURFACE, which is the " +
                "moment the claim LANDED rather than the moment its author read it, so a claim already stale when composed " +
                "is outside this and stays outside it",
            deterministic: false,
            from: contention.cited,
            target: path,
            to: null,
        },
        rule: "claim/contendedCitation",
        stack: [
            { check: "stamped", resolved: String(contention.stamped) },
            { check: "moved", resolved: String(contention.moved) },
        ],
    };
};

export const rule: RuleDeclaration = {
    check(context: RuleContext): RuleResult {
        const findings: Finding[] = [];
        const fanIn: Record<string, string> = {};

        const surfaces = context.paths.filter(
            (path) => path === BOARD || (path.endsWith(BLOCKING_SUFFIX) && !path.startsWith(VENUE_ARCHIVE)),
        );

        const modified = (cited: string): number | null => {
            const absolute = citedAbsolute(context.repoRoot, cited);
            return absolute === null ? null : statSync(absolute).mtimeMs;
        };

        const withdrawn: Record<string, string> = {};

        for (const path of surfaces) {
            const walked = contendedCitations(context.read(path), modified);
            const permanent = lifetimeOf(path)?.retention === "accumulating";

            for (const contention of walked.contended) {
                if (permanent) {
                    withdrawn[`${path} · ${contention.key}`] =
                        `cites ${contention.cited}, which moved after the claim landed`;
                    continue;
                }
                findings.push(finding(path, contention));
            }

            for (const entry of walked.fanIn) {
                fanIn[`${path} · ${entry.cited}`] =
                    `${String(entry.citations)} citation(s), ${String(entry.contended)} contended`;
            }
        }

        return {
            derivations: {
                fanIn,
                reads: "a citation carries the cited surface's state at the moment the claim landed; fan-in is the count of claims resting on one surface and contended is how many of those the surface has moved under",
                standingContract:
                    "A CITATION SITS ON AN ITEM MARKER BY CONSTRUCTION, so whether its claim can be RESTATED is decided " +
                    "by the declared retention of the surface holding that item. Where the surface ACCUMULATES, the item " +
                    "is permanent by its own declared lifetime: the computed remediation offers restating the claim, " +
                    "which that lifetime forbids, or leaving it standing, which changes nothing — so the finding is " +
                    "unclearable from the moment it is raised, and a run reporting many of them is red on a value nothing " +
                    "can move. A permanent red teaches every reader to discount the color and the cost lands on the " +
                    "findings beside it rather than on itself, so the standing is WITHDRAWN HERE as a derivation and the " +
                    "reader who is about to quote a claim is still told its operand moved. Where the surface is " +
                    "CURRENT-TRUTH the item is drainable by its handler, the claim can be withdrawn with it, and the " +
                    "finding stands. The verdict on the claim is untouched in both cases — what is withdrawn is its " +
                    "standing to be quoted, which is the only thing a moved operand actually damages",
                surfaces,
                withdrawnStandings: withdrawn,
            },
            findings,
            healed: [],
        };
    },
    extensions: [".md"],
    heals: false,
    invariant: "a claim whose cited surface moved after it landed is reported rather than quoted",
    jurisdiction: "all",
    kinds: ["contendedCitation"],
    readsTree:
        "the question is when a cited surface was last MODIFIED, which is a property of the tree rather than of any " +
        "file's contents — a context read returns the text and never the moment, so no declared input can supply it and " +
        "no synthetic sample can carry it. The tree read is bounded to the paths already named by stamps on the surfaces " +
        "this walk was handed, so it reaches nothing a claim does not itself cite",

    stage: "content",
};
```
