Orchestrata Ultimate › Gates › parallel-safety

Gate: parallel-safety

At a glance

Purpose Refuse test code that will collide under parallel execution, found statically by six sub-gates (0.1–0.6) without running a test.
Where it runs The scripts/gates.py battery (registered as parallel-safety) and the suite preflight _run_gates() in scripts/run_tests.py.
Trigger A battery run whose tests/ fingerprint changed; every suite run's preflight.
Exact command python scripts/gate_parallel_safety.py (--gate 0.N, --json, --strict, --tests-dir PATH)
Blocks Exit 1 when any blocking sub-gate (0.1, 0.2, 0.3, 0.4, 0.6) has a finding; 0.5 is advisory unless --strict. Exit 0 otherwise.
Ruling / ADR User ruling 2026-07-10, "no violations allowed" (quoted in the _run_gates() docstring); none recorded as a RUL page or ADR. Neighbouring: RUL-001, RUL-002.
Last recorded verdict ok: true in the primary checkout's .cache/gates.json (file last written 2026-09-22 10:01 local). wt-MAP-PRECOMMIT has no .cache/gates.json.

Diagram projects-orchestrata-ultimate-gates-parallel-safety-1

What it refuses

A test pattern that is guaranteed to collide when the suite runs in parallel: an unscoped Cypher CREATE on a constrained label, a global DETACH DELETE, a session-scope fixture holding mutable state, an un-namespaced Redis write, a shared port disguised as a wait loop.

Why it exists

Module docstring:

"Gate: Parallel Safety Audit — deterministic static analysis for test flakiness. …gates that detect guaranteed parallel collisions without running tests. Each gate finds patterns that WILL cause failures under parallel execution (threadpool runner, multiple workers sharing the graph/Redis/filesystem)."

The suite runs 8 workers over shared real infrastructure (no mocks), so isolation is carried by conventions — test_id properties on graph nodes, test_id-namespaced Redis keys, function-scope fixtures, per-test tmp dirs. This gate makes those conventions mechanical. A single originating incident is not recorded in the module docstring — origin not recorded in the source beyond the flakiness class it names.

The sub-gates (0.1–0.6, from the script's own section markers)

Sub-gate Detects Blocking?
0.1 Cypher CREATE on a constrained label (File, Project, Module, Intent, Session, Spec, Artifact, Portfolio, WorkItem, Checkpoint, Verification, Run, Requirement) without a test_id: property yes
0.2 Cypher DETACH DELETE / global edge DELETE without scope yes
0.3 Session-scope fixtures (mutable state shared across tests — the repo law is "function-scope fixtures only") yes
0.4 Redis writes without test_id namespacing yes
0.5 Filesystem writes outside isolation ADVISORY — the script's own note: "Gate 0.5 (filesystem) is ADVISORY: static analysis cannot prove a write target"
0.6 wait-for-port guards — "a shared port wearing a disguise" yes

How it runs

Waivers

From the docstring — the one battery gate with a disciplined waiver channel:

"A finding on a line carrying (or directly below) a # gate-ok: <reason> comment is suppressed. This exists for tests whose FIXTURE DATA is deliberately-unsafe Cypher/source fed to a tool under test (preflight checker, isolation auditor, code reviewer) — the string is analyzed, never executed. A reason is required; a bare # gate-ok: does not waive."

Two readers apply the convention inside this script (refs through the AST toolkit, 2026-10-23). An earlier version of this page said the shared core.gate_waivers.waived_lines was the one reader; in the code it serves sub-gate 0.4 only. Sub-gates 0.1, 0.2, 0.5 and 0.6 call the script's own _is_waived(), whose regex #\s*gate-ok:\s*\S checks the flagged line and the line above it, so a bare tag does not waive there either. No waiver call was found in the 0.3 session-fixture audit.

Typical failures and how to fix them

Wiring