# tools/rules/entrypoint.rule.ts

> 200 lines of code and 14 definitions.

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

## Definitions

- `finding` (lexical_declaration, line 22)
- `unpublishedOperand` (lexical_declaration, line 49)
- `unwitnessed` (lexical_declaration, line 98)
- `presenceBackedGuard` (lexical_declaration, line 123)
- `entrypointFindings` (lexical_declaration, line 159)
- `PIPELINE_ENTRY` (lexical_declaration, line 20)
- `REPORT_CALL` (lexical_declaration, line 47)
- `duplicateEntry` (lexical_declaration, line 74)
- `guards` (lexical_declaration, line 160)
- `rule` (lexical_declaration, line 171, exported)
- `check` (method_definition, line 172, exported)
- `scoped` (lexical_declaration, line 173, exported)
- `pipelines` (lexical_declaration, line 174, exported)
- `findings` (lexical_declaration, line 175, exported)

## Uses

- [tools/core/predicates/literal.predicate.ts](https://banes-lab.com/source/coordination/tools/core/predicates/literal.predicate.ts.md)
- [tools/core/validators/entrypoint.validator.ts](https://banes-lab.com/source/coordination/tools/core/validators/entrypoint.validator.ts.md)

## Source

```typescript
import type { BranchOperand, Mutation, PresenceBackedGuard } from "../core/validators/entrypoint.validator.ts";
import {
    ENTRYPOINT_ROOTS,
    GUARD_RESOLUTION_DEPTH,
    MUTATION_FIELDS,
    NO_FIX_FLAG,
    OPT_IN_MUTATION_FLAGS,
    PRESENCE_READERS,
} from "../core/constants/path.constants.ts";
import type { RuleContext, RuleDeclaration, RuleResult } from "../core/types/rule.types.ts";
import {
    presenceBackedMutationGuards,
    unpublishedBranchOperands,
    unwitnessedWrites,
} from "../core/validators/entrypoint.validator.ts";
import type { Finding } from "../core/types/segment.types.ts";
import { stringLiterals } from "../core/predicates/literal.predicate.ts";
import { underRoots } from "../core/filters/scope.filter.ts";

const PIPELINE_ENTRY = "runPipeline";

const finding = function finding(path: string, line: number, flag: string): Finding {
    return {
        actual: `${path} offers ${flag}, so healing is opt-in`,
        expected: `${path} heals by default and offers ${NO_FIX_FLAG}`,
        healed: false,
        line,
        locus: flag,
        path,
        remediation: {
            action: "rename",
            decide: "an opt-in repair flag inverts the rule — the tool computed the fix and then declined to apply it, which turns a solved problem into a queue nobody drains",
            deterministic: true,
            from: flag,
            target: path,
            to: NO_FIX_FLAG,
        },
        rule: "entrypoint/healingIsOptIn",
        stack: [
            { check: "entrypoint", resolved: path },
            { check: "flag", resolved: flag },
            { check: "default", resolved: "report" },
        ],
    };
};

const REPORT_CALL = "writePipelineReport";

const unpublishedOperand = function unpublishedOperand(path: string, operand: BranchOperand): Finding {
    return {
        actual: `${operand.name} is computed here, decides which of two behaviors the run takes, is passed into the run, and appears in no key the emitted report declares`,
        expected: "the operand published as a report key",
        healed: false,
        line: operand.line,
        locus: operand.name,
        path,
        remediation: {
            action: "declare",
            decide: "an operand a run BRANCHES on decides what its result MEANS, so a report omitting it publishes a measurement whose conditions the reader cannot recover — and this tree answers outstanding work by READING the report rather than by re-running, so the fact lives only in a line printed to whoever started it. Publish it as a key. THE KEY NAME IS THE AUTHOR'S rather than derivable, which is why this reports instead of healing: a healer inventing a name asserts a field nobody declared. An operand that changes only HOW a result was produced belongs nowhere in it, and this comparison cannot tell that from one that changes what the result means — so a false positive is argued out on the record rather than narrowed away, because narrowing until nothing false ever fires is the check governing the scanner",
            deterministic: false,
            from: operand.name,
            target: path,
            to: null,
        },
        rule: "entrypoint/unpublishedBranchOperand",
        stack: [
            { check: "entrypoint", resolved: path },
            { check: "branches", resolved: operand.name },
            { check: "published", resolved: "absent" },
        ],
    };
};

const duplicateEntry = function duplicateEntry(path: string, pipelines: readonly string[]): Finding {
    return {
        actual: `${String(pipelines.length)} entrypoints run the pipeline`,
        expected: "one entrypoint",
        healed: false,
        line: 1,
        locus: PIPELINE_ENTRY,
        path,
        remediation: {
            action: "move",
            decide: "governance runs through a single entry point whose default is the full pipeline, and arguments narrow it; a second entry is a second default that can disagree with the first, so a run can pass without having run everything",
            deterministic: false,
            from: path,
            target: path,
            to: pipelines[0] ?? null,
        },
        rule: "entrypoint/secondPipelineEntry",
        stack: [
            { check: "entries", resolved: String(pipelines.length) },
            { check: "sites", resolved: pipelines.join(" ") },
        ],
    };
};

const unwitnessed = function unwitnessed(path: string, mutation: Mutation): Finding {
    return {
        actual: `${path} rewrites ${mutation.target} from content read earlier, with no re-read compared against it before the write`,
        expected: `${path} re-reads ${mutation.target} immediately before writing and aborts when it differs from what was read`,
        healed: false,
        line: mutation.line,
        locus: mutation.target,
        path,
        remediation: {
            action: "declare",
            decide: "a whole-file rewrite derived from an earlier read silently destroys anything written between the two, and the loser of that race is never told — the write reports success, so the destruction is discovered only when somebody misses their own work",
            deterministic: false,
            from: null,
            target: path,
            to: "compare-and-swap",
        },
        rule: "entrypoint/unwitnessedWrite",
        stack: [
            { check: "target", resolved: mutation.target },
            { check: "reads", resolved: String(mutation.reads) },
            { check: "witness", resolved: "absent" },
        ],
    };
};

const presenceBackedGuard = function presenceBackedGuard(path: string, guard: PresenceBackedGuard): Finding {
    return {
        actual: `the operand deciding whether this run MUTATES resolves to a reader answering who EXISTS`,
        expected: "the same decision resolved from a reader answering who is WRITING",
        healed: false,
        line: guard.line,
        locus: guard.guard,
        path,
        remediation: {
            action: "declare",
            decide:
                "a mutation guard asks whether taking an exclusive resource is safe RIGHT NOW, and that is a question " +
                "about a write being live rather than about a party existing. A presence surface answers who is " +
                "seated, which is a state a protocol may hold CONTINUOUSLY — and where it does, the guard's true " +
                "state never occurs and the repair it gates becomes unreachable BY CONSTRUCTION rather than deferred " +
                "until quiet, so every finding whose only remedy is that repair is stranded on a walk nobody can " +
                "drain. The two surfaces are usually both already present and one derivation apart, which is what " +
                "makes the wrong one so easy to reach: it is the surface the party is already reading. Resolve the " +
                "decision from the liveness record instead — it clears on its own when the other writer finishes, and " +
                "two parties whose write sets are disjoint stop holding each other at all. WHICH SURFACES ANSWER " +
                "WHICH QUESTION IS SEMANTIC, so it is DATA this check cites rather than a property it infers, and a " +
                "surface enters that data only once somebody has read it and classified it",
            deterministic: false,
            from: guard.guard,
            target: path,
            to: null,
        },
        rule: "entrypoint/presenceBackedMutationGuard",
        stack: [
            { check: "guard", resolved: guard.guard },
            { check: "resolution", resolved: guard.chain.join(" → ") },
            { check: "operand", resolved: "presence" },
        ],
    };
};

const entrypointFindings = function entrypointFindings(path: string, source: string): Finding[] {
    const guards = presenceBackedMutationGuards(source, MUTATION_FIELDS, PRESENCE_READERS, GUARD_RESOLUTION_DEPTH);
    return [
        ...stringLiterals(source)
            .filter((literal) => OPT_IN_MUTATION_FLAGS.includes(literal.value))
            .map((literal) => finding(path, literal.line, literal.value)),
        ...unwitnessedWrites(source).map((mutation) => unwitnessed(path, mutation)),
        ...unpublishedBranchOperands(source, PIPELINE_ENTRY, REPORT_CALL).map((operand) => unpublishedOperand(path, operand)),
        ...guards.map((guard) => presenceBackedGuard(path, guard)),
    ];
};

export const rule: RuleDeclaration = {
    check(context: RuleContext): RuleResult {
        const scoped = underRoots(context.paths, ENTRYPOINT_ROOTS);
        const pipelines = scoped.filter((path) => context.read(path).includes(PIPELINE_ENTRY));
        const findings = [
            ...scoped.flatMap((path) => entrypointFindings(path, context.read(path))),
            ...pipelines.slice(1).map((path) => duplicateEntry(path, pipelines)),
        ];

        return {
            derivations: {
                entrypoints: scoped,
                guardResolutionBound:
                    "the chain from a mutation operand to its reader is followed through local declarations to the " +
                    "declared depth and no further, so a guard whose operand is assembled across more hops than that " +
                    "is outside this check — the bound is stated rather than implied, because a mechanism that " +
                    "appears exhaustive and is not is worse than one whose limit a reader can see",
                guardResolutionDepth: GUARD_RESOLUTION_DEPTH,
                mutationFields: [...MUTATION_FIELDS],
                pipelines,
                presenceReaders: [...PRESENCE_READERS],
            },
            findings,
            healed: [],
        };
    },
    extensions: [".ts"],
    heals: false,
    invariant:
        "every entrypoint heals by default, disables healing only through the declared flag, resolves the decision to mutate from a reader answering who is WRITING rather than who EXISTS, and never rewrites a file from an earlier read without a compared witness",
    jurisdiction: "taxonomy",
    kinds: [
        "healingIsOptIn",
        "unpublishedBranchOperand",
        "secondPipelineEntry",
        "unwitnessedWrite",
        "presenceBackedMutationGuard",
    ],

    stage: "meta",
};
```
