Symptom
Six of twelve unit-tests jobs fail on every branch: ubuntu-latest and windows-latest on 3.10, 3.11 and 3.12. All three macos-latest jobs pass. PRs merge as UNSTABLE because no gate in our review sequence reads CI.
Five failures, identical everywhere:
tests/recall/test_consolidate.py::TestLocalConflictJudge::test_real_judge_classifies_the_founding_pair_as_conflict
AssertionError: None is not true -- got None
tests/recall/test_consolidate.py::TestLocalConflictJudge::test_real_judge_classifies_a_complementary_pair_as_not_conflict
Failed: Unexpected success
tests/recall/test_consolidate.py::TestLocalConflictJudge::test_real_judge_drives_escalation_to_contest_not_silent_resolution_complementary_pair
AssertionError: 'keep_both' != 'contest'
tests/recall/test_consolidate.py::TestLocalConflictJudge::test_real_judge_drives_escalation_to_contest_not_silent_resolution_founding_pair
AssertionError: 'keep_both' != 'contest'
tests/recall/test_supersession.py::TestRecallContradictContestResolution::test_real_contest_then_resolve_then_sync_end_to_end
AssertionError: real judge did not flag the founding pair
This is branch-independent, and the control is the evidence
A docs-only branch fails with the byte-identical five. A documentation change cannot break a model judge, so the failure cannot be coming from anyone's diff. Fourteen consecutive tests workflow runs across nine unrelated branches are all failure.
Root cause: the guard exists and its predicate is lying
Every one of those tests is already guarded:
@unittest.skipUnless(consolidate._MLX_AVAILABLE, "MLX not available (requires Apple Silicon)")
The guard never fires, because MLX_AVAILABLE was computed like this:
try:
from synapt._models.mlx_client import MLXClient, MLXOptions
from synapt._models.base import Message
MLX_AVAILABLE = True
except ImportError:
pass
synapt._models.mlx_client imports mlx_lm and mlx function-locally (_load, _load_fused, chat), never at module scope. So the wrapper imports cleanly on a machine with no backend at all — and mlx-lm is declared only for sys_platform == 'darwin' and platform_machine == 'arm64', so it is absent by design on Linux and Windows.
The predicate asked "does the wrapper import?" when its callers ask "can inference run here?" Those come apart on every non-Apple-Silicon host. Reproduced directly, with a control proving the block took effect:
CONTROL: mlx_lm really present here? True
CONTROL: MLX_AVAILABLE with mlx_lm present = True (correct)
SIM: import mlx_lm -> blocked ok (No module named 'mlx_lm')
SIM: MLX_AVAILABLE with mlx_lm ABSENT = True <-- false positive
So the tests run with nothing behind them, inference returns None, and the suite reports FAILED where the honest answer is SKIPPED.
Wider than the test guards
Nine production call sites read this predicate — enrich.py (5), server.py, consolidate.py (2), cli.py. On Linux and Windows they currently take the MLX path on hosts that cannot execute it, failing at call time instead of returning the install message. Red CI was the symptom, not the defect.
The same defect class with the opposite sign
tests/recall/test_benchmarks_llm.py read _MLX_AVAILABLE from synapt.recall.clustering, which has never defined it. The import raised, a broad except ImportError pinned the flag False, and the module skipped unconditionally on every platform — including Apple Silicon, where the backend works. Verified by fruit: 16 skipped on a host with real MLX.
One predicate is stuck True so its guard never fires and tests fail loudly. The other is stuck False so its guard always fires and 16 tests disappear silently, because a skip reads as fine. Same root shape: a try/except ImportError wrapped around a multi-name import cannot distinguish "the backend is absent" from "one of these symbols does not exist." It answers an adjacent question and reports the wrong one confidently.
A latent defect that only a working guard exposes
enrich.py imported Message — a backend-neutral type from synapt._models.base — inside if _MLX_AVAILABLE:. That was survivable only while the predicate was stuck True. _enrich_single_window builds a Message for whatever client it is handed, and the router returns Modal or Ollama clients on hosts with no MLX; those callers never pass the MLX guard in enrich_session. Correcting the predicate alone would therefore have traded a red matrix for a NameError on the enrichment path of every non-Apple-Silicon install.
Fixing a guard can expose defects the broken guard was hiding. They ship together or not at all.
Fix
Resolve the backend modules rather than the wrapper, and resolve specs rather than importing — so a backend that exists but raises surfaces its ImportError at the call site instead of being downgraded to "absent." Absent and broken are different facts, and only absence is expected here.
Skip reasons now name the installable dependency, so a skip tells the reader what to do:
requires the MLX backend, missing: mlx_lm, mlx -- install with `pip install mlx-lm`.
recall declares it only for sys_platform=='darwin' and platform_machine=='arm64', so it
is absent by design on Linux and Windows.
The real-model benchmarks stay off by default behind an explicit opt-in (SYNAPT_RUN_LLM_BENCHMARKS=1). Repairing their import alone would have switched all 16 on inside the default CI sweep, because the macOS runners are arm64 and do install the backend — turning a predicate fix into a multi-gigabyte model download on three Python versions. That is a cost decision on its own evidence, not a side effect.
Convention this leaves behind
A platform-local test receipt names its platform. Write 158 passed (macOS-local), never bare 158 passed.
A suite result is a property of a commit in an environment. A green local run and a red matrix are not contradictory when the local host is the one platform that satisfies a dependency the others cannot — they are measuring different populations, and the local one is the strict subset that happens to be clean. An unlabelled receipt invites the reader to treat the subset as the whole, which is how fourteen red runs went unread.
Symptom
Six of twelve
unit-testsjobs fail on every branch:ubuntu-latestandwindows-lateston 3.10, 3.11 and 3.12. All threemacos-latestjobs pass. PRs merge asUNSTABLEbecause no gate in our review sequence reads CI.Five failures, identical everywhere:
This is branch-independent, and the control is the evidence
A docs-only branch fails with the byte-identical five. A documentation change cannot break a model judge, so the failure cannot be coming from anyone's diff. Fourteen consecutive
testsworkflow runs across nine unrelated branches are allfailure.Root cause: the guard exists and its predicate is lying
Every one of those tests is already guarded:
@unittest.skipUnless(consolidate._MLX_AVAILABLE, "MLX not available (requires Apple Silicon)")The guard never fires, because
MLX_AVAILABLEwas computed like this:synapt._models.mlx_clientimportsmlx_lmandmlxfunction-locally (_load,_load_fused,chat), never at module scope. So the wrapper imports cleanly on a machine with no backend at all — andmlx-lmis declared only forsys_platform == 'darwin' and platform_machine == 'arm64', so it is absent by design on Linux and Windows.The predicate asked "does the wrapper import?" when its callers ask "can inference run here?" Those come apart on every non-Apple-Silicon host. Reproduced directly, with a control proving the block took effect:
So the tests run with nothing behind them, inference returns
None, and the suite reports FAILED where the honest answer is SKIPPED.Wider than the test guards
Nine production call sites read this predicate —
enrich.py(5),server.py,consolidate.py(2),cli.py. On Linux and Windows they currently take the MLX path on hosts that cannot execute it, failing at call time instead of returning the install message. Red CI was the symptom, not the defect.The same defect class with the opposite sign
tests/recall/test_benchmarks_llm.pyread_MLX_AVAILABLEfromsynapt.recall.clustering, which has never defined it. The import raised, a broadexcept ImportErrorpinned the flagFalse, and the module skipped unconditionally on every platform — including Apple Silicon, where the backend works. Verified by fruit: 16 skipped on a host with real MLX.One predicate is stuck
Trueso its guard never fires and tests fail loudly. The other is stuckFalseso its guard always fires and 16 tests disappear silently, because a skip reads as fine. Same root shape: atry/except ImportErrorwrapped around a multi-name import cannot distinguish "the backend is absent" from "one of these symbols does not exist." It answers an adjacent question and reports the wrong one confidently.A latent defect that only a working guard exposes
enrich.pyimportedMessage— a backend-neutral type fromsynapt._models.base— insideif _MLX_AVAILABLE:. That was survivable only while the predicate was stuckTrue._enrich_single_windowbuilds aMessagefor whatever client it is handed, and the router returns Modal or Ollama clients on hosts with no MLX; those callers never pass the MLX guard inenrich_session. Correcting the predicate alone would therefore have traded a red matrix for aNameErroron the enrichment path of every non-Apple-Silicon install.Fixing a guard can expose defects the broken guard was hiding. They ship together or not at all.
Fix
Resolve the backend modules rather than the wrapper, and resolve specs rather than importing — so a backend that exists but raises surfaces its
ImportErrorat the call site instead of being downgraded to "absent." Absent and broken are different facts, and only absence is expected here.Skip reasons now name the installable dependency, so a skip tells the reader what to do:
The real-model benchmarks stay off by default behind an explicit opt-in (
SYNAPT_RUN_LLM_BENCHMARKS=1). Repairing their import alone would have switched all 16 on inside the default CI sweep, because the macOS runners are arm64 and do install the backend — turning a predicate fix into a multi-gigabyte model download on three Python versions. That is a cost decision on its own evidence, not a side effect.Convention this leaves behind
A platform-local test receipt names its platform. Write
158 passed (macOS-local), never bare158 passed.A suite result is a property of a commit in an environment. A green local run and a red matrix are not contradictory when the local host is the one platform that satisfies a dependency the others cannot — they are measuring different populations, and the local one is the strict subset that happens to be clean. An unlabelled receipt invites the reader to treat the subset as the whole, which is how fourteen red runs went unread.