Closes W-004 wiring debt surfaced by L2 audit (#238) and predicted by L1 audit's forward note (#237). ADR-0006 §"Integration Points" states: "Vault recall re-activates the region to E2 transiently, then lets it cool again." Prior to this commit, vault.recall() returned entries with no energy field at all — the re-thaw was spec-only. Changes: - vault/store.py: import EnergyClass / EnergyProfile from core.physics.energy. Define module-level _VAULT_RECALL_RETHAW_ENERGY singleton (raw=0.50, energy_class=E2, mid-band). Both .recall() and .recall_batch() stamp each returned entry with the re-thaw profile via a new "energy_profile" key in the result dict. - tests/test_vault_recall_rethaw.py: 6 tests pinning the contract — recall returns E2 profile, recall_batch returns E2 profile, singleton is byte-identical across calls (replay determinism), empty vault is no-op, min_status filtering preserves the field, raw value sits unambiguously in E2 band [0.37, 0.62). Architectural notes: - The re-thaw is *declared* by the vault, not derived through the energy operator. ADR-0006 makes the assertion directly; vault recall is the moment the assertion applies. - The singleton (rather than a per-call construction) preserves byte-identical replay: same recall sequence => identical EnergyProfile object => stable trace if downstream folds it. - Cool-down per ADR-0006 is downstream field propagation's responsibility via FieldEnergyOperator's natural recency decay. Once the recalled entry is no longer being injected into the active field state, recency drops and energy class falls. - "energy_profile" is added to recall result dicts, alongside the existing "epistemic_state" field. Existing consumers (generate/ stream.py:169, chat/runtime.py:1643, vault/decompose.py:124,179, session/context.py:347) ignore unknown keys — no breakage. Unlocks W-005 (energy-modulated surface readback) — now that E0/E2 distinction exists at the runtime data shape, downstream readback modulation can become meaningful instead of moot. Verification: - tests/test_vault_recall_rethaw.py: 6 passed - tests/test_vault_*.py: 48 passed, 4 skipped (no regression) - core test --suite smoke: 67 passed - core test --suite cognition: 120 passed, 1 skipped - core test --suite algebra: 82 passed, 50 skipped - scripts/verify_lane_shas.py: 7/7 match pinned SHAs (byte-identity preserved)
97 lines
3.6 KiB
Python
97 lines
3.6 KiB
Python
"""Tests for ADR-0006 vault-recall re-thaw (W-004).
|
|
|
|
ADR-0006 §"Integration Points": "Vault recall re-activates the region to E2
|
|
transiently, then lets it cool again."
|
|
|
|
These tests pin the contract that vault.recall and vault.recall_batch return
|
|
an EnergyProfile with energy_class=E2 on every returned entry, declaring
|
|
the transient re-activation.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import numpy as np
|
|
|
|
from core.physics.energy import EnergyClass, EnergyProfile
|
|
from teaching.epistemic import EpistemicStatus
|
|
from vault.store import VaultStore, _VAULT_RECALL_RETHAW_ENERGY
|
|
|
|
|
|
def _make_versor(seed: int) -> np.ndarray:
|
|
rng = np.random.default_rng(seed)
|
|
return rng.standard_normal(32).astype(np.float32)
|
|
|
|
|
|
def test_recall_returns_energy_profile_e2() -> None:
|
|
"""Every recall result carries an EnergyProfile declaring E2 re-thaw."""
|
|
store = VaultStore()
|
|
for i in range(3):
|
|
store.store(_make_versor(i), {"label": f"entry-{i}"})
|
|
|
|
results = store.recall(_make_versor(0), top_k=3)
|
|
assert len(results) == 3
|
|
for hit in results:
|
|
assert "energy_profile" in hit, "recall result missing energy_profile"
|
|
profile = hit["energy_profile"]
|
|
assert isinstance(profile, EnergyProfile)
|
|
assert profile.energy_class is EnergyClass.E2
|
|
|
|
|
|
def test_recall_batch_returns_energy_profile_e2() -> None:
|
|
"""Batched recall stamps the same re-thaw energy on every entry."""
|
|
store = VaultStore()
|
|
for i in range(3):
|
|
store.store(_make_versor(i), {"label": f"entry-{i}"})
|
|
|
|
queries = np.stack([_make_versor(0), _make_versor(1)])
|
|
batch_results = store.recall_batch(queries, top_k=2)
|
|
assert len(batch_results) == 2
|
|
for per_query in batch_results:
|
|
assert len(per_query) == 2
|
|
for hit in per_query:
|
|
assert "energy_profile" in hit
|
|
assert hit["energy_profile"].energy_class is EnergyClass.E2
|
|
|
|
|
|
def test_rethaw_energy_singleton_byte_identical() -> None:
|
|
"""The re-thaw EnergyProfile is a deterministic singleton — no per-call
|
|
drift. Required for replay byte-identity (same recall sequence ⇒ same
|
|
energy profile on every entry)."""
|
|
store = VaultStore()
|
|
store.store(_make_versor(0), {"label": "entry-0"})
|
|
|
|
a = store.recall(_make_versor(0), top_k=1)[0]["energy_profile"]
|
|
b = store.recall(_make_versor(0), top_k=1)[0]["energy_profile"]
|
|
assert a is b, "re-thaw profile must be a stable singleton, not a fresh allocation"
|
|
assert a is _VAULT_RECALL_RETHAW_ENERGY
|
|
|
|
|
|
def test_recall_empty_vault_does_not_emit_profile() -> None:
|
|
"""Empty vault returns []; no energy_profile to attach."""
|
|
store = VaultStore()
|
|
assert store.recall(_make_versor(0), top_k=5) == []
|
|
|
|
|
|
def test_recall_with_min_status_still_carries_energy_profile() -> None:
|
|
"""min_status filtering does not strip the energy_profile field."""
|
|
store = VaultStore()
|
|
store.store(_make_versor(0), {"label": "coherent"},
|
|
epistemic_status=EpistemicStatus.COHERENT)
|
|
store.store(_make_versor(1), {"label": "speculative"},
|
|
epistemic_status=EpistemicStatus.SPECULATIVE)
|
|
|
|
results = store.recall(
|
|
_make_versor(0), top_k=5,
|
|
min_status=EpistemicStatus.COHERENT,
|
|
)
|
|
assert len(results) == 1
|
|
assert results[0]["energy_profile"].energy_class is EnergyClass.E2
|
|
|
|
|
|
def test_rethaw_profile_raw_is_in_e2_band() -> None:
|
|
"""ADR-0006 declares E2 transient re-activation. Verify the singleton's
|
|
raw value sits in the E2 band [0.37, 0.62) — so it is unambiguously E2
|
|
rather than borderline."""
|
|
profile = _VAULT_RECALL_RETHAW_ENERGY
|
|
assert 0.37 <= profile.raw < 0.62
|
|
assert profile.energy_class is EnergyClass.E2
|