diff --git a/core/contemplation/__init__.py b/core/contemplation/__init__.py index e7d439fb..435516bb 100644 --- a/core/contemplation/__init__.py +++ b/core/contemplation/__init__.py @@ -2,6 +2,9 @@ ADR-0080: contemplation can emit speculative findings about current substrate/report evidence, but it cannot ratify, promote, or mutate packs. + +ADR-0241 P9: Trace A wave seam may SPECULATIVE-seal standing-wave modes and +emit RESONANT_MODE_CANDIDATE findings — never COHERENT, never serve-wired. """ from .runner import contemplate_frontier_reports, run_contemplation @@ -12,6 +15,13 @@ from .schema import ( FindingKind, ) from .snapshot import ContemplationSubstrate +from .wave_seam import ( + WaveModeHypothesis, + WaveReconstructResult, + reconstruct_as_evidence, + reconstruct_as_hypothesis, + speculative_seal_from_contemplation, +) __all__ = [ "ContemplationEvidenceRef", @@ -19,6 +29,11 @@ __all__ = [ "ContemplationRun", "ContemplationSubstrate", "FindingKind", + "WaveModeHypothesis", + "WaveReconstructResult", "contemplate_frontier_reports", + "reconstruct_as_evidence", + "reconstruct_as_hypothesis", "run_contemplation", + "speculative_seal_from_contemplation", ] diff --git a/core/contemplation/schema.py b/core/contemplation/schema.py index fbfcc3a9..42efc2f2 100644 --- a/core/contemplation/schema.py +++ b/core/contemplation/schema.py @@ -25,6 +25,8 @@ class FindingKind(Enum): OOV_GAP = "oov_gap" PLANNER_GAP = "planner_gap" PACK_MUTATION_CANDIDATE = "pack_mutation_candidate" + # ADR-0241 P9 Trace A: speculative standing-wave mode sealed for review. + RESONANT_MODE_CANDIDATE = "resonant_mode_candidate" def _canonical_json(payload: dict[str, Any]) -> str: diff --git a/core/contemplation/wave_seam.py b/core/contemplation/wave_seam.py new file mode 100644 index 00000000..5c3ed147 --- /dev/null +++ b/core/contemplation/wave_seam.py @@ -0,0 +1,193 @@ +"""P9 Trace A seam — contemplation → SPECULATIVE holographic standing-wave seal. + +ADR-0241 cohesion package P9: + +1. Contemplation may **SPECULATIVE-seal** standing-wave modes via + :meth:`HolographicVaultStore.seal_mode` only. +2. Never writes COHERENT — teaching corridor / authorized + ``seal_mode_reviewed`` remains outside this module. +3. Resonant reconstruct is available as a **hypothesis** over the full + spectrum, or as **evidence** only when ``min_status=COHERENT``. +4. Serve path stays quarantined (no import from ``chat/runtime.py``). +5. No direct ``VaultStore.store`` — INV-21 writes stay in holographic_vault. + +This module is the living-system bridge for Trace A without collapsing +the teaching / serve containment boundary. +""" + +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any, Literal + +import numpy as np + +from core.contemplation.schema import ( + ContemplationEvidenceRef, + ContemplationFinding, + FindingKind, +) +from core.physics.holographic_vault import ( + HolographicVaultError, + HolographicVaultStore, + SealedMode, +) +from teaching.epistemic import EpistemicStatus + + +@dataclass(frozen=True, slots=True) +class WaveModeHypothesis: + """SPECULATIVE seal + contemplation finding for teaching review.""" + + sealed: SealedMode + finding: ContemplationFinding + standing: Literal["hypothesis"] = "hypothesis" + + def as_dict(self) -> dict[str, Any]: + return { + "standing": self.standing, + "mode_id": self.sealed.mode_id, + "vault_index": self.sealed.vault_index, + "epistemic_status": self.sealed.epistemic_status.value, + "finding": self.finding.as_dict(), + } + + +@dataclass(frozen=True, slots=True) +class WaveReconstructResult: + """Reconstructed field with honest epistemic standing label.""" + + psi_hat: np.ndarray + coeffs: np.ndarray + energies: np.ndarray + spectrum: tuple[SealedMode, ...] + standing: Literal["hypothesis", "evidence"] + min_status: EpistemicStatus | None + + def as_dict(self) -> dict[str, Any]: + return { + "standing": self.standing, + "min_status": None if self.min_status is None else self.min_status.value, + "mode_ids": [s.mode_id for s in self.spectrum], + "coeff_count": int(self.coeffs.shape[0]), + } + + +def speculative_seal_from_contemplation( + store: HolographicVaultStore, + psi: np.ndarray, + *, + substrate_hash: str, + subject: str, + mode_id: str | None = None, + notes: str = "", + predicate: str = "propose_standing_wave_mode", +) -> WaveModeHypothesis: + """SPECULATIVE-seal a closed mode and emit a contemplation finding. + + Fail-closed on non-closed / high-drift ψ (delegates to holographic admit). + Does **not** accept an authorization flag — COHERENT promotion is not + available on this seam. + """ + if not str(substrate_hash).strip(): + raise ValueError("substrate_hash is required for Trace A provenance") + if not str(subject).strip(): + raise ValueError("subject is required") + + meta: dict[str, Any] = { + "source": "contemplation_trace_a", + "substrate_hash": substrate_hash, + "notes": notes, + "adr_refs": ["ADR-0241", "ADR-0080"], + } + sealed = store.seal_mode(psi, mode_id=mode_id, metadata=meta) + if sealed.epistemic_status is not EpistemicStatus.SPECULATIVE: + # Defensive: seal_mode contract is SPECULATIVE-only; never promote here. + raise RuntimeError( + "Trace A seam integrity breach: seal_mode returned non-SPECULATIVE" + ) + + mid = sealed.mode_id + finding = ContemplationFinding( + kind=FindingKind.RESONANT_MODE_CANDIDATE, + subject=subject, + predicate=predicate, + object=mid, + evidence_refs=( + ContemplationEvidenceRef( + source_type="holographic_vault", + source_id=mid, + pointer=f"vault_index:{sealed.vault_index}", + summary=( + "SPECULATIVE standing-wave mode sealed for teaching review; " + "not admissible as COHERENT evidence" + ), + ), + ), + proposed_action="review_standing_wave_mode", + substrate_hash=substrate_hash, + epistemic_status=EpistemicStatus.SPECULATIVE, + ) + return WaveModeHypothesis(sealed=sealed, finding=finding, standing="hypothesis") + + +def reconstruct_as_hypothesis( + store: HolographicVaultStore, + psi_query: np.ndarray, +) -> WaveReconstructResult: + """Superposition reconstruct over the full spectrum (incl. SPECULATIVE). + + Result standing is always ``hypothesis`` — never claim reviewed evidence. + """ + psi_hat, coeffs, energies, spectrum = store.resonant_reconstruct(psi_query) + return WaveReconstructResult( + psi_hat=psi_hat, + coeffs=coeffs, + energies=energies, + spectrum=spectrum, + standing="hypothesis", + min_status=None, + ) + + +def reconstruct_as_evidence( + store: HolographicVaultStore, + psi_query: np.ndarray, +) -> WaveReconstructResult: + """Superposition reconstruct over COHERENT modes only. + + SPECULATIVE modes are excluded. Empty COHERENT spectrum refuses so + unreviewed hypothesis mass cannot masquerade as evidence. + """ + try: + psi_hat, coeffs, energies, spectrum = store.resonant_reconstruct( + psi_query, + min_status=EpistemicStatus.COHERENT, + ) + except HolographicVaultError as exc: + if exc.reason == "empty_spectrum": + raise HolographicVaultError( + "empty_spectrum", + detail=( + "evidence reconstruct requires COHERENT standing-wave modes; " + "SPECULATIVE hypothesis mass is excluded" + ), + ) from exc + raise + return WaveReconstructResult( + psi_hat=psi_hat, + coeffs=coeffs, + energies=energies, + spectrum=spectrum, + standing="evidence", + min_status=EpistemicStatus.COHERENT, + ) + + +__all__ = [ + "WaveModeHypothesis", + "WaveReconstructResult", + "reconstruct_as_evidence", + "reconstruct_as_hypothesis", + "speculative_seal_from_contemplation", +] diff --git a/core/physics/holographic_vault.py b/core/physics/holographic_vault.py index 39c59588..261a7dd7 100644 --- a/core/physics/holographic_vault.py +++ b/core/physics/holographic_vault.py @@ -222,14 +222,7 @@ class HolographicVaultStore: Empty spectrum / cold start without modes → refuse (no confabulation). Uses algebraic reverse-product energy via WaveManifold. """ - if min_status is not None: - # Rebuild filtered view so COHERENT-tier evidence excludes SPECULATIVE. - spectrum = list(self.load_spectrum(min_status=min_status)) - else: - spectrum = list(self._sealed) - if not spectrum: - # Cold start: attempt unfiltered load once. - spectrum = list(self.load_spectrum()) + spectrum = self._spectrum_for_status(min_status) if not spectrum: raise HolographicVaultError( "empty_spectrum", @@ -240,6 +233,47 @@ class HolographicVaultStore: mode, energy, idx = self._manifold.resonant_recall(query, modes=modes) return mode, float(energy), int(idx), spectrum[int(idx)] + def resonant_reconstruct( + self, + psi_query: np.ndarray, + *, + min_status: EpistemicStatus | None = None, + ) -> tuple[np.ndarray, np.ndarray, np.ndarray, tuple[SealedMode, ...]]: + """Superposition reconstruct over the durable spectrum. + + ``min_status=COHERENT`` excludes SPECULATIVE modes so hypothesis + mass cannot masquerade as reviewed evidence (Trace A / INV-24). + Empty filtered spectrum refuses (no confabulation). + """ + spectrum = self._spectrum_for_status(min_status) + if not spectrum: + raise HolographicVaultError( + "empty_spectrum", + detail=( + "no standing-wave modes for resonant reconstruct " + f"(min_status={getattr(min_status, 'value', min_status)!r})" + ), + ) + query = _as_mv(psi_query, "ψ_query") + modes = [s.mode for s in spectrum] + psi_hat, coeffs, energies = self._manifold.resonant_reconstruct( + query, modes=modes + ) + return psi_hat, coeffs, energies, tuple(spectrum) + + def _spectrum_for_status( + self, + min_status: EpistemicStatus | None, + ) -> list[SealedMode]: + if min_status is not None: + # Rebuild filtered view so COHERENT-tier evidence excludes SPECULATIVE. + return list(self.load_spectrum(min_status=min_status)) + spectrum = list(self._sealed) + if not spectrum: + # Cold start: attempt unfiltered load once. + spectrum = list(self.load_spectrum()) + return spectrum + def spectrum_size(self) -> int: """Number of standing-wave modes currently in the reconstruction cache.""" return len(self._sealed) diff --git a/docs/adr/ADR-0241-wave-field-driven-hyperbolic-atlas-and-resonant-cognition.md b/docs/adr/ADR-0241-wave-field-driven-hyperbolic-atlas-and-resonant-cognition.md index ff3e622b..1f518531 100644 --- a/docs/adr/ADR-0241-wave-field-driven-hyperbolic-atlas-and-resonant-cognition.md +++ b/docs/adr/ADR-0241-wave-field-driven-hyperbolic-atlas-and-resonant-cognition.md @@ -1,6 +1,6 @@ # ADR-0241: Wave-Field Driven Hyperbolic Atlas and Resonant Algebraic Cognition -**Status**: Proposed — substrate + Slice-2/3 subsumption complete on branch (`wave_manifold`, operator delegates, multi-pair conjugacy thin wrap, resonant recall); acceptance path: Joshua review + merge +**Status**: Proposed — substrate + entity suite + ADR-0242 packing/Fibonacci + P9 Trace A wave_seam (SPECULATIVE holographic seal / hypothesis-vs-evidence reconstruct); remaining cohesion packages P10 energy + P12 governance; acceptance path: Joshua review **Date**: 2026-07-13 **Deciders**: Joshua Shay + multi-model R&D **Traceability**: Issue #14, parent #10 diff --git a/docs/research/third-door-blueprint-fidelity.md b/docs/research/third-door-blueprint-fidelity.md index e30faaa8..f83878a2 100644 --- a/docs/research/third-door-blueprint-fidelity.md +++ b/docs/research/third-door-blueprint-fidelity.md @@ -296,11 +296,12 @@ PY | Phase correlation \(\rho\) (I-04 algebra) | 🟢 `phase_correlation` (sensorium feed still open) | | Surprise / GoldTether / biography delegate to wave | 🟢 | | No teaching import in `wave_manifold`; no `core_ha` package | 🟢 | -| Serve path not wired to wave / Fibonacci (containment) | 🟢 (AST-pinned in cohesion suite) | +| Serve path not wired to wave / Fibonacci (containment) | 🟢 (AST-pinned in cohesion suite; includes `wave_seam`) | | Entity I-01…I-05 cohesion suite | 🟢 progressive pins in `test_third_door_cohesion.py` (I-02 float32-honest) | | Vault public `get_versor` ABI | 🟢 | | Golden-Angle atlas packing \(d_{\min}=0.12\) | 🟢 ADR-0242 (`atlas_packing`; CGA null-point \(d\)) | | Fibonacci κ search | 🟢 ADR-0242 (`fibonacci_search`) | +| Contemplation Trace A SPECULATIVE holographic seal (P9) | 🟢 `core/contemplation/wave_seam.py` (hypothesis vs COHERENT evidence) | ### Subsumption map (Slice 2–3) | Operator | Delegation | @@ -335,6 +336,7 @@ PY | `core_ha` deprecation — 🟢 no live tree + hygiene + Phase 0 grep | ADR-0241 / deprecation plan | | Durable holographic vault spectrum — 🟢 HolographicVaultStore | ADR-0241 | | Entity cohesion I-01…I-05 + Trace A/B | cohesion master plan | +| Contemplation Trace A SPECULATIVE seal (P9) — 🟢 wave_seam | ADR-0241 P9 | | Atlas packing + Fibonacci κ (ADR-0242) — 🟢 packing + search | PR #37 / ADR-0242 | Closing a gap = flip its `xfail` in `tests/test_third_door_blueprint_fidelity.py` (or the ADR-0241 / cohesion suite) to a passing behavioral test and delete the matching characterization lock. That is the definition of "done right" here. diff --git a/tests/test_adr_0241_wave_contemplation_seam.py b/tests/test_adr_0241_wave_contemplation_seam.py new file mode 100644 index 00000000..fd991e1c --- /dev/null +++ b/tests/test_adr_0241_wave_contemplation_seam.py @@ -0,0 +1,164 @@ +"""P9 Trace A — contemplation → SPECULATIVE holographic seal → teaching corridor. + +ADR-0241 cohesion plan package P9: + * Contemplation may SPECULATIVE-seal standing-wave modes (no COHERENT). + * Resonant reconstruct as *hypothesis* may use SPECULATIVE spectrum. + * Resonant reconstruct as *evidence* requires min_status=COHERENT. + * Serve path remains quarantined from this seam. + * Writes go only through HolographicVaultStore.seal_mode (INV-21). +""" + +from __future__ import annotations + +import ast +from pathlib import Path + +import numpy as np +import pytest + +from algebra.rotor import make_rotor_from_angle +from core.contemplation.schema import FindingKind +from core.physics.holographic_vault import HolographicVaultError, HolographicVaultStore +from teaching.epistemic import EpistemicStatus +from vault.store import VaultStore + +from core.contemplation.wave_seam import ( + WaveModeHypothesis, + WaveReconstructResult, + reconstruct_as_evidence, + reconstruct_as_hypothesis, + speculative_seal_from_contemplation, +) + +_ROOT = Path(__file__).resolve().parents[1] + + +def _closed(angle: float = 0.3, plane: int = 6) -> np.ndarray: + return make_rotor_from_angle(angle, bivector_idx=plane) + + +# --- SPECULATIVE seal from contemplation ------------------------------------ + + +def test_speculative_seal_writes_speculative_only(): + hv = HolographicVaultStore(VaultStore()) + hyp = speculative_seal_from_contemplation( + hv, + _closed(0.21), + substrate_hash="sub-abc", + subject="mode-from-contemplation", + mode_id="p9-m0", + ) + assert isinstance(hyp, WaveModeHypothesis) + assert hyp.sealed.epistemic_status is EpistemicStatus.SPECULATIVE + assert hyp.sealed.mode_id == "p9-m0" + assert hyp.finding.epistemic_status is EpistemicStatus.SPECULATIVE + assert hyp.finding.kind is FindingKind.RESONANT_MODE_CANDIDATE + assert hyp.finding.substrate_hash == "sub-abc" + assert hyp.standing == "hypothesis" + # Evidence ref points at vault mode, not pack mutation. + assert any( + e.source_type == "holographic_vault" and "p9-m0" in e.source_id + for e in hyp.finding.evidence_refs + ) + + +def test_speculative_seal_refuses_non_closed(): + hv = HolographicVaultStore(VaultStore()) + dirty = np.zeros(32, dtype=np.float64) + dirty[0] = 0.5 + dirty[1] = 0.5 + with pytest.raises((HolographicVaultError, ValueError)): + speculative_seal_from_contemplation( + hv, dirty, substrate_hash="sub", subject="bad" + ) + + +def test_seam_has_no_coherent_write_surface(): + """Contemplation seam must not *call* seal_mode_reviewed or VaultStore.store.""" + src = (_ROOT / "core/contemplation/wave_seam.py").read_text(encoding="utf-8") + assert "min_status" in src # evidence path filters COHERENT; does not write it + tree = ast.parse(src) + for node in ast.walk(tree): + if not isinstance(node, ast.Call): + continue + func = node.func + if isinstance(func, ast.Attribute) and func.attr in { + "store", + "seal_mode_reviewed", + }: + pytest.fail( + f"wave_seam must not call .{func.attr}(...) " + "(INV-21 / no COHERENT self-write)" + ) + if isinstance(func, ast.Name) and func.id in {"store", "seal_mode_reviewed"}: + pytest.fail(f"wave_seam must not call {func.id}(...)") + + +# --- Hypothesis vs evidence reconstruct ------------------------------------- + + +def test_hypothesis_reconstruct_uses_speculative_spectrum(): + hv = HolographicVaultStore(VaultStore()) + psi = _closed(0.33, plane=7) + speculative_seal_from_contemplation( + hv, psi, substrate_hash="s", subject="m", mode_id="only-spec" + ) + result = reconstruct_as_hypothesis(hv, psi) + assert isinstance(result, WaveReconstructResult) + assert result.standing == "hypothesis" + assert result.psi_hat.shape == (32,) + # Overlap with the sealed mode should be strong. + assert float(np.linalg.norm(result.psi_hat)) > 0.0 + + +def test_evidence_reconstruct_refuses_speculative_only_spectrum(): + """Evidence path requires COHERENT modes — SPECULATIVE must not masquerade.""" + hv = HolographicVaultStore(VaultStore()) + psi = _closed(0.18) + speculative_seal_from_contemplation( + hv, psi, substrate_hash="s", subject="m", mode_id="spec-only" + ) + with pytest.raises((HolographicVaultError, ValueError), match="empty|COHERENT|evidence|spectrum"): + reconstruct_as_evidence(hv, psi) + + +def test_evidence_reconstruct_accepts_coherent_modes(): + hv = HolographicVaultStore(VaultStore()) + psi = _closed(0.27, plane=8) + # Teaching corridor: authorized COHERENT seal (not via contemplation seam). + hv.seal_mode_reviewed(psi, authorized=True, mode_id="reviewed") + result = reconstruct_as_evidence(hv, psi) + assert result.standing == "evidence" + assert result.min_status is EpistemicStatus.COHERENT + assert float(np.linalg.norm(result.psi_hat)) > 0.0 + + +def test_mixed_spectrum_evidence_ignores_speculative(): + hv = HolographicVaultStore(VaultStore()) + psi_coh = _closed(0.4, plane=6) + psi_spec = _closed(0.9, plane=9) + speculative_seal_from_contemplation( + hv, psi_spec, substrate_hash="s", subject="spec", mode_id="spec" + ) + hv.seal_mode_reviewed(psi_coh, authorized=True, mode_id="coh") + # Evidence reconstruct should lock to COHERENT geometry, not SPECULATIVE. + result = reconstruct_as_evidence(hv, psi_coh) + assert result.standing == "evidence" + # Coefficient mass on the single COHERENT mode. + assert result.coeffs.shape[0] == 1 + + +# --- Serve quarantine ------------------------------------------------------- + + +def test_serve_runtime_does_not_import_wave_seam(): + runtime_path = _ROOT / "chat/runtime.py" + tree = ast.parse(runtime_path.read_text(encoding="utf-8")) + for node in ast.walk(tree): + if isinstance(node, ast.ImportFrom) and node.module: + assert "wave_seam" not in node.module + assert "wave_contemplation" not in node.module + if isinstance(node, ast.Import): + for alias in node.names: + assert "wave_seam" not in alias.name diff --git a/tests/test_third_door_cohesion.py b/tests/test_third_door_cohesion.py index 075c7aeb..8a818d18 100644 --- a/tests/test_third_door_cohesion.py +++ b/tests/test_third_door_cohesion.py @@ -61,15 +61,22 @@ def test_phase0_a04_serve_path_quarantines_wave_and_fibonacci(): "holographic_vault", "fibonacci_search", "atlas_packing", + "wave_seam", # P9 Trace A — contemplation only, never serve } + banned_substrings = ( + "wave_manifold", + "holographic_vault", + "fibonacci_search", + "atlas_packing", + "wave_seam", + ) for node in ast.walk(tree): if isinstance(node, ast.Import): for alias in node.names: leaf = alias.name.split(".")[-1] assert leaf not in banned_roots, f"banned import {alias.name}" - assert "wave_manifold" not in alias.name - assert "holographic_vault" not in alias.name - assert "fibonacci_search" not in alias.name + for ban in banned_substrings: + assert ban not in alias.name if isinstance(node, ast.ImportFrom) and node.module: mod = node.module for ban in banned_roots: