Orchestrata Ultimate › Gates › prolog-gate

Gate: prolog-gate

At a glance

Purpose Prove the Key Rules (no_relative_import, banned_import, bare_os_environ, env_mutation, infra_key_with_default, bare_toolchain) over a fact base extracted from the AST snapshot, and refuse to call a stale fact base green.
Where it runs The scripts/gates.py battery (registered as prolog-gate), after the __ast__ refresh pre-step.
Trigger A battery run whose fingerprint changed, or whose last cached verdict was not ok.
Exact command python scripts/gate.py run (--snapshot, default plans/ast-ultimate.json; --repo-root, --workdir, --max-listed)
Blocks Exit 1 on a violation; exit 2 INVALID when the fact base is stale, no rules loaded, or the snapshot is missing; 0 pass.
Ruling / ADR ADR-0031 — every gate decision carries its proof tree; ADR-0032 — the gate adopts the admission-control contract; ADR-0025 — no dynamic predicate construction, no cut; ADR-0089 — bare toolchain names fail the gate. Rules cite RUL-003 and RUL-002 in gate_rules.pl.
Last recorded verdict ok: false in the primary checkout's .cache/gates.json (file last written 2026-09-22 10:01 local; the cause is not recorded there). wt-MAP-PRECOMMIT has no .cache/gates.json.

Diagram projects-orchestrata-ultimate-gates-prolog-gate-1

What it refuses

A Key-Rule violation in the tree — the rule set that used to live in the legacy standards checker (relative imports, bare os.environ["X"] reads, banned imports) plus infra_key_with_default — evaluated as Prolog rules over a fact base extracted from the AST snapshot. It also refuses its own false greens: a stale fact base or a run with no rules loaded exits 2 INVALID, never 0.

gate_rules.pl on wt-MAP-PRECOMMIT (read 2026-10-23) has six violation/4 rules, two more than an earlier version of this page listed:

Rule Refuses Landed
no_relative_import a relative import with the gate
banned_import an import of a library in .claude/banned-libraries.txt with the gate
bare_os_environ an os.environ["X"] read (RUL-003) with the gate
env_mutation an os.environ["X"] = v write (RUL-002) 592a73da7, 2026-08-08: "Split env reads from env writes: the gate was advising a silent data loss"
infra_key_with_default a required infra endpoint read with a literal fallback (RUL-003) with the gate
bare_toolchain a bare toolchain name at a spawn site (ADR-0089) 34b9dc2b1, 2026-10-11

Every rule body carries \+ waived(File, Line): a reasoned # gate-ok: <reason> covering the line suppresses the finding, and a bare # gate-ok: emits no waiver fact (code_facts.pl).

Why it exists

From scripts/gate.py's docstring:

"run evaluates the gate and exits 0 pass / 1 fail / 2 invalid — three outcomes, because 'the rules did not evaluate the code in front of them' is not a pass. explain and why-not answer, for one location, why a rule DID or DID NOT fire. diff runs this layer and the legacy checker it replaces over one corpus and accounts for every disagreement — because a replacement that quietly finds LESS than what it replaces is a regression wearing a cleanup's clothes.

why-not is the question that matters most and the one no checker in this repo could previously answer. The tree-sitter relative-import checker was dead for its entire life, twice over, and nothing noticed — because nothing could ask it why it never fired."

The registry comment in scripts/gates.py adds the succession note: "It REPLACES the standards entry that used to sit here — same three rules plus infra_key_with_default, over an inferred fact base rather than a per-file walk, with three outcomes instead of two."

Design authority: plans/prolog-gates-implementation-plan.md; contract: plans/contracts/prolog-gates.contract.json.

How it runs

Typical failures and how to fix them

Wiring