test: lock ADR-0146 engine-state byte-stability + discovery store path
The ADR-0146 round-trip tests proved object-equality but not byte-stability, and the only non-empty discovery test bypassed EngineStateStore. Mutation testing confirmed object-equality has teeth (a dropped field is caught) while the store's non-empty discovery round-trip, save->load->save idempotence, and cross-instance byte-determinism were untested. Adds 4 locking tests (mutation-verified to fail under a lossy from_dict): - recognizers_save_load_save_is_idempotent - recognizers_save_is_deterministic_across_instances - discovery_store_round_trips_nonempty_candidate - discovery_store_save_load_save_is_idempotent Deliberately not golden-format pins: a deterministic format change is harmless for a content hash, and pinning would make every legitimate schema bump a death-and-rebirth event. Prerequisite for any cross-reboot EngineIdentity content-hash (ADR-0146 / L10).
This commit is contained in:
parent
d47741f5df
commit
3911db66a3
1 changed files with 57 additions and 0 deletions
|
|
@ -137,3 +137,60 @@ def test_discovery_candidate_from_dict_round_trips() -> None:
|
|||
roundtrip = DiscoveryCandidate.from_dict(candidate.as_dict())
|
||||
|
||||
assert roundtrip == candidate
|
||||
|
||||
|
||||
# --- ADR-0146 byte-stability + store-path coverage (added 2026-06-05) ----------
|
||||
# The round-trip tests above prove OBJECT equality. The cross-reboot identity the
|
||||
# telos needs (the shelved EngineIdentity content-hash) additionally requires the
|
||||
# on-disk serialization to be IDEMPOTENT (save->load->save reproduces the bytes)
|
||||
# and DETERMINISTIC (same logical state -> same bytes across independent stores).
|
||||
# These lock that. They are deliberately NOT golden-format pins: a *deterministic*
|
||||
# format change is harmless for a content hash (it changes consistently), so the
|
||||
# real hazards are non-idempotence, run-to-run nondeterminism, and a broken store
|
||||
# path -- not the exact byte layout (which must stay free to evolve under a
|
||||
# versioned schema, lest every legitimate field-add become a death-and-rebirth).
|
||||
|
||||
|
||||
def test_recognizers_save_load_save_is_idempotent(tmp_path) -> None:
|
||||
store = EngineStateStore(tmp_path)
|
||||
recs = [_recognizer("set-1"), _recognizer("set-2")]
|
||||
|
||||
store.save_recognizers(recs)
|
||||
first = (tmp_path / "recognizers.jsonl").read_bytes()
|
||||
store.save_recognizers(store.load_recognizers())
|
||||
|
||||
assert (tmp_path / "recognizers.jsonl").read_bytes() == first
|
||||
|
||||
|
||||
def test_recognizers_save_is_deterministic_across_instances(tmp_path) -> None:
|
||||
recs = [_recognizer("set-1"), _recognizer("set-2")]
|
||||
|
||||
EngineStateStore(tmp_path / "a").save_recognizers(recs)
|
||||
EngineStateStore(tmp_path / "b").save_recognizers(recs)
|
||||
|
||||
assert (
|
||||
(tmp_path / "a" / "recognizers.jsonl").read_bytes()
|
||||
== (tmp_path / "b" / "recognizers.jsonl").read_bytes()
|
||||
)
|
||||
|
||||
|
||||
def test_discovery_store_round_trips_nonempty_candidate(tmp_path) -> None:
|
||||
# The only existing non-empty discovery test bypasses EngineStateStore
|
||||
# (as_dict -> from_dict in memory); this exercises the STORE's save+load
|
||||
# path for a non-empty candidate, which was previously untested.
|
||||
store = EngineStateStore(tmp_path)
|
||||
candidate = _candidate()
|
||||
|
||||
store.save_discovery_candidates([candidate])
|
||||
|
||||
assert store.load_discovery_candidates() == [candidate]
|
||||
|
||||
|
||||
def test_discovery_store_save_load_save_is_idempotent(tmp_path) -> None:
|
||||
store = EngineStateStore(tmp_path)
|
||||
|
||||
store.save_discovery_candidates([_candidate()])
|
||||
first = (tmp_path / "discovery_candidates.jsonl").read_bytes()
|
||||
store.save_discovery_candidates(store.load_discovery_candidates())
|
||||
|
||||
assert (tmp_path / "discovery_candidates.jsonl").read_bytes() == first
|
||||
|
|
|
|||
Loading…
Reference in a new issue