Orchestrata Ultimate › Plans › briefs › gate-rul038-container-creation
GATE-RUL038 — the Prolog gate clause ADR-0111 owes: no container-creating module under tests/
Source: plans/briefs/gate-rul038-container-creation.md at 8a2cb42ad · last changed 2026-10-20 · first committed 2026-10-20 · 92 lines.
Prose pending.
Plan text
GATE-RUL038 — the Prolog gate clause ADR-0111 owes: no container-creating module under tests/
Task #569, build order 1. Contract: docs/ast-checkable-rules.md §2#3 (the ruled mechanism shape)
- the RUL-038 wiki page (
~/workspace/knowledge-wiki/rulings/RUL-038-test-runs-never-create-containers.md— READ it: the ruling verbatim, the four known violators, the owed Mechanism section) + ADR-0111 (docs/adr/0111-...md). Sequencing note: P-RUL039's derivation pass (scripts/derive_test_categories.py, briefplans/briefs/p-rul039-rehearsal-exclusion.md) detects the SAME argv-marker class — if it has landed when you start, CONSUME/extend its derivation facts instead of rebuilding detection (report which state you found). If it has not landed, build the fact extraction inside this packet's fence in the shape its brief specifies (marker rows with file:line evidence) so the two converge rather than fork.
You are a worker. You do NOT commit. RUL-037. Never xdist. The Prolog gate is policy-shaped: the
rule lives as FACTS + a gate_rules.pl clause, with the EXISTING waiver system — no new waiver
mechanics.
The rule (§2#3, verbatim scope)
Under tests/ ONLY (scope admission already handles tests/-scoped rules — measure how existing
scoped clauses do it and follow): a module FAILS scripts/gate.py run when its AST facts show
- a subprocess-family call (
subprocess.run/Popen/call/check_call/check_output,os.system,os.exec*) whose argv string literals containincus,lxc,docker,terraform, ortofuin ANY arg position, or - an import of a container-client library (measure the set from
.claude/banned-libraries.txt+ the codetools violators' actual imports: e.g.pylxd, docker SDK, incus client wrappers — name the list in your report), or - a shell string passed to those calls containing those binaries (the
bash -c "incus ..."shape).rehearsals/and everything outsidetests/are OUT of scope (ADR-0111: rehearsals deliberately create instances). ERROR severity; waiver via the existing# gate-ok:mechanism on the flagged module's line (measure the waiver system's actual shape in gate_rules.pl/core gate_waivers and use it unchanged — a bare# gate-ok:without a reason waives nothing).
The facts (KB side)
The gate reads the serialized snapshot's Call nodes + string args (plans/ast-ultimate.json covers
tests/ via the wide roots — VERIFY with code_intel.py literals / a jq probe that tests/ Call
facts with argv strings are actually IN the snapshot; if the snapshot lacks argv-literal facts for
calls, that gap is THIS packet's blocker — report it with evidence and propose the minimal
serializer extension BEFORE writing Prolog against absent facts; do not fabricate a fact shape).
Fence
src/orchestrata_ultimate/prolog/gate_rules.pl
tests/prolog/test_gate_rul038.py (NEW — or the existing gate-rules test module's conventions; MEASURE and follow)
scripts/derive_test_categories.py (ONLY if extending the P-RUL039 derivation — coordinate state per the sequencing note)
tests/scripts/test_derive_test_categories.py (same condition)
READ-ONLY: scripts/gate.py, scripts/serialize_codebase_ast.py, the snapshot JSONs,
core/gate_waivers.py (or wherever the waiver logic lives — measure), the four known violators
(three are in the CODETOOLS repo: tests/gate/test_provisioner_scratch_container.py,
tests/incus/live/test_idempotent_ensure.py, tests/bdd/test_spec_013.py creating scenarios;
orchestrata's is tests/harness/test_incus_isolation.py — the incus_live lane +
INCUS_HARNESS_IT=1 round-trip).
Required behavior at landing
gate.py runFAILS (non-zero) on the current tree IF the orchestrata violator is unwaived — the ruling page says the violators must LIGHT UP. The disposition of the lit violator is a COORDINATOR ruling, not yours: propose either (a) a reasoned# gate-ok:waiver on the named lane with the ADR-0111 migration-to-rehearsals/ as the tracked follow-up, or (b) the module's immediate move to rehearsals/ (out of this fence — say so). Do not execute either; report the proposal with the gate output showing the violation.- The codetools three violators: this gate does not run on codetools' tree — report them as the sibling-half debt ADR-0111 names (their repo, their gate run) with the evidence lines. Do not touch the codetools repo.
- Clean modules stay clean:
gate.py runon the pre-packet fact base + your clause → only the named violator(s) as new findings; every other gate verdict UNCHANGED (paste both runs' summary lines; a clause that lights up unrelated modules is a defect).
VERIFY (report verbatim)
.venv/bin/python scripts/gate.py run # pre-change baseline (PASS + clause/fact counts)
.venv/bin/python scripts/gate.py run # post-change: the violator lights up (or the waiver path per ruling)
.venv/bin/pytest tests/prolog/test_gate_rul038.py -o addopts="" -q # pytest-live; real janus, per-test engine (T9)
.venv/bin/python scripts/gate.py run # post-waiver-state: PASS again with the waiver honored (if path (a))
.venv/bin/ruff check <fence .py> && .venv/bin/black --check <fence .py>
Plus: the clause text itself pasted; the fact-shape evidence (a real snapshot row your clause
matches, with the module + argv literal); waiver-mechanism proof (a fixture module with a reasoned
# gate-ok: passes, a bare one fails).
Report
Fence file lists, the fact-shape finding (present/absent + evidence), the clause + its scope
admission shape, the violator light-up output, your disposition proposal (a/b) with argument, the
codetools sibling-half evidence lines, all VERIFY outputs verbatim, anything unfaithful named.
Registration (RUL-038 wiki Mechanism section naming this commit + Enforcement line moving to
gate) is the coordinator's post-verification step.