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)

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

  1. a subprocess-family call (subprocess.run/Popen/call/check_call/check_output, os.system, os.exec*) whose argv string literals contain incus, lxc, docker, terraform, or tofu in ANY arg position, or
  2. 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
  3. a shell string passed to those calls containing those binaries (the bash -c "incus ..." shape). rehearsals/ and everything outside tests/ 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

  1. gate.py run FAILS (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.
  2. 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.
  3. Clean modules stay clean: gate.py run on 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.