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) |
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
- Accept the
sys.pathinserts as-is (recorded adjudication): keeps children testing the working tree, diverging from what ships; recreates the silent-staleness hazard the campaign exists to eliminate. - Repoint without the staleness guard: swaps one staleness hazard (child importing a stale installed copy) for the one the insert papered over — the band-aid trade; rejected by the pairing clause.
- Per-test mtime freshness checks: false-positive on every checkout; superseded by §5.3's content/version guard at the runner.
Consequences
- New test subprocesses that import the repo's packages resolve them from the installed environment; a new
sys.path/PYTHONPATH-into-source site is a defect, caught by the existing import-shadow guard, the batch-runner child-env sanitization, and review. - The three KILL_SCRIPT sites are repointed in a packet whose acceptance criteria include the §5.3 staleness guard in place; the packet may not land the repoints alone.
- L26's contamination class is closed at the subprocess boundary as well as the in-process one.
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.
Related ADRs
No other ADR is named in this record.
Rulings cited
None.
Specs cited
None (or no spec page exists for the ones named).