Repository navigation
pytest.ini's prescribed local invocation is red: autobot-slm-backend alone fails an order-dependent test CI never sees #16075
Description
What
pytest autobot-slm-backend — the local invocation pytest.ini itself prescribes — fails on current Dev_new_gui. CI passes the same tree, because CI's command is not that command.
autobot-slm-backend/services/hf_token_validator_test.py::TestProbeHfTokenValid::test_200_is_valid
E AttributeError: module 'services' has no attribute 'hf_token_validator'.
Did you mean: 'hf_token_validator_test'?
1 failed, 499 passed
The invocations differ, and the difference is what hides it
pytest.ini:64-73 tells a developer to run two invocations, the second being autobot-slm-backend alone. .github/workflows/ci.yml:338-347 runs:
python -m pytest autobot-slm-backend \
-n auto --dist loadscope \
-p repo_tests.stable_shard \
--shard-splits 12 --shard-group N --shard-durations .test_durations_slm \
-m "not integration and not slow and not distributed and not performance"
--dist loadscope keeps a module's tests on one worker and distributes modules across twelve. Sequential collection puts them in a single interpreter in collection order. The failing test is order-dependent, so the two shapes disagree.
Verified against CI rather than assumed: shard 8/12 on 2845e68abb is success with zero FAILED lines, and its log names this exact node — hf_token_validator_test.py::TestProbeHfTokenValid::test_200_is_valid — being handled. CI runs it and it passes there.
Why it fails sequentially
conftest.py real-loads hf_token_validator and binds it onto the services stub, and its own comment says why:
hf_token_validator#14307 — co-located test, same shard-order dependency.
and for its neighbour:
Its co-located test passed only when
tests/services/conftest.pyhappened to be collected first in the same shard, which pytest-split decides.
The binding does not survive another module replacing sys.modules['services'] wholesale. That is not hypothetical — the successful CI shard emits it as a warning:
sys.modules['services'] was replaced by autobot-slm-backend/services/a2a_card_fetcher_test.py
and is STILL INSTALLED while pytest handles ...
Eight distinct owners leak inside that one shard. Under loadscope the collision happens to miss; sequentially it lands.
Why this matters beyond one test
The documented local command is red while CI is green, so a developer following pytest.ini sees a failure that no reviewer can reproduce and no CI run reflects. The natural readings are "my environment is broken" or "base is broken", and both are wrong. That is expensive in the same way the two-range confusion on #16069 was: the output is accurate and answers a different question from the one being asked.
It also means the pre-push hook's fix in #16074 restores CI's path partitioning but not CI's distribution, so a local run can still diverge. #16074 is still correct and still necessary; this is a separate axis.
Acceptance criteria
-
pytest autobot-slm-backendpasses on a clean checkout of base, orpytest.inistops prescribing a command that does not - The specific ordering dependency is removed rather than reordered around — the stub that replaces
sys.modules['services']installs and removes in the sametry/finally, scoped to the nodes that need it - A test fails if
hf_token_validatorresolves to a stub, verified by a mutation rather than by reading (the current failure mode is anAttributeError, but aMagicMockresolution would pass silently) - The eight leaking owners inside the slm-alone shard are enumerated, and each is either fixed or recorded with a reason
Provenance
Observed by a peer session running the two-invocation shape by hand, and explicitly offered as an observation rather than a finding pending a check against CI's invocation. That check is above: it does not reproduce under CI's command, and it does reproduce the documented one. Related: #16069 (conftest stubs escaping their directory), #14307 (the real-load list this depends on), #13084 (the identical-package-name collision).
Activity