test(inference): the optional-runtime boundary is asked in a fresh interpreter - #505
Merged
Merged
Conversation
…terpreter `test_configuring_a_connection_reaches_no_model_runtime` ended on a `sys.modules` assertion, which is a fact about the whole process rather than about the code under test. Where the local-inference extra is installed, the inference tests import the runtime for their own reasons long before `tests/kernel` is collected, so a full `uv run pytest` failed for every contributor carrying it — the one environment in which the assertion means anything. The transitive half of the claim moves to `tests/architecture/test_optional_runtime.py`, where the fresh-process precedent already lives and where CI's inference-smoke job runs it with the runtime present. It now drives the real configure path — open a workspace, write a connection, read it back — in an interpreter that has imported nothing else, so the answer is about the import graph rather than about collection order. The source-level half stays in the kernel test, which is all a test sharing the suite's process can honestly ask. Three fixtures cited the old test as their reason for faking the post-download config read. That reason is gone; the surviving one is measured and stated instead.
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.
test_configuring_a_connection_reaches_no_model_runtimeended on aprocess-global assertion —
sys.modulesbelongs to the run, not to the codeunder test — so with the
local-inferenceextra installed it was decided bywhatever ran before it.
tests/inferencesorts first and imports the runtime forits own legitimate reasons, so the answer was already fixed by the time
tests/kernelwas collected.Tests only: five files under
tests/, no change undersrc/orfrontend/.Reproduced first, at
5b623e3withuv sync --locked --extra local-inferenceThat pair is the defect: no contributor carrying the extra could run the suite
green — the one environment in which the assertion means anything.
The fix — the same claim, asked where the answer is about the code
The assertion was right and its scope was wrong, so nothing here weakens it.
The transitive half moves to
tests/architecture/test_optional_runtime.pyastest_configuring_a_connection_loads_none_of_it_either, followingtest_kernel_purity.py's mechanism exactly —subprocess.run([sys.executable, "-c", probe]), assert on the return code — and the probe now drives the realpath rather than an import: open a workspace,
create()a local connection, readit back, then ask
sys.modules. The forbidden set isMODULES, the same singlesource of truth the neighbouring probes use, rather than a hand-copied subset of
three.
tests/architecture/is not just where the precedent lives — it is the onlyplacement that keeps the test meaningful in CI. The
inference-smokejob addedby #490 names
tests/architecture/test_optional_runtime.pyin its file list anddoes not run
tests/kernel/at all. A fresh-process test left in the kernel filewould have run only in the
pythonjob, which installs no extra and where theassertion is true by construction — order-immune and vacuous everywhere. Moving
it is what puts it in front of an installed runtime.
The source-level (AST) half stays in
tests/kernel/test_inference_connections.py,which is all a test sharing the suite's process can honestly ask. Its docstring
now says why the other half left and that it does not belong back — the failure
mode here is somebody re-adding one convenient line.
No ordering trick. No
pytest.mark.order, nosys.modulesscrubbing fixture,no file moved to collect first.
The require-var interaction: none, verified, and unchanged
VISIONSET_REQUIRE_LOCAL_INFERENCEnever touched this test.git grepovertests/shows every consumer ofrequire_local_inference/without_the_extra,and neither the kernel test nor
test_optional_runtime.pyis among them — bothare unconditional, and both stay unconditional. With the extra the new test is
meaningful; without it, true by construction. #490's flip test
(
tests/inference/test_runtime_gate.py) is green in both full-suite runs below.Acceptance criterion — three conditions, none traded for another
1. Full suite, extra installed — the run that was failing:
2. Full suite, base environment (
uv sync --locked, extra removed andabsence verified via
importlib.util.find_specon all five modules):3. Non-vacuity — below.
Mutation verification
Committed before the first mutation; each applied by a script asserting its
anchor appears exactly once and that the replacement landed; each reverted by
git apply -Ron its own captured diff, withgit statusverified empty after.M1 — the configure path itself imports the runtime.
import torchinsideInferenceConnectionService.create:M2 — the one that proves the new test earns its place. A module-level
import torchinvisionset/kernel/adapters/_mappers.py, which the servicereaches transitively and which the surviving AST half does not parse:
The kernel test stayed green under M2. The subprocess test is not redundant
with the half that stayed behind; it catches a class of regression the AST read
structurally cannot see.
M2 again, under suite context —
tests/inference tests/architecture tests/kernel/test_inference_connections.pyin one process, so the parent hasalready imported the runtime before the probe runs:
Red with and without suite context, and green with and without it. The answer no
longer depends on collection order in either direction.
The three fixtures — measured, not reverted
Three fixtures faked the post-download config read and named this test as their
reason. That reason is gone, so the question was whether they could go with it.
They cannot, and the evidence is a measurement rather than a judgement — a
session-scoped plugin reporting which runtime modules the run imported, with the
fake neutralised and then restored:
The tests pass either way —
_family_if_it_can_be_readswallowsLocalInferenceUnavailable, and an unreadable config is""byfamily_of's owncontract — so the fakes are not load-bearing for any assertion. What they buy is
that the file costs the same in both halves of the matrix: unfaked, it drags in
the whole runtime and runs 5× slower, but only on machines carrying the
extra. That is the same divergence the adjacent
_the_size_lookup_is_fakeddocstrings already call "the worst kind of intermittent".
So all three fakes stay and their dead paragraph is replaced by the reason that
survives. Leaving them citing a claim this PR relocates would have been a stale
rationale pointing at a test that no longer makes it.
One departure from the dispatch, and one clarification
tests/architecture/test_optional_runtime.py::test_configuring_a_connection_reaches_no_model_runtime.No such test existed there; the failing test was in
tests/kernel/test_inference_connections.py:336, as test_configuring_a_connection_reaches_no_model_runtime asserts a process-global fact, so a full run fails wherever the extra is installed #501's own reproductionsays. The design is unaffected — that file is where the fix lands — but the
starting point is worth stating plainly.
proved unusable. It did not;
test_kernel_purity.py's mechanism transferredwithout modification.
Test plan
Every stage run in the worktree on Node 24; exit codes verbatim.
uv run pytest— extra installed3139 passed, 14 skipped— exit 0uv run pytest— base environment3140 passed, 13 skipped— exit 0ruff check ./ruff format --check .364 files already formattedmypy src/visionset/kernel/mypy src/visionsetlint-importsexport_openapi.py+git diff --exit-code openapi.jsonexport_mcp_tools.py --checkpnpm -r buildpnpm testpnpm -r lintbash scripts/check.sh browserPASSED ran=browser— 95s annotator+app e2e, 20s real-server cycle — exit 0Both browser suites were run, so no suite is skipped and no justification is
claimed. The counts differ between the two pytest environments by design:
without_the_extratests run in the base environment and skip where the runtimeis present, and the CUDA test skips only where there is no device.
Found, not fixed
pnpm -r buildbeforepnpm test:@visionset/annotatorresolves to its
dist, so 22 ui-core files fail to transform until it exists.An environment condition, not a defect in this diff — recorded because the
failure reads as a broken import rather than as a missing build.
cf. #418, #490Closes #501