tools/core/steps/gate.step.ts

tools/core/steps/gate.step.ts is a file in Coordination Surface. 167 lines of code and 22 definitions.

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 { isObject } from "../predicates/schema.predicate.ts";
import { isUnreadableJson } from "../predicates/file.predicate.ts";
import { proofRunEmpty } from "../strings/gate.strings.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 gateReportList = function gateReportList(repoRoot: string, key: string): unknown[] {
    const path = resolve(repoRoot, GENERATED_DIR, REPORT);
    if (!existsSync(path)) {
        return [];
    }

    try {
        const parsed: unknown = JSON.parse(readFileSync(path, "utf8"));
        const held = isObject(parsed) ? parsed[key] : null;
        return Array.isArray(held) ? held : [];
    } catch (error) {
        if (isUnreadableJson(error)) {
            return [];
        }
        throw error;
    }
};

const unfixturedFrom = function unfixturedFrom(repoRoot: string): string[] {
    return gateReportList(repoRoot, "unfixturedKinds").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[] {
    return gateReportList(repoRoot, "outcomes").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: proofRunEmpty(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",
        },
    };
};