The 6 long-standing test_mind_utils failures on the robot are not flaky and
not folklore. They are a test-isolation defect with a confirmed mechanism.
Mechanism
tests/conftest.py has three autouse fixtures that redirect live state to tmp:
| line |
fixture |
| 12 |
_isolate_health_writes |
| 35 |
_isolate_brain_mailbox |
| 55 |
_isolate_alive_heartbeat |
There is no autouse fixture for the session. PX_SESSION_PATH is set on
exactly one line (87), inside isolated_project — which is opt-in, and per
CLAUDE.md only isolates subprocesses. tests/test_mind_utils.py uses
isolated_project zero times.
So any in-process test reaching load_session() reads the live robot's
state/session.json. That file currently has spark_quiet_mode: true (see #209
— an unattributable latch we deliberately are not clearing). policy.py:118 is
the sole reader, and mind.expression() is a #174 enforcement point, so the
dispatch is blocked before any mock fires:
expression: requested=look_around verdict=blocked reason=quiet_mode substituted=none
mock_us.call_args is then None, and the assertion dies on
AttributeError: 'NoneType' object has no attribute 'kwargs'.
Affected tests
test_expression_play_sound_calls_tool
test_expression_look_around_calls_tool
test_expression_time_check_calls_tool
test_expression_calendar_check_calls_tool
test_unknown_action_logged
test_expression_speech_actions_have_no_outcome_key
Evidence it is pre-existing, not caused by #206
Same six tests, same pinned PX_SESSION_PATH (a copy of the live session, so
the only variable is the code):
| tree |
result |
fix/audio-sink-policy-gate |
6 failed |
origin/master @ 585175e |
6 failed |
Also note these pass on any machine whose state/session.json has quiet mode
off, or where the file is absent — which is why CI never sees them and why they
have been carried as a known-red baseline.
Proposed fix
A fourth autouse fixture in tests/conftest.py, matching the shape of the
existing three, pointing PX_SESSION_PATH at tmp_path. Tests that mean to
exercise a populated session set it themselves, exactly as the health and brain
tests do today.
This generalises past test_mind_utils: it closes the whole class, rather than
patching six call sites.
Non-goals
The 6 long-standing
test_mind_utilsfailures on the robot are not flaky andnot folklore. They are a test-isolation defect with a confirmed mechanism.
Mechanism
tests/conftest.pyhas three autouse fixtures that redirect live state to tmp:_isolate_health_writes_isolate_brain_mailbox_isolate_alive_heartbeatThere is no autouse fixture for the session.
PX_SESSION_PATHis set onexactly one line (87), inside
isolated_project— which is opt-in, and perCLAUDE.md only isolates subprocesses.
tests/test_mind_utils.pyusesisolated_projectzero times.So any in-process test reaching
load_session()reads the live robot'sstate/session.json. That file currently hasspark_quiet_mode: true(see #209— an unattributable latch we deliberately are not clearing).
policy.py:118isthe sole reader, and
mind.expression()is a #174 enforcement point, so thedispatch is blocked before any mock fires:
mock_us.call_argsis thenNone, and the assertion dies onAttributeError: 'NoneType' object has no attribute 'kwargs'.Affected tests
test_expression_play_sound_calls_tooltest_expression_look_around_calls_tooltest_expression_time_check_calls_tooltest_expression_calendar_check_calls_tooltest_unknown_action_loggedtest_expression_speech_actions_have_no_outcome_keyEvidence it is pre-existing, not caused by #206
Same six tests, same pinned
PX_SESSION_PATH(a copy of the live session, sothe only variable is the code):
fix/audio-sink-policy-gateorigin/master@ 585175eAlso note these pass on any machine whose
state/session.jsonhas quiet modeoff, or where the file is absent — which is why CI never sees them and why they
have been carried as a known-red baseline.
Proposed fix
A fourth autouse fixture in
tests/conftest.py, matching the shape of theexisting three, pointing
PX_SESSION_PATHattmp_path. Tests that mean toexercise a populated session set it themselves, exactly as the health and brain
tests do today.
This generalises past
test_mind_utils: it closes the whole class, rather thanpatching six call sites.
Non-goals
spark_quiet_modelatch (state(quiet): make quiet mode attributable, bounded and explainable #209).test_api,test_brain,test_gpio_lease,test_px_alive), which pass in isolation.