Orchestrata Ultimate › Gates

Gates — Master Index

A gate in orchestrata-ultimate is a mechanical check with a command, a failure behavior, and no discretion. This index lists every gate in the order a change meets it, with where it runs, what it blocks, the ruling or ADR behind it, and its page. The path itself, with diagrams and a worked example, is on Workflow.

The layers:

  1. Dispatch and session gates: Claude Code hooks that refuse a brief, a command or the end of a turn.
  2. The worker's stop gate: the commit gate run on a temporary index before a worker may finish.
  3. The commit gates: scripts/hooks/pre-commit and scripts/hooks/commit-msg.
  4. The push gates: scripts/hooks/pre-push and the stages of scripts/run_tests.py it calls (freshness, affected selection, infrastructure, five safety gates, reuse, rehearsal exclusion, the capped test phase).
  5. The 24 registered battery gates: the GATES registry of scripts/gates.py plus the __ast__ pre-step, cached in .cache/gates.json.
  6. Ship, CI and deploy: deploy/ship.sh verify, the GitLab pipeline, the fleet-drift gates and the deploy launchers' checks.
  7. The codetools gates and the process-level gates that live in workflow law.

The narrative context, where these gates sit in the design, decision and implementation lifecycle, is on Ruleset Engine — The Complete Picture (section 5, "Process-level gates").

Diagram projects-orchestrata-ultimate-gates-index-1

The catalogue, in the order a change meets it

1. Dispatch and session (Claude Code hooks)

Gate Where it runs What it blocks Ruling / ADR Page
dispatch-brief PreToolUse Agent and Workflow hooks of the orchestrata plugin: task_context_hook.py, require-design-before-build.sh, workflow-default-sonnet.sh An Agent brief without the literal GOAL:, FILES:, CONSTRAINTS:, DONE WHEN:, VERIFY: labels; a build dispatch with neither a DESIGN_WAIVER: line nor a design contract; a Workflow script without the Sonnet default RUL-022, ADR-0048, RUL-026 dispatch-brief
Session-hook guards (family: 30 guards and 2 plumbing files) .claude/hooks/*.sh, registered in the repo's .claude/settings.json and re-emitted into the orchestrata plugin, which runs them through _dispatch.sh, on SessionStart, PreToolUse, PostToolUse, Stop and UserPromptSubmit Per guard: no-xdist.sh, force-ast-toolkit.sh (hand-reading Python), single-gate-entrypoint.sh, no-unbounded-wait.sh, force-test-observation.sh, no-doubles-py.sh, no-banned-deps.sh, forbidden-doubles-stop.sh and the rest per guard, on the family page family-session-hooks
Shell write and delete guard PreToolUse Bash intercept_bash.py; intercept_write.py and intercept_edit.py on Write and Edit Files written through the shell and any deletion command, in every project; a Write over an existing file ("Use Edit tool") see page /claude/hooks/intercept_bash
Test-run contention guard test_run_context.py on PreToolUse Bash (also SessionStart and UserPromptSubmit for context) CPU-heavy commands while an authoritative run is measuring; ORCH_ALLOW_CONTENDING=1 overrides see page /claude/hooks/test_run_context
Install and secret guard install_secret_guard.py on PreToolUse Bash Unpinned package installs, registry overrides, credential materialization see page /claude/hooks/install_secret_guard
Convention guard convention_guard.py on PreToolUse Bash, Write, Edit Asks rather than denies: a command or edit that contradicts a standing platform convention, confirmed with one keypress see page /claude/hooks/convention_guard
unshipped-guard Stop hook in ~/.claude/settings.json (user level) Ending a turn while a watched repo has local-only commits this session made scoping per RUL-035 unshipped-guard

2. The worker's stop

Gate Where it runs What it blocks Ruling / ADR Page
commit-precheck SubagentStop hook ~/.claude/hooks/precommit_gate_subagent.sh (in ~/.claude/settings.local.json), which runs ~/bin/precommit-check A worker's finish while its .py edits fail the commit gate; at most 3 blocks per agent RUL-035, RUL-008, RUL-041 commit-precheck

3. Commit (scripts/hooks/pre-commit, scripts/hooks/commit-msg)

Gate Where it runs What it blocks Ruling / ADR Page
secrets pre-commit, first stage: scripts/check_staged_secrets.py A credential-shaped value on an added staged line (exit 1); an unreadable staged set (exit 2, "never silently treated as clean") none recorded by id; AD-85 (2026-10-17) added the punctuation-only exemption secrets
Project interpreter check pre-commit, when Python is staged A commit from a checkout with no .venv/bin/python ("Commit blocked — no project interpreter"), since a checkout without one cannot review RUL-021 review-staged
review-staged pre-commit: scripts/gate.py review-staged (code review over src/, test review over tests/, end2end/, scripts/, verdict derived in commit_review.pl) Blocking findings (exit 1) or an invalid review (exit 2: not run, timed out, report that does not add up) RUL-008, ADR-0101, ADR-0116 review-staged
ai-attribution commit-msg: check_ai_attribution.py --message-file; also ship verify (--range) and scripts/health_check.py An AI trailer (R1) or AI marker (R2) in a new commit message RUL-007 ai-attribution

The pre-commit hook also runs three steps that never block: the stage-walls ledger (reports/precommit-walls.ndjson, ADR-0101 rule 2), ruff check --fix on the staged files, and the codebase-map refresh. They are described on Workflow — the commit gate.

4. Push (scripts/hooks/pre-push and scripts/run_tests.py)

Gate Where it runs What it blocks Ruling / ADR Page
pre-push-guards scripts/hooks/pre-push A push from a worktree with master or main checked out; a missing origin/master (fail closed); skips a push whose exact source already passed RUL-040, RUL-032, RUL-021 pre-push-guards
freshness-guard run_tests.py step 0 A run that would consume stale inputs: a failed refresh aborts the run the 2026-08-04 ruling in the script's docstring freshness-guard
affected-selection run_tests.py --affected step 0.75, before infrastructure A changed file the selector cannot bound: refused with the missing fact named, never a silent full run RUL-040, RUL-029 affected-selection
Infrastructure preflight run_tests.py step 1: Redis, Graph, Gateway, Kernel in parallel, then Link Any test run when a service, or the gateway's link to the kernel, is down; the kernel is required RUL-010 family-suite-preflight
source-provenance run_tests.py step 2, first of five concurrent safety gates A run whose installed package is not this checkout's non-editable install RUL-021, ADR-0120 source-provenance
parallel-safety step 2 (also a battery gate) Test patterns that collide under parallel execution the 2026-07-10 ruling "no violations allowed" parallel-safety
test-purity step 2 (also a battery gate) Mocks, fakes, stubs, monkeypatch, skips; banned-library imports RUL-002 test-purity
prolog-boundary step 2 (also a battery gate) A Python Prolog query aimed at a predicate or arity that does not exist see page prolog-boundary
rulings-lint step 2, fifth of five A ruling with no ## Enforcement section, or a declared mechanism that does not exist RUL-014 rulings-lint
green-ledger pre-push and ship (source stamp); run_tests.py steps 2b and 2c Never fails; removes proven modules from the run so a passing test does not run twice RUL-032 green-ledger
rehearsal-exclusion run_tests.py, gate mode only Rehearsal-class modules in a promotion gate; a missing or wrong-version derivation artifact aborts the run RUL-039 rehearsal-exclusion
test-phase-cap run_tests.py step 3; the observer plugin in every pytest a Claude session starts A test phase over 300 s (CAPPED, non-zero); a multi-file pytest session without the sanctioned-runner stamp RUL-038 amendment, RUL-009 test-phase-cap

5. Ship, CI and deploy

Gate Where it runs What it blocks Ruling / ADR Page
ship-verify deploy/ship.sh step 1 A ship whose ruff, black, RUL-007 range, suite, plugin check or env agreement fails; it then pushes with --no-verify RUL-007, RUL-032, RUL-038 ship-verify
fleet-drift check_infra_drift.py on the orchestrata-infra-drift timer and in health_check.py; check_env_fleet_agreement.py in ship Drift between the OpenTofu declaration and the live fleets; env files that disagree with terraform ADR-0077 fleet-drift
ci-pipeline GitLab CI from .gitlab-ci.yml on the self-hosted Incus executor A failed job fails the pipeline; nothing local waits for it, so CI reports after the push RUL-004 ci-pipeline
Deploy-time checks ct-install, tools-deploy, hermes-deploy, install-orchestrata.sh, install-claude-config.sh A deploy whose installed thing is not the recorded commit (identity), whose smoke check fails, or whose source is not a pinned ref; failed installs roll back platform convention 4 (no deploy-in-place) Deployment

6. Elsewhere

Gate Where it runs What it blocks Ruling / ADR Page
codetools gates the codetools repo: codetools gate provision, readiness, run, cpuset, status; select-affected; the ct-install post-promote checks A red readiness probe (refusal class infra); a red batch (bisected); an affected batch with no full verify record codetools ADRs 0039, 0040, 0042, 0043, 0044; RUL-040 codetools-gates
Process-level gates (family) workflow moments: dispatch, landing, fold, commit, ratification, merge briefs-before-dispatch, evidence-on-landing, fold-verifier, ADR drift, plugin currency, F13's traceability battery, Mohamed's ruling per row, on the family page family-process-gates

Count. The catalogue has 51 entries: 27 in the tables above that are not battery gates (three of them groups with their own page: the 30 session guards, the process gates, the deploy launchers' checks) and the 24 battery gates below. Three gates run in both places (parallel-safety, test-purity, prolog-boundary) and are counted once, in the battery.

How the battery works (one command, three behaviors)

The registered gates have one entry point — enforced by the single-gate-entrypoint.sh session hook:

python scripts/gates.py                # changed gates only (the default)
python scripts/gates.py --all          # ignore the cache, run everything
python scripts/gates.py --only ruff mypy   # run only the named gate(s)
python scripts/gates.py --no-fix-ast   # skip the AST refresh (on by default)
python scripts/gates.py --no-fix       # skip the auto-format step

From scripts/gates.py's own docstring, the three behaviors that exist "because the manual alternative kept costing whole minutes and whole sessions":

  1. Parallel. "The gates are independent read-only analyses over a tree nobody is mutating, so wall-clock is the slowest gate, not their sum. Measured 2026-08-07: ~50s serial -> ~25s parallel."
  2. Deduplicated. "Each gate's verdict is cached against a fingerprint of the inputs it actually reads. Re-running with nothing changed is a no-op that prints the cached PASS instead of re-deriving it." The cache lives in .cache/gates.json. _fingerprint(roots) (AST toolkit, 2026-10-23) is a sha256 over the relative path and the sha256 of the bytes of every file under the gate's declared input roots, so it is insensitive to mtime; _interesting keeps only .py, .toml, .pl, .json, .md and .sh files and drops cache directories. One suffix set serves every gate. The function's docstring still says "from git's own object hashing"; the code reads the bytes itself. No gate mixes git state into its fingerprint, so a new commit or a moved master with no content change does not re-run feature-loss or wiring. Two gates (generated-artifacts, worktree-envs) opt out of caching entirely with the root !always (ALWAYS_RUN), because their subject is git or system state no content hash can see. Earlier versions of this page named GATE_MASKS and GATE_GIT_STATE; neither exists in any commit of scripts/gates.py (git log --all -S, 2026-10-23). The blind spots this leaves are listed on each gate's page; re-run one with python scripts/gates.py --only <gate> --all.
  3. Self-healing. ruff --fix + black run before the gates (files written by scripts skip the editor-side autoformat hook), and a stale AST snapshot is refreshed automatically (__ast__ — see its page) because "that two-step ordering was documented and still forgotten repeatedly."

Exit code of the battery: 0 only if every gate passed.

The 24 registered gates

Where they run: by hand, python scripts/gates.py. No git hook, CI job or ship step runs the battery (grep of scripts/hooks/, .gitlab-ci.yml, .github/workflows/ and deploy/ship.sh, 2026-10-23). Ship runs its own copy of the plugin-drift check, "which this gate does not run" otherwise (see ship-verify), and the pre-push suite runs three of the gates as its safety gates. The battery exits non-zero when any gate fails.

Gate Family What it refuses (one line) Ruling / ADR Command Page
__ast__ correctness / lint Running the battery against a stale AST snapshot, or refreshing it in a way that destroys the runtime call graph none names the pre-step; snapshot path ADR-0097 (automatic pre-step) uv run ast-sync + scripts/build_runtime_callgraph.py reaugment page
architecture structure An import that violates the 6-layer model (a lower layer reaching up, a domain service importing a concrete peer) RUL-008, ADR-0056 python scripts/architecture_checker.py page
check-deps structure A third-party import that pyproject.toml does not declare none by id; the CLAUDE.md Key Rule python scripts/serialize_codebase_ast.py check-deps --include-tests page
coverage-claude delivery The claude/ tree's measured test coverage dropping below its ratcheted floor RUL-034 python scripts/coverage_ratchet.py --scope claude --paths claude --tests tests/claude tests/scripts/test_task_context_hook.py --min 19.5 page
env-contract environment A production entrypoint that needs infra config but never loads the env contract RUL-019 python scripts/check_env_contract.py page
env-subnet-scheme environment An environment profile whose addresses break the dedicated-octet scheme (prod 10.53.1.x / test 10.53.2.x / dev 10.53.3.x) RUL-003, ADR-0080 python scripts/check_env_subnet_scheme.py page
external-tools structure A non-PyPI executable that is undeclared, missing, or too old (both directions) RUL-014, ADR-0089 python scripts/check_external_tools.py page
feature-loss traceability & loss A requirement silently losing its implementation, or a spec/ADR being deleted while code still cites it RUL-023, RUL-030 python scripts/check_feature_loss.py page
generated-artifacts traceability & loss A generated artifact kept out of git, or a generator deleted while its artifacts survive RUL-030 python scripts/check_generated_artifacts.py page
lexicon-collision lexicon An intent-lexicon work-type word that also names a subsystem (so "wire the memory engine" misclassifies) RUL-014 python scripts/check_lexicon_collisions.py page
lexicon-drift lexicon The generated Prolog intent lexicon drifting from the Python vocabulary that is its source of truth RUL-030 python scripts/gen_intent_lexicon.py --check page
mypy correctness / lint A type error reaching CI that a local run should have caught RUL-008 uv run mypy --cache-dir .cache/mypy src/ page
parallel-safety test discipline A test pattern that WILL collide under parallel execution (unscoped Cypher, shared Redis keys, session-scope fixtures…) the 2026-07-10 ruling "no violations allowed" python scripts/gate_parallel_safety.py page
plugin-drift delivery The generated plugins/orchestrata plugin drifting from the claude/ tree it is derived from the "claude/ is production, not scaffolding" ruling python claude/scripts/gen_plugin.py --check page
prod-separation environment A production systemd unit pointing any path-bearing directive at the development tree RUL-027 python scripts/check_prod_tree_separation.py page
prolog-boundary structure A Python Prolog query aimed at a predicate/arity that does not exist in the consulted rule base see page python scripts/check_prolog_boundary.py page
prolog-gate policy-as-rules A Key-Rule violation (relative import, bare os.environ[...], banned import, infra default) — proven over a fact base, with 0/1/2 outcomes the CLAUDE.md Key Rules python scripts/gate.py run page
requirement-corpus traceability & loss Production code citing a requirement id the RTM cannot grade (DANGLING) see page python scripts/check_requirement_corpus.py page
ruff correctness / lint A lint violation under the project's ruff configuration RUL-008 uv run ruff check src/ tests/ scripts/ page
test-purity test discipline A mock/fake/stub/monkeypatch/skip in tests, or a banned-library import anywhere RUL-002 python scripts/audit_test_purity.py tests/ --banned-import-only src/ scripts/ page
uncovered-policies policy-as-rules (Advisory) A policy requirement with no enabled mechanism behind it going unseen RUL-014 python scripts/gate.py uncovered page
validate-ci environment A CI configuration that bypasses the canonical runner, hardcodes prod IPs, or breaks any of its 14 hard requirements user ruling 2026-08-03 (requirement 12) python scripts/validate_ci.py page
wiring traceability & loss A capability added by this branch but left inert — a hook registered nowhere, a module reachable from nothing RUL-023 python scripts/check_wiring.py page
worktree-envs environment A worktree whose .venv is a symlink into another checkout's virtualenv RUL-021 python scripts/check_worktree_envs.py --checks venv-symlink page

Counts, verified against scripts/gates.py on 2026-08-29 and again with the AST toolkit on 2026-10-23: 23 GATES registry entries + the __ast__ pre-step = 24 cached gate names. python in the commands is sys.executable, the interpreter running the battery. ruff and mypy run through plain uv run, which in a checkout without UV_NO_EDITABLE=1 can re-sync the venv as an editable install; whether it does here is not measured (see source-provenance).

The three families

Family page Covers Fires
Suite preflight gates source-provenance, parallel-safety (sub-gates 0.1–0.6), test-purity, prolog-boundary, rulings-lint — plus the Redis/Graph/Gateway/Kernel infra checks and the Link check Before every scripts/run_tests.py suite run
.claude session hooks The 32 .sh guards in .claude/hooks/ (30 registered + 2 shared plumbing files) At the moment of action inside a Claude Code session (SessionStart / PreToolUse / PostToolUse / Stop / UserPromptSubmit)
Process-level gates briefs-before-dispatch, evidence-on-landing, author sweep, per-id ledger, fold-verifier, RUL-007 attribution, ADR drift, plugin currency, RUL-022, F13's traceability battery, session honesty, the suite, Mohamed At workflow moments: dispatch, landing, fold, commit, ratification, merge

Reading a battery run

A real battery run prints one line per gate. SKIP lines are cached verdicts being reused ("unchanged since last PASS", with the previous evidence attached); OK/FAIL lines are fresh subprocess runs with a timing and the last lines of output:

[gates] SKIP ruff             unchanged since last PASS   0.1s | All checks passed!
[gates] OK   check-deps        25.0s | Dependency audit (59 declared deps): ✅ All third-party imports are declared in pyproject.toml.
[gates] FAIL prolog-gate       23.5s | ... stale (2): scripts/gates.py (content_changed) ...
[gates] 2 gate(s) in 25.1s wall (21 reused)
[gates] FAILED: prolog-gate

(The OK/FAIL details above are real recorded outputs from .cache/gates.json.)

Where the truth lives

Known gaps (2026-10-23)

Gap Page
The source-provenance message prints identical expected and actual paths for an editable install, so the reader cannot see what is wrong source-provenance
The battery's ruff and mypy, and ship's verify, call plain uv run; the hooks' uv run --no-sync fix (8a2cb42ad) is not pushed workflow improvements
The three user-level hooks are in no repo; a config deploy with rsync --delete removed them on 2026-10-23 commit-precheck
The green ledger keys at module level; RUL-040 asks for a function-level ledger green-ledger
The rehearsal artifact's fingerprint is never checked, and nothing runs derive_test_categories.py --check rehearsal-exclusion
require-design-before-build.sh matches the subagent type by exact name, so orchestrata:builder dispatches are not checked dispatch-brief
The last ten GitLab pipelines failed within about a second; the cause is not measured ci-pipeline
The infra-drift gate is red since 2026-10-20 and its timer is disabled fleet-drift
Battery cache blind spots: env/*.env, deploy/systemd units, .j2 and .envrc files and git state are outside the fingerprints of the gates that read them (derived from the code, not measured) the affected gate pages, for example plugin-drift, prod-separation
validate-ci fingerprints docker/Dockerfile.ci but reads docker/docker-compose.yml validate-ci
proportionate-test-scope.sh still reads an escalate field that the affected oracle no longer returns since 2669f4882 (derived from the code, not run) family-session-hooks
The wiring gate's W1 check expects repo-level .claude/settings.json registrations, which RUL-035 forbids; needs a ruling wiring