Skip to content

test(inference): the optional-runtime boundary is asked in a fresh interpreter - #505

Merged
JArmandoAnaya merged 1 commit into
mainfrom
test/optional-runtime-fresh-process
Aug 10, 2026
Merged

test(inference): the optional-runtime boundary is asked in a fresh interpreter#505
JArmandoAnaya merged 1 commit into
mainfrom
test/optional-runtime-fresh-process

Conversation

@JArmandoAnaya

Copy link
Copy Markdown
Contributor

test_configuring_a_connection_reaches_no_model_runtime ended on a
process-global assertion — sys.modules belongs to the run, not to the code
under test — so with the local-inference extra installed it was decided by
whatever ran before it. tests/inference sorts first and imports the runtime for
its own legitimate reasons, so the answer was already fixed by the time
tests/kernel was collected.

Tests only: five files under tests/, no change under src/ or frontend/.

Reproduced first, at 5b623e3 with uv sync --locked --extra local-inference

$ uv run pytest
FAILED tests/kernel/test_inference_connections.py::test_configuring_a_connection_reaches_no_model_runtime
1 failed, 3137 passed, 14 skipped in 196.13s

$ uv run pytest tests/kernel/test_inference_connections.py::test_configuring_a_connection_reaches_no_model_runtime
1 passed in 0.23s

That 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.py as
test_configuring_a_connection_loads_none_of_it_either, following
test_kernel_purity.py's mechanism exactly — subprocess.run([sys.executable, "-c", probe]), assert on the return code — and the probe now drives the real
path rather than an import: open a workspace, create() a local connection, read
it back, then ask sys.modules. The forbidden set is MODULES, the same single
source 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 only
placement that keeps the test meaningful in CI.
The inference-smoke job added
by #490 names tests/architecture/test_optional_runtime.py in its file list and
does not run tests/kernel/ at all. A fresh-process test left in the kernel file
would have run only in the python job, which installs no extra and where the
assertion 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, no sys.modules scrubbing fixture,
no file moved to collect first.

The require-var interaction: none, verified, and unchanged

VISIONSET_REQUIRE_LOCAL_INFERENCE never touched this test. git grep over
tests/ shows every consumer of require_local_inference / without_the_extra,
and neither the kernel test nor test_optional_runtime.py is among them — both
are 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:

$ VISIONSET_REQUIRE_FFMPEG=1 uv run pytest -rs
3139 passed, 14 skipped in 190.55s   EXIT=0

2. Full suite, base environment (uv sync --locked, extra removed and
absence verified via importlib.util.find_spec on all five modules):

$ VISIONSET_REQUIRE_FFMPEG=1 uv run pytest
3140 passed, 13 skipped in 186.84s   EXIT=0

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 -R on its own captured diff, with git status verified empty after.

M1 — the configure path itself imports the runtime. import torch inside
InferenceConnectionService.create:

FAILED tests/architecture/test_optional_runtime.py::test_configuring_a_connection_loads_none_of_it_either
FAILED tests/kernel/test_inference_connections.py::test_configuring_a_connection_reaches_no_model_runtime
2 failed, 59 passed

M2 — the one that proves the new test earns its place. A module-level
import torch in visionset/kernel/adapters/_mappers.py, which the service
reaches transitively and which the surviving AST half does not parse:

FAILED tests/architecture/test_optional_runtime.py::test_configuring_a_connection_loads_none_of_it_either
AssertionError: configuring a connection pulled in the optional runtime: {'torch'}
3 failed, 58 passed

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 contexttests/inference tests/architecture tests/kernel/test_inference_connections.py in one process, so the parent has
already imported the runtime before the probe runs:

FAILED tests/architecture/test_optional_runtime.py::test_configuring_a_connection_loads_none_of_it_either
3 failed, 261 passed, 3 skipped

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:

tests/jobs/test_weights_job.py, fake neutralised:
  RUNTIME MODULES IMPORTED BY THIS RUN: ['huggingface_hub', 'torch', 'transformers']
  7 passed in 1.66s

tests/jobs/test_weights_job.py, fake restored:
  RUNTIME MODULES IMPORTED BY THIS RUN: none
  7 passed in 0.33s

The tests pass either way — _family_if_it_can_be_read swallows
LocalInferenceUnavailable, and an unreadable config is "" by family_of's own
contract — 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_faked
docstrings 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

Test plan

Every stage run in the worktree on Node 24; exit codes verbatim.

Stage Result
uv run pytestextra installed 3139 passed, 14 skipped — exit 0
uv run pytestbase environment 3140 passed, 13 skipped — exit 0
ruff check . / ruff format --check . exit 0 / 364 files already formatted
mypy src/visionset/kernel / mypy src/visionset 63 files / 153 files — exit 0
lint-imports 4 contracts kept, 0 broken — exit 0
export_openapi.py + git diff --exit-code openapi.json no drift — exit 0
export_mcp_tools.py --check no drift — exit 0
pnpm -r build exit 0
pnpm test 77 node tests, 406 ui-core tests — exit 0
pnpm -r lint exit 0
bash scripts/check.sh browser PASSED ran=browser — 95s annotator+app e2e, 20s real-server cycle — exit 0

Both 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_extra tests run in the base environment and skip where the runtime
is present, and the CUDA test skips only where there is no device.

Found, not fixed

  • A fresh worktree needs pnpm -r build before pnpm test: @visionset/annotator
    resolves 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, #490

Closes #501

…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.
@JArmandoAnaya
JArmandoAnaya merged commit df44bc6 into main Aug 10, 2026
14 checks passed
@JArmandoAnaya
JArmandoAnaya deleted the test/optional-runtime-fresh-process branch August 10, 2026 10:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

test_configuring_a_connection_reaches_no_model_runtime asserts a process-global fact, so a full run fails wherever the extra is installed

1 participant