Refuse to run the suite against a different checkout's engine - #437
Merged
Conversation
) The suite could report a full green about source nobody was editing, and the case where it happened is the one where a green matters most: reviewing a pull request in a git worktree. `pythonpath = [".", "tools"]` excludes `src` (#398), so the engine is importable only through the installed package -- which records ONE absolute path, the checkout where `uv sync` last ran. Point another checkout's interpreter at a worktree and `pythonpath = ["."]` collects the worktree's tests while `deltatrack` still resolves elsewhere. Red-green then proves nothing: reverting the file under review changes nothing the run can see. Measured before the guard existed: a top-level `raise RuntimeError` appended to a worktree's src/deltatrack/bill_tree.py left tests/test_bill_tree.py at 133 passed. The fault was unreachable code as far as that run was concerned. AGENTS.md already claimed this "fails loudly on the first import rather than silently reading the main checkout's source". That was true only for a worktree with NO environment; supplying an interpreter was the loophole, and nothing enforced the claim. This makes the claim true and records the loophole beside it. Rejecting the violation rather than adding `src` to `pythonpath`, which would resolve the engine off disk and make the symptom disappear. NOT for wheel fidelity: under an editable install the suite already reports on the working tree, which is precisely why tests/test_engine_installs.py exists and says so in its own docstring. The reason is import uniformity -- `pythonpath` would make pytest the only consumer with its own resolution story, so an env-less worktree would quietly pass against itself while `./diff_bill.py` beside it imported another checkout or failed. A split brain is worse than a hard stop, and the stop names the real problem instead of papering over one symptom of it. The check lives at conftest import rather than in a test: a test asserting this would itself be collected by the wrong-tree run and could only show that the WRONG tree agrees with itself. It anchors on this checkout's root, not pytest's rootdir, which is what keeps test_corpus_manifest.py's child sessions (rootdir = tmp_path) from tripping it. Second branch, same root cause: when the editable install points at a deleted path, every run died at `ModuleNotFoundError: No module named 'deltatrack'`, which reads as "this branch broke the package". It now names the stale pointer and the repair -- but ONLY for the engine's own top-level name. A failure from inside the engine (a typo'd `deltatrack.something`) is a fault in the branch and is re-raised untouched, because pytest prints conftest import errors without the `raise ... from` chain, so rewriting it would have hidden the real module name entirely and sent a developer with a healthy environment to their venv. Two tests, because the guard is silent when it passes and each covers a different way of going quiet. `engine_is_foreign` is unit-tested (verified by neutering it to `return False`), including a sibling directory sharing a name prefix, which is where a path comparison differs from a string one. And a child pytest session with a fabricated foreign engine on PYTHONPATH pins that conftest still CONSULTS the rule -- verified by deleting the call: the unit test stayed green while that one failed, which is the fail-open it exists to close. Verified against the known-bad setup, not by the suite passing (it passed before): from a worktree using another checkout's interpreter the run now stops naming both paths, where it previously reported 133 passed. Both correct setups still work and see the worktree's own code -- its own `uv sync` environment, and `PYTHONPATH=$PWD/src` as a one-off escape hatch that satisfies the guard by making the import correct rather than bypassing it. Refs #398, #401 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…435) Review of the original guard surfaced four gaps. All four are in the same area: the guard was correct for the direction it was written against, and quiet about an adjacent one. - `engine_is_foreign` compared against the checkout ROOT, but a worktree of this repository lives inside the checkout that owns it (`.claude/worktrees/<name>`). A root comparison reads such a sibling working tree as "this checkout" and stays silent. Measured: with an engine copy at `<root>/.claude/worktrees/other/src`, the run imported it and the guard said nothing. Anchoring on `root/src` closes that, and also rejects a non-editable install under `<root>/.venv/`, a snapshot that equally cannot see an edit to `src/`. - The ModuleNotFoundError message recommended `uv pip install -e . --no-deps`. `uv pip` resolves an activated VIRTUAL_ENV ahead of the checkout you are standing in, and otherwise walks up parents, so a developer reading that message from a worktree is led to re-point the shared environment at it: the trap the neighbouring AGENTS.md bullet names, and the state the anchor change above had to be made to see. It now names `uv sync`, which targets the cwd project's own `.venv` from either seat. - That handler had no test in either direction. Two child-session tests now pin them. Neither can fail open (the handler runs only when the import has already failed), so what they protect is the diagnostic, not the gate. - The comment justifying import-time placement argued that a guard test would be "collected by the wrong-tree run". It would not: the tests come from the tree under test, so such a test would be collected correctly and would fail correctly. The load-bearing reason is selection -- `pytest tests/test_bill_tree.py` never collects a guard test at all, and that single module run is the scenario this issue measured. Closes #435 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Nitjsefnie
added a commit
to Nitjsefnie-OSC/DeltaTrack
that referenced
this pull request
Aug 3, 2026
Resolve the import conflict in src/deltatrack/diff_bill.py by keeping both intents: develop's amount_text import (from AgoraDMV#421/AgoraDMV#437 work) alongside this branch's version_stems imports (local_versions, resolve_version_file) for slug/ordinal version addressing. Co-Authored-By: Kimi K3 <noreply@kimi.com>
Nitjsefnie
pushed a commit
to Nitjsefnie-OSC/DeltaTrack
that referenced
this pull request
Aug 3, 2026
…MV#439) The wrong-tree guard (AgoraDMV#437, closing AgoraDMV#435) ran its foreignness check AFTER conftest imported two submodules off the engine. An engine that is importable as `deltatrack` but whose layout does not match this tree therefore died at the submodule import, and that exception is a `ModuleNotFoundError` named `deltatrack.bill_tree`, which the handler correctly re-raises untouched because by its `exc.name != "deltatrack"` test it genuinely is a branch fault. The run read as a broken branch and the guard's message never appeared, sending the developer to inspect their own changes over an environment fault. This cannot produce a false green -- the session is red either way, so AgoraDMV#435's property still held. What is at stake is the diagnostic, which is what AgoraDMV#437's own follow-up treated as worth two tests. The check now runs on `import deltatrack` alone, before anything is imported off the engine. `engine_is_foreign` moves to tests/engine_guard.py so it is defined above the code that calls it without pushing conftest's engine imports below a function body; keeping the check inside the existing `try` leaves the import block contiguous, so no E402/I001 suppression is needed (verified with `ruff check`). tests/test_fixture_layout.py follows the move. Exposure is narrow today: both submodules named are long-standing. It widens with the import list -- nothing holds it at two, and the first change that adds a third makes this reachable for anyone reviewing THAT change from a worktree against a shared environment, the workflow the guard exists to protect. Verified against the known-bad case from the issue: a stand-in engine importable as `deltatrack` from outside the checkout and missing `bill_tree`, on PYTHONPATH so it wins over the editable install. Before, `ModuleNotFoundError: No module named 'deltatrack.bill_tree'`; after, the guard's RuntimeError naming both trees. Pinned by test_conftest_refuses_a_foreign_engine_before_reading_its_layout. _BRANCH_FAULT moves its fault into the stand-in's `__init__.py`. Every stand-in here is foreign by construction, which is how PYTHONPATH makes one reproducible, so a submodule fault is now preempted by the foreign-engine error and that test would have pinned nothing. The preemption is correct where the two coincide: a broken import inside an engine from another checkout is still the environment's fault. A fault in the tree under test is not foreign and reaches the submodule imports as before, and an `__init__` reaching for a missing module is the shape the `exc.name` discrimination exists for. Closes AgoraDMV#439 Refs AgoraDMV#435, AgoraDMV#437 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related issue
Closes #435
What does this change?
The test suite could report a full green about source nobody was editing. It happened in
the situation where a green matters most: reviewing a pull request in a git worktree.
pyproject.tomlsetspythonpath = [".", "tools"]and excludessrcon purpose (#398),so the engine is importable only through the installed package, which records one
absolute path — the checkout where
uv synclast ran. Point another checkout'sinterpreter at a worktree and
pythonpath = ["."]collects that worktree'stests/whiledeltatrackstill resolves somewhere else entirely. Red-green verification then provesnothing, because reverting the file under review changes nothing the run can see.
Measured before the guard existed. A top-level
raise RuntimeErrorappended to aworktree's
src/deltatrack/bill_tree.py, then run with another checkout's interpreter:The injected fault was unreachable code as far as that run was concerned.
AGENTS.mdalready asserted that this "fails loudly on the first import rather thansilently reading the main checkout's source." That held only for a worktree with no
environment. Supplying an interpreter was the loophole, and nothing enforced the claim.
This makes the existing claim true and records the loophole beside it.
Why not just add
srctopythonpathThat one-line change would make the symptom disappear, and it is the obvious fix. It is
not the right one, but not for the reason that first suggests itself: under an editable
install the suite already reports on the working tree rather than the distribution, which
is exactly why
tests/test_engine_installs.pyexists and says so in its own docstring.Wheel fidelity is not what the
srcexclusion buys.What it buys is one import-resolution story. Putting
srconpythonpathwould makepytest the only consumer that resolves the engine differently from everything else, so an
env-less worktree would quietly pass against its own code while
./diff_bill.pysittingbeside it imported another checkout or failed outright. A split brain is worse than a hard
stop, and the stop names the actual problem — a tree running against a foreign environment
— instead of papering over the one symptom that happened to surface.
Changes
tests/conftest.py— refuses to run whendeltatrackresolves outside thischeckout's root, naming both paths. Anchored on the checkout root rather than pytest's
rootdir, which is what keeps
test_corpus_manifest.py's child sessions (rootdir =tmp_path) from tripping it.Second branch, same root cause: when the editable install points at a deleted path, runs
previously died at
ModuleNotFoundError: No module named 'deltatrack', which reads as"this branch broke the package." It now names the stale pointer and the repair — but
only for the engine's own top-level name. A failure from inside the engine (a typo'd
deltatrack.something) is a fault in the branch and is re-raised untouched.tests/test_fixture_layout.py— two tests, because the guard is silent when itpasses and there are two different ways for it to go quiet.
AGENTS.md— the worktree convention, the loophole, and the rule that an editableinstall must never be run from a worktree against a shared
.venv.The check lives at conftest import rather than in a test on purpose: a test asserting this
would itself be collected by the wrong-tree run, and could only demonstrate that the wrong
tree agrees with itself.
How to test
The suite passed while the defect was active, so "tests pass" cannot demonstrate this fix.
Each claim was verified against the known-bad setup.
The guard fires where the suite previously went green:
Both correct setups still work, and now actually see the worktree's code. With the same
injected fault in place, a worktree using its own
uv syncenvironment and a run usingPYTHONPATH=$PWD/srcboth fail on the fault itself, atsrc/deltatrack/bill_tree.py: RuntimeError: FAULT INJECTED IN WORKTREE. The escape hatchsatisfies the guard by making the import correct, not by bypassing the check.
The branch's own broken imports are not misreported. Injecting
from deltatrack.missing_helper import Oopsinto the engine now surfacessrc/deltatrack/bill_tree.py:1: ModuleNotFoundError: No module named 'deltatrack.missing_helper'rather than an environment message. This matters because pytest prints conftest import
errors without the
raise ... fromchain, so rewriting the exception would have hidden thereal module name completely.
Both tests were shown to fail.
engine_is_foreignwas neutered toreturn False,which reddens the unit test. Separately the guard's three calling lines were deleted: the
unit test stayed green while the child-session test failed, which is the fail-open that
test exists to close.
All five CI gates on this branch:
1415 against a 1413 baseline: the two new tests. Skips are pre-existing.
Breaking changes
None for any current workflow. The guard is stricter by design: a run whose engine does not
come from this tree's own
src/now stops instead of reporting. Two setups it would newlyreject, neither of which anything in this repo does today:
layout). Called out rather than silently accepted — if such a workflow is adopted, the
guard needs an explicit exemption at that point.
.venv/. That is a copied snapshotwhich cannot see an edit to
src/, so it is the same wrong-tree green from closer range.uv sync,uv runandsource ./initall produce an editable install, so no documentedpath reaches this state.
An editable install into an external environment is unaffected, since its pointer still
resolves into the checkout's
src/.Known limitations
deltatrack.__file__beingNone, which exotic namespace-package resolution can produce,would raise a bare
TypeErrorrather than a clear message. Left alone rather than addinghardening for a case that could not be reproduced.
Checklist
Closes #...)AI assistance
Written with Claude Code, and reviewed by a second model before this pull request was
opened. That review caught two defects in the first version, both fixed here and both
reproduced independently before being acted on: the error handler misreported a branch's
own broken import as an environment fault, and the guard's wiring was unpinned so deleting
three lines would have restored the silent green with every test still passing. It also
correctly refuted the original justification for rejecting the
pythonpathfix, which iswhy the reasoning above rests on import uniformity rather than on wheel fidelity.
Follow-up commit: review findings resolved
A review of the first commit raised four items, all resolved in
bec302b. Each wasreproduced before being acted on, and each fix was shown to redden exactly one test.
The guard was blind to the worktree layout this repo actually uses.
engine_is_foreigncompared against the checkout root, but a worktree lives inside the checkout that owns
it (
.claude/worktrees/<name>), so a root comparison reads a sibling working tree as "thischeckout". Measured: with an engine copy at
<root>/.claude/worktrees/other/src, the runimported it and the guard said nothing. It is reachable through the footgun the AGENTS.md
bullet above it names —
uv pipresolves an activatedVIRTUAL_ENVahead of the checkoutyou are standing in, and otherwise walks up parents, so an editable install run from a
nested worktree re-points the shared environment at it. Now anchored on
root/src, whichalso rejects a non-editable install under
<root>/.venv/.The repair advice led to that same state. The
ModuleNotFoundErrormessage recommendeduv pip install -e . --no-deps— the one command that is dangerous from the other realisticseat, and the repo's only recommendation of it (
init, AGENTS.md and theRuntimeErrortwenty lines below all say
uv sync). It now namesuv sync, which targets the cwdproject's own
.venvfrom either seat. The "why not the other one" reasoning moved into thecode comment: someone stuck at that error needs one action, not the argument.
That handler had no test in either direction. Two child-session tests now pin them:
an absent engine is reported as an environment fault with a safe repair, and a broken import
inside the engine reaches the developer with its module name intact. Neither can fail open
— the handler runs only when the import has already failed, so the session is red either way
— so what they protect is the diagnostic, not the gate. That is stated in both docstrings so
the next reader does not mistake them for fail-open gates.
The comment justifying import-time placement did not hold. It argued a guard test "would
itself be collected by the wrong-tree run"; it would not, since the tests come from the tree
under test, so such a test would be collected correctly and fail correctly. The load-bearing
reason is selection:
pytest tests/test_bill_tree.pynever collects a guard test at all, andthat single-module run is the scenario this issue measured. The placement was right, only the
stated reason was wrong — which matters, because someone who correctly rebuts a wrong
rationale might move the guard into a test file and reopen the hole.
Verification
Both directions proven end to end, in a worktree nested at
.claude/worktrees/:Each new assertion was shown to fail against the fault it claims to catch, scoped so that
exactly one test reddens and the rest stay green:
/srcanchortest_the_foreign_engine_rule_can_fireuv pip install -e .as the repairtest_conftest_names_a_broken_environmentModuleNotFoundErroras an environment fault..._does_not_blame_the_environment_for_a_branch_faultGates on
bec302b, exit codes captured directly rather than read off the summary line:ruff check0,ruff format --check0, fast suite 0 (1411 passed, +2 for the new tests),external validation 0 (33), corpus gates 0 (360), remaining slow suites 0 (155), packaging
gate 0 (6). Run from a worktree, which does not carry the fetched
bills/corpus, so thefast-suite count sits 6 below a main-checkout run; every one of those is a corpus-gated skip
naming a missing fetched file.