# tools/core/steps/gate.step.ts

> 184 lines of code and 21 definitions.

Tree: Coordination tree
Language: typescript
Layer: application
Canonical: https://banes-lab.com/anatomy/coordination#file-coordination-tools-core-steps-gate-step-ts
Source text: https://banes-lab.com/assets/sources/source.981198fd1564a453bda1e75002242a20dd9e2655783021352d7f9a1f04f9a2bb.generated.txt

## Definitions

- `unfixturedFrom` (lexical_declaration, line 31)
- `unfixturedFinding` (lexical_declaration, line 55)
- `gateFinding` (lexical_declaration, line 122)
- `gateStage` (lexical_declaration, line 148, exported)
- `COMMAND` (lexical_declaration, line 11)
- `ARGS` (lexical_declaration, line 13)
- `REPORT` (lexical_declaration, line 15)
- `INVARIANT` (lexical_declaration, line 17)
- `DECIDE` (lexical_declaration, line 19)
- `Outcome` (interface_declaration, line 25)
- `rule` (lexical_declaration, line 56)
- `isOutcome` (lexical_declaration, line 85)
- `candidate` (lexical_declaration, line 90)
- `outcomesFrom` (lexical_declaration, line 98)
- `path` (lexical_declaration, line 99)
- `parsed` (lexical_declaration, line 104)
- `held` (lexical_declaration, line 114)
- `KINDS` (lexical_declaration, line 146, exported)
- `run` (lexical_declaration, line 156, exported)
- `outcomes` (lexical_declaration, line 158, exported)
- `findings` (lexical_declaration, line 160, exported)

## Uses

- [config/surface.config.ts](https://banes-lab.com/source/coordination/config/surface.config.ts.md)
- [tools/core/reporters/rule.reporter.ts](https://banes-lab.com/source/coordination/tools/core/reporters/rule.reporter.ts.md)

## Source

```typescript
import type { StepOptions, StepOutcome } from "../types/rule.types.ts";
import { existsSync, readFileSync } from "node:fs";

import { surfacePath, surfaceRoot } from "../../../config/surface.config.ts";
import type { Finding } from "../types/segment.types.ts";
import { GENERATED_DIR } from "../constants/path.constants.ts";
import { resolve } from "node:path";
import { runTool } from "../runners/process.runner.ts";
import { writeRuleReport } from "../reporters/rule.reporter.ts";

const COMMAND = "npm";

const ARGS = ["run", "--silent", "gates"];

const REPORT = "gate.report.generated.json";

const INVARIANT = "every registered rule is proven to fire on a violation and to accept a clean input";

const DECIDE =
    "a rule nobody has watched fail is indistinguishable from one that cannot fail, and a gate that scans " +
    "nothing passes; declare a fixture pair — one sample " +
    "the rule must report and one it must accept — so the proof is an artifact rather than a ritual repeated " +
    "from memory each time the rule is touched";

interface Outcome {
    readonly rule: string;
    readonly state: string;
    readonly detail: string;
}

const unfixturedFrom = function unfixturedFrom(repoRoot: string): string[] {
    const path = resolve(repoRoot, GENERATED_DIR, REPORT);
    if (!existsSync(path)) {
        return [];
    }

    let parsed: unknown;
    try {
        parsed = JSON.parse(readFileSync(path, "utf8"));
    } catch {
        return [];
    }

    if (typeof parsed !== "object" || parsed === null) {
        return [];
    }
    const held = (parsed as { unfixturedKinds?: unknown }).unfixturedKinds;
    if (!Array.isArray(held)) {
        return [];
    }

    return held.filter((kind): kind is string => typeof kind === "string");
};

const unfixturedFinding = function unfixturedFinding(kind: string): Finding {
    const rule = kind.slice(0, kind.indexOf("/"));

    return {
        actual: `${kind} is emitted and no fixture pair declares it`,
        expected: "a sample the kind must report and one it must accept, or a written exemption",
        healed: false,
        line: 0,
        locus: kind,
        path: `${surfacePath("rules")}/${rule}.rule.ts`,
        remediation: {
            action: "declare",
            decide:
                "a rule proven at RULE granularity says nothing about the kinds it can emit — a pair covering one " +
                "kind leaves every other kind of that rule unobserved, which is how a detector ships having only " +
                "ever been seen to stay quiet. Declare the pair, or declare the exemption with the reason a " +
                "synthetic sample cannot hold the construct",
            deterministic: false,
            from: kind,
            target: `${surfacePath("core")}/fixtures/gate.fixture.ts`,
            to: null,
        },
        rule: "gate/unfixturedKind",
        stack: [
            { check: "emitted", resolved: kind },
            { check: "fixturePair", resolved: "none declares this kind" },
        ],
    };
};

const isOutcome = function isOutcome(value: unknown): value is Outcome {
    if (typeof value !== "object" || value === null) {
        return false;
    }

    const candidate = value as { rule?: unknown; state?: unknown; detail?: unknown };
    return (
        typeof candidate.rule === "string" &&
        typeof candidate.state === "string" &&
        typeof candidate.detail === "string"
    );
};

const outcomesFrom = function outcomesFrom(repoRoot: string): Outcome[] {
    const path = resolve(repoRoot, GENERATED_DIR, REPORT);
    if (!existsSync(path)) {
        return [];
    }

    let parsed: unknown;
    try {
        parsed = JSON.parse(readFileSync(path, "utf8"));
    } catch {
        return [];
    }

    if (typeof parsed !== "object" || parsed === null) {
        return [];
    }
    const held = (parsed as { outcomes?: unknown }).outcomes;
    if (!Array.isArray(held)) {
        return [];
    }

    return held.filter(isOutcome);
};

const gateFinding = function gateFinding(outcome: Outcome): Finding {
    return {
        actual: outcome.detail,
        expected: "a fixture pair the rule fires on and accepts",
        healed: false,
        line: 0,
        locus: outcome.rule,
        path: `${surfacePath("rules")}/${outcome.rule}.rule.ts`,
        remediation: {
            action: "declare",
            decide: DECIDE,
            deterministic: false,
            from: outcome.rule,
            target: `${surfacePath("core")}/fixtures/gate.fixture.ts`,
            to: null,
        },
        rule: `gate/${outcome.state}`,
        stack: [
            { check: "fixturePair", resolved: outcome.state },
            { check: "detail", resolved: outcome.detail },
        ],
    };
};

export const KINDS: readonly string[] = ["gate/unfixturedKind", "gate/silent", "gate/noisy", "gate/untested"];

export const gateStage = function gateStage(options: StepOptions): StepOutcome {
    if (options.bypass.includes("gates")) {
        return {
            findings: [],
            stage: { bypassed: true, findings: 0, healed: 0, invariant: INVARIANT, rule: "gates", stage: "meta" },
        };
    }

    const run = runTool(surfaceRoot(), "gates", COMMAND, INVARIANT, ARGS);

    const outcomes = outcomesFrom(options.repoRoot);

    const findings =
        outcomes.length === 0
            ? [
                  gateFinding({
                      detail:
                          "the proof run produced no outcomes, so no rule has been shown to fire — a step whose " +
                          `own invocation failed reports the same green as one where every pair passed: ${run.output.trim().slice(0, 300)}`,
                      rule: "gates",
                      state: "unproven",
                  }),
              ]
            : [
                  ...outcomes
                      .filter((outcome) => outcome.state !== "proven" && outcome.state !== "exempt")
                      .map(gateFinding),
                  ...unfixturedFrom(options.repoRoot).map(unfixturedFinding),
              ];

    writeRuleReport(options.repoRoot, "gates", {
        authoritative: options.authoritative,
        derivations: {
            provenKinds: outcomes
                .filter((outcome) => outcome.state === "proven")
                .map((outcome) => `${outcome.rule}: ${outcome.detail}`),
            reached: outcomes.map((outcome) => outcome.rule),
            skippedAsExemptByDerivation: outcomes
                .filter((outcome) => outcome.state === "exempt")
                .map((outcome) => `${outcome.rule}: ${outcome.detail}`),
            unfixturedKinds: unfixturedFrom(options.repoRoot),
        },
        findings,
        healed: [],
        invariant: INVARIANT,
        rule: "gates",
        scanned: outcomes.length,
        scope: options.scope,
        stage: "meta",
        verdict: findings.length === 0 ? "pass" : "fail",
    });

    return {
        findings,
        stage: {
            bypassed: false,
            findings: findings.length,
            healed: 0,
            invariant: INVARIANT,
            rule: "gates",
            stage: "meta",
        },
    };
};
```
