Home / Projects / Orchestrata Ultimate / Decisions / ADR index / ADR-0120

ADR-0120: Test-spawned subprocesses import from the installed environment, never the source tree

field value
Status Accepted — Accepted (ruling, Mohamed, 2026-10-20)
Date 2026-10-20
Register factory (docs/adr, 4-digit ids)
Source docs/adr/0120-test-subprocesses-import-from-installed-environment-never-source-tree.md — permalink at 62da20306 (unchanged on master since that commit)
Wiki register entry ADR-0120 (wiki status: Accepted)

← ADR-0119 · ADR-0121 →

The record

Status: Accepted (ruling, Mohamed, 2026-10-20) · Date: 2026-10-20

Context

The proper-install campaign (dd919d55c) made both repos install non-editable, PEP 610-verified, with the .envrc PYTHONPATH export removed and the import-shadow mechanism landed (codetools bc7c2b6: root conftest refusal + batch-runner child-env sanitization). The §5.4 coupling measurement then found the same hazard kept alive in miniature inside three test files: their kill-child subprocesses run

sys.path.insert(0, sys.argv[1])   # argv[1] = repo/src
from codetools.deploy import ...

i.e. the child imports the working tree instead of the installed artifact. Sites: tests/deploy/test_atomic_promote.py:51, tests/deploy/test_install.py:35, tests/bdd/steps_spec012_fixtures.py:22. L26 names the general class: a green proof is only as good as the import resolution it ran under — and the child's resolution is part of the proof.

Mohamed's forcing question: "What is the professional best practice, not the band aid, what is the RIGHT way?"

The answer: children import from the environment like production does; freshness is a runner-level invariant (his §5.3 ruling — the installed artifact is a versioned copy into /opt|/lib, never in-place, never a path in the dev directory, staleness hard-fails), never a per-test path hack.

Decision (Mohamed, 2026-10-20, verbatim)

"yes and create an adr that applies this to all future cases like this"

Implemented as: a test-spawned subprocess must resolve the packages under test from the installed environment (the venv's site-packages), exactly as production resolves them — it must never insert the repository's source directory into sys.path or PYTHONPATH. Freshness of the installed copy is enforced by the runner-level staleness guard (the §5.3 ruling), not by per-test path surgery. Where a child simulates a production process it invokes the production entrypoint (console script or python -m pkg.module); a synthetic -c shim is permitted only where the test structurally needs the child's PID (e.g. to SIGKILL it mid-flight at a random offset). The three named KILL_SCRIPT sites are repointed under this rule, and the removal of their sys.path inserts is paired with the §5.3 staleness guard landing — the two travel together as acceptance criteria of the same packet, never alone.

Alternatives rejected

Consequences

Provenance

Mohamed, in-session, 2026-10-20, session 272 (quotes above, verbatim). Forcing question: "What is the professional best practice, not the band aid, what is the RIGHT way?" Preceding §5.3 ruling, verbatim: "version and deploy properly, no deploy in place and path not in the dev directory". Evidence: the §5.4 coupling measurement table (session 272 work log); plans/handoff-2026-10-20-proper-install.md §5.4; docs/lessons/L26-import-shadow-contaminated-proof.md; proper-install commit dd919d55c; import-shadow mechanism codetools bc7c2b6.

No other ADR is named in this record.

Rulings cited

None.

Specs cited

None (or no spec page exists for the ones named).