Four tests across three independent call sites assert that a corrupt or non-conforming meta.json is handled gracefully — returning None, or raising a typed domain exception. All four are red on main: each call site instead lets a raw ValueError propagate.
The failures
| Node-id |
Job |
Expected |
Actual |
tests/lanes/test_worktree_allocator.py::TestDefensiveHelpers::test_read_coordination_branch_none_on_malformed_json |
integration-tests-lanes |
None |
ValueError: Malformed JSON in …/meta.json: Expecting property name enclosed in double quotes: line 1 column 3 (char 2) |
tests/unit/status/test_mission_status_aggregate.py::TestLoadCoordUnavailableFailsClosed::test_corrupt_meta_fails_closed_instead_of_legacy_fallback |
integration-tests-core-misc (misc) |
MissionMetadataUnavailable |
ValueError: Malformed JSON in …/meta.json: Expecting value: line 1 column 63 (char 62) |
tests/unit/status/test_mission_status_aggregate.py::TestLoadCoordUnavailableFailsClosed::test_non_dict_meta_fails_closed_instead_of_legacy_fallback |
integration-tests-core-misc (misc) |
MissionMetadataUnavailable |
ValueError: Expected JSON object in …/meta.json, got list |
tests/specify_cli/cli/commands/test_charter_widen_integration.py::TestGetMissionId::test_returns_none_if_json_malformed |
fast-tests-cli |
None |
ValueError |
Evidence
Stable — all four fail identically in two independent runs on the same SHA:
Both on bb2020fea924d6e5b157974f27a7cab1a77ad259.
The shape
Three call sites — the lane worktree allocator, the mission-status aggregate, and the charter mission-id lookup — each wrap a meta.json read that is supposed to degrade gracefully, and each now surfaces the raw parse error instead. The ValueError messages are well-formed and specific (Malformed JSON in <path>, Expected JSON object in <path>, got list), which suggests a shared reader that was made stricter and now raises where it previously returned a sentinel, rather than three call sites independently losing their guards.
Check that before filing follow-ups or fixing site-by-site. If one reader changed, this is one fix. If the guards were removed independently, it is three, and test_read_coordination_branch_none_on_malformed_json's name suggests its guard was deliberate.
A fifth instance, already known and never filed
tests/agent/.../test_charter_io.py::test_get_mission_id_returns_none_when_meta_json_malformed has been carried on at least one mission's briefed "known pre-existing failures — do not chase" list. It is the same assertion shape as the fourth row above, in a different file.
That is the reason this is worth an issue rather than a shrug: the failure class is old enough to have been informally routed around by more than one piece of work, which is exactly how a defect stops being counted. Under DIR-013 a pre-existing failure gets filed rather than absorbed as accepted baseline.
Why the direction matters
Three of the four tests assert fail-closed behaviour by name (TestLoadCoordUnavailableFailsClosed, ..._fails_closed_instead_of_legacy_fallback). A raw ValueError escaping to the caller is not fail-closed — it is uncaught, and the calling surface decides what happens by accident. Whichever way this is fixed, the fix should preserve the distinction those test names are drawing: refusing to proceed is not the same as crashing.
What has not been established
- Whether one shared reader or three separate guards changed.
- Which commit introduced it.
- Whether the
ValueError-raising behaviour is intended and the tests are stale — possible, given the messages are deliberate and well-formed, in which case the tests need updating and the fail-closed contract needs restating somewhere durable.
Filed from a CI baseline inventory taken at bb2020fea9, which separated pre-existing reds from PR-caused ones for an unrelated mission. Of 41 distinct failing node-ids, 29 were tied to an open issue and 18 were unfiled; these 4 are one of two unfiled clusters.
Four tests across three independent call sites assert that a corrupt or non-conforming
meta.jsonis handled gracefully — returningNone, or raising a typed domain exception. All four are red onmain: each call site instead lets a rawValueErrorpropagate.The failures
tests/lanes/test_worktree_allocator.py::TestDefensiveHelpers::test_read_coordination_branch_none_on_malformed_jsonintegration-tests-lanesNoneValueError: Malformed JSON in …/meta.json: Expecting property name enclosed in double quotes: line 1 column 3 (char 2)tests/unit/status/test_mission_status_aggregate.py::TestLoadCoordUnavailableFailsClosed::test_corrupt_meta_fails_closed_instead_of_legacy_fallbackintegration-tests-core-misc (misc)MissionMetadataUnavailableValueError: Malformed JSON in …/meta.json: Expecting value: line 1 column 63 (char 62)tests/unit/status/test_mission_status_aggregate.py::TestLoadCoordUnavailableFailsClosed::test_non_dict_meta_fails_closed_instead_of_legacy_fallbackintegration-tests-core-misc (misc)MissionMetadataUnavailableValueError: Expected JSON object in …/meta.json, got listtests/specify_cli/cli/commands/test_charter_widen_integration.py::TestGetMissionId::test_returns_none_if_json_malformedfast-tests-cliNoneValueErrorEvidence
Stable — all four fail identically in two independent runs on the same SHA:
3068194149530621215287Both on
bb2020fea924d6e5b157974f27a7cab1a77ad259.The shape
Three call sites — the lane worktree allocator, the mission-status aggregate, and the charter mission-id lookup — each wrap a
meta.jsonread that is supposed to degrade gracefully, and each now surfaces the raw parse error instead. TheValueErrormessages are well-formed and specific (Malformed JSON in <path>,Expected JSON object in <path>, got list), which suggests a shared reader that was made stricter and now raises where it previously returned a sentinel, rather than three call sites independently losing their guards.Check that before filing follow-ups or fixing site-by-site. If one reader changed, this is one fix. If the guards were removed independently, it is three, and
test_read_coordination_branch_none_on_malformed_json's name suggests its guard was deliberate.A fifth instance, already known and never filed
tests/agent/.../test_charter_io.py::test_get_mission_id_returns_none_when_meta_json_malformedhas been carried on at least one mission's briefed "known pre-existing failures — do not chase" list. It is the same assertion shape as the fourth row above, in a different file.That is the reason this is worth an issue rather than a shrug: the failure class is old enough to have been informally routed around by more than one piece of work, which is exactly how a defect stops being counted. Under DIR-013 a pre-existing failure gets filed rather than absorbed as accepted baseline.
Why the direction matters
Three of the four tests assert fail-closed behaviour by name (
TestLoadCoordUnavailableFailsClosed,..._fails_closed_instead_of_legacy_fallback). A rawValueErrorescaping to the caller is not fail-closed — it is uncaught, and the calling surface decides what happens by accident. Whichever way this is fixed, the fix should preserve the distinction those test names are drawing: refusing to proceed is not the same as crashing.What has not been established
ValueError-raising behaviour is intended and the tests are stale — possible, given the messages are deliberate and well-formed, in which case the tests need updating and the fail-closed contract needs restating somewhere durable.Filed from a CI baseline inventory taken at
bb2020fea9, which separated pre-existing reds from PR-caused ones for an unrelated mission. Of 41 distinct failing node-ids, 29 were tied to an open issue and 18 were unfiled; these 4 are one of two unfiled clusters.