Phase 1 step 5 of #53 — the load-bearing piece. Freezes the cache-
identity byte shape today so the run_query rewrite landing in Phase 2
can be checked against it.
What's pinned (tests/fixtures/byte_identity/claim_lattice.json):
- SHA-256 of CLAIM_LATTICE_SYSTEM_PROMPT (drift = every cache rotates)
- SHA-256 of CLAIM_LATTICE_GROUNDING_REMINDER (same)
- Per-question question_hash (strict + equivalence_class modes)
- Per-question conversation_hash on the synthetic 2-message array
[system + user(EVIDENCE+QUESTION+grounding_reminder)] — the EXACT
shape arborist/qa/corpus_query.py:run_query builds
- governance_policy_hash on three reference policy shapes
- model_profile_hash for hermes / qwen / stub
Plus a determinism sanity test that pins the algos themselves
(SHA-256, _canonical_json key-sorting, dedup-mode question canonical).
Risk class addressed (Plan §6 risks #1+#2): conversation_hash takes
the FULL OpenAI messages array. Any drift — message reorder, whitespace
shift, optional message gated on a different condition — rotates every
cache_key in the world and orphans every providence_cache record on
re-lookup. Same for governance_policy_hash on the policy dict (a new
field rotates everything). The fixture catches a drift the SECOND it
happens, with a diff-style failure naming the path that drifted.
Re-capture mode: `CAPTURE=1 pytest tests/test_run_query_byte_identity.py`
rewrites the fixture. Only do this on deliberate prompt-shape or
policy-shape changes that are treated as cache-invalidation events.