feat(wave): P10 Trace B energy boundary + multi-scale Fibonacci τ
Land ADR-0241 cohesion package P10:
- core/physics/wave_energy_boundary.py wires WaveManifold unitary residual
into energy profiles and trajectory energy gates (no free-floating residual).
- fibonacci_tau_schedule: τ_n = F_n · τ_0 constants table + recency bands.
- crystallization_for_holographic_seal: E0–E1 + closed residual may
SPECULATIVE-seal; dirty residual or hot classes refuse.
- Public fibonacci_number; serve quarantine includes wave_energy_boundary.
- Fidelity + ADR-0241 status updated.
Lane: pytest tests/test_adr_0241_wave_energy_boundary.py
tests/test_adr_0242_fibonacci.py tests/test_energy.py
tests/test_third_door_cohesion.py → green.
This commit is contained in:
parent
aa86f1ae35
commit
f123e0ea75
7 changed files with 401 additions and 2 deletions
|
|
@ -82,6 +82,16 @@ from core.physics.holographic_vault import (
|
|||
HolographicVaultStore,
|
||||
SealedMode,
|
||||
)
|
||||
from core.physics.wave_energy_boundary import (
|
||||
CrystallizationDecision,
|
||||
assess_wave_trajectory,
|
||||
crystallization_for_holographic_seal,
|
||||
energy_profile_from_wave,
|
||||
fibonacci_tau_schedule,
|
||||
recency_band_index,
|
||||
wave_unitary_residual,
|
||||
)
|
||||
from core.physics.fibonacci_search import fibonacci_number
|
||||
|
||||
__all__ = [
|
||||
"SalienceOperator", "SalienceMap", "FieldRegion",
|
||||
|
|
@ -116,4 +126,12 @@ __all__ = [
|
|||
"assess_trajectory", "energy_boundary_ok",
|
||||
"relative_holonomy", "trajectory_divergence",
|
||||
"HolographicVaultError", "HolographicVaultStore", "SealedMode",
|
||||
"CrystallizationDecision",
|
||||
"assess_wave_trajectory",
|
||||
"crystallization_for_holographic_seal",
|
||||
"energy_profile_from_wave",
|
||||
"fibonacci_tau_schedule",
|
||||
"recency_band_index",
|
||||
"wave_unitary_residual",
|
||||
"fibonacci_number",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class SearchTrace:
|
|||
certificate: dict = field(default_factory=dict)
|
||||
|
||||
|
||||
def _fibonacci(n: int) -> int:
|
||||
def fibonacci_number(n: int) -> int:
|
||||
"""F_0=0, F_1=1, … standard Fibonacci. n may be 0."""
|
||||
if n < 0:
|
||||
raise ValueError("fibonacci index must be non-negative")
|
||||
|
|
@ -51,6 +51,11 @@ def _fibonacci(n: int) -> int:
|
|||
return a
|
||||
|
||||
|
||||
def _fibonacci(n: int) -> int:
|
||||
"""Internal alias — prefer :func:`fibonacci_number` at call sites."""
|
||||
return fibonacci_number(n)
|
||||
|
||||
|
||||
def _assert_sampled_unimodality(eval_values: dict[float, float]) -> None:
|
||||
"""Fail-closed if sorted samples are not unimodal about the observed min."""
|
||||
sorted_points = sorted(eval_values.keys())
|
||||
|
|
@ -168,6 +173,8 @@ def fibonacci_section_search(
|
|||
|
||||
|
||||
__all__ = [
|
||||
"fibonacci_number",
|
||||
|
||||
"BoundedUnimodalObjective",
|
||||
"SearchTrace",
|
||||
"fibonacci_section_search",
|
||||
|
|
|
|||
219
core/physics/wave_energy_boundary.py
Normal file
219
core/physics/wave_energy_boundary.py
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
"""P10 Trace B — wave unitary residual → energy boundary + multi-scale τ.
|
||||
|
||||
ADR-0241 cohesion package P10:
|
||||
|
||||
1. **Wire wave residual into energy / trajectory gates** — coherence is not a
|
||||
free-floating float; it is :meth:`WaveManifold.measure_unitary_residual`.
|
||||
2. **Multi-scale recency** ``τ_n = F_n · τ_0`` as a constants table (not dogma).
|
||||
3. **Crystallization E0–E1 → holographic seal policy** — only low-energy
|
||||
classes with closed residual may SPECULATIVE-seal; COHERENT still requires
|
||||
authorized teaching review outside this module.
|
||||
|
||||
Serve path remains quarantined (no import from ``chat/runtime.py``).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Sequence
|
||||
|
||||
import numpy as np
|
||||
|
||||
from core.physics.energy import EnergyClass, EnergyProfile, FieldEnergyOperator
|
||||
from core.physics.fibonacci_search import fibonacci_number
|
||||
from core.physics.trajectory_invariants import (
|
||||
TrajectoryAssessment,
|
||||
assess_trajectory,
|
||||
)
|
||||
from core.physics.wave_manifold import WaveManifold
|
||||
|
||||
_DEFAULT_EPSILON_DRIFT = 1e-6
|
||||
_DEFAULT_TAU0 = 1.0
|
||||
|
||||
|
||||
def wave_unitary_residual(
|
||||
psi: np.ndarray,
|
||||
*,
|
||||
manifold: WaveManifold | None = None,
|
||||
epsilon_drift: float = _DEFAULT_EPSILON_DRIFT,
|
||||
) -> float:
|
||||
"""Unitary residual ‖ψ~ψ − 1‖_F dual-checked via WaveManifold."""
|
||||
m = manifold if manifold is not None else WaveManifold(epsilon_drift=epsilon_drift)
|
||||
return float(m.measure_unitary_residual(psi))
|
||||
|
||||
|
||||
def energy_profile_from_wave(
|
||||
psi: np.ndarray,
|
||||
*,
|
||||
operator: FieldEnergyOperator | None = None,
|
||||
manifold: WaveManifold | None = None,
|
||||
epsilon_drift: float = _DEFAULT_EPSILON_DRIFT,
|
||||
**compute_kwargs: object,
|
||||
) -> EnergyProfile:
|
||||
"""Build an EnergyProfile with coherence_residual from the wave field.
|
||||
|
||||
Structural axes (convergence, activation, aspect) remain caller-supplied;
|
||||
residual is never invented — it is measured on ψ.
|
||||
"""
|
||||
residual = wave_unitary_residual(
|
||||
psi, manifold=manifold, epsilon_drift=epsilon_drift
|
||||
)
|
||||
op = operator if operator is not None else FieldEnergyOperator()
|
||||
# FieldEnergyOperator.compute takes coherence_residual as float kwarg.
|
||||
kwargs = dict(compute_kwargs)
|
||||
kwargs["coherence_residual"] = residual
|
||||
return op.compute(**kwargs) # type: ignore[arg-type]
|
||||
|
||||
|
||||
def assess_wave_trajectory(
|
||||
versors: Sequence[np.ndarray],
|
||||
*,
|
||||
eps_trajectory: float = 1e-5,
|
||||
kappa: float = 1.0,
|
||||
dt: float = 1.0,
|
||||
epsilon_drift: float = _DEFAULT_EPSILON_DRIFT,
|
||||
manifold: WaveManifold | None = None,
|
||||
) -> TrajectoryAssessment:
|
||||
"""Trajectory gate with exertion energy from max wave unitary residual.
|
||||
|
||||
``E_exertion`` = max residual along the path.
|
||||
``E_sensory`` = ``epsilon_drift`` (GoldTether-scale sensory budget).
|
||||
Closed unit paths stay under the boundary when residual ≤ κ · ε.
|
||||
"""
|
||||
if not versors:
|
||||
# Delegate fail-closed empty handling to trajectory_invariants.
|
||||
return assess_trajectory(
|
||||
versors,
|
||||
E_exertion=0.0,
|
||||
E_sensory=float(epsilon_drift),
|
||||
eps_trajectory=eps_trajectory,
|
||||
kappa=kappa,
|
||||
dt=dt,
|
||||
)
|
||||
residuals = [
|
||||
wave_unitary_residual(v, manifold=manifold, epsilon_drift=epsilon_drift)
|
||||
for v in versors
|
||||
]
|
||||
e_exertion = float(max(residuals))
|
||||
e_sensory = float(epsilon_drift)
|
||||
return assess_trajectory(
|
||||
versors,
|
||||
E_exertion=e_exertion,
|
||||
E_sensory=e_sensory,
|
||||
eps_trajectory=eps_trajectory,
|
||||
kappa=kappa,
|
||||
dt=dt,
|
||||
)
|
||||
|
||||
|
||||
def fibonacci_tau_schedule(
|
||||
tau0: float = _DEFAULT_TAU0,
|
||||
*,
|
||||
levels: int = 8,
|
||||
) -> tuple[float, ...]:
|
||||
"""Multi-scale recency hierarchy τ_n = F_n · τ_0 for n = 1..levels.
|
||||
|
||||
Constants table only — not a runtime dogma. F_1=1, F_2=1, F_3=2, …
|
||||
"""
|
||||
t0 = float(tau0)
|
||||
if not (t0 > 0.0) or t0 != t0: # NaN check via !=
|
||||
raise ValueError("tau0 must be a positive finite scalar")
|
||||
n = int(levels)
|
||||
if n < 1:
|
||||
raise ValueError("levels must be >= 1")
|
||||
return tuple(float(fibonacci_number(i) * t0) for i in range(1, n + 1))
|
||||
|
||||
|
||||
def recency_band_index(age: float, taus: Sequence[float]) -> int:
|
||||
"""Smallest band index with age ≤ τ_n, or ``len(taus)`` if beyond schedule."""
|
||||
a = float(age)
|
||||
if a < 0.0:
|
||||
raise ValueError("age must be non-negative")
|
||||
for i, tau in enumerate(taus):
|
||||
if a <= float(tau) + 1e-15:
|
||||
return i
|
||||
return len(taus)
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class CrystallizationDecision:
|
||||
"""E0–E1 crystallization gate aligned with holographic SPECULATIVE seal policy."""
|
||||
|
||||
energy: EnergyProfile
|
||||
unitary_residual: float
|
||||
vault_candidate: bool
|
||||
residual_closed: bool
|
||||
may_speculative_seal: bool
|
||||
reason: str
|
||||
epsilon_drift: float
|
||||
|
||||
def as_dict(self) -> dict[str, object]:
|
||||
return {
|
||||
"energy_class": self.energy.energy_class.value,
|
||||
"unitary_residual": self.unitary_residual,
|
||||
"vault_candidate": self.vault_candidate,
|
||||
"residual_closed": self.residual_closed,
|
||||
"may_speculative_seal": self.may_speculative_seal,
|
||||
"reason": self.reason,
|
||||
"epsilon_drift": self.epsilon_drift,
|
||||
}
|
||||
|
||||
|
||||
def crystallization_for_holographic_seal(
|
||||
psi: np.ndarray,
|
||||
*,
|
||||
epsilon_drift: float = _DEFAULT_EPSILON_DRIFT,
|
||||
manifold: WaveManifold | None = None,
|
||||
operator: FieldEnergyOperator | None = None,
|
||||
**energy_kwargs: object,
|
||||
) -> CrystallizationDecision:
|
||||
"""Decide whether ψ may enter the SPECULATIVE holographic seal path.
|
||||
|
||||
Policy (Trace B ↔ Trace A):
|
||||
* residual must be closed (≤ epsilon_drift) — fail-closed, no repair
|
||||
* energy class must be vault_candidate (E0/E1)
|
||||
* both required for ``may_speculative_seal``
|
||||
|
||||
COHERENT promotion is never authorized here.
|
||||
"""
|
||||
residual = wave_unitary_residual(
|
||||
psi, manifold=manifold, epsilon_drift=epsilon_drift
|
||||
)
|
||||
energy = energy_profile_from_wave(
|
||||
psi,
|
||||
operator=operator,
|
||||
manifold=manifold,
|
||||
epsilon_drift=epsilon_drift,
|
||||
**energy_kwargs,
|
||||
)
|
||||
vault = bool(energy.energy_class.vault_candidate)
|
||||
closed = bool(residual <= float(epsilon_drift))
|
||||
may_seal = vault and closed
|
||||
if may_seal:
|
||||
reason = "e0_e1_closed_residual_speculative_seal_ok"
|
||||
elif not closed:
|
||||
reason = "residual_not_closed"
|
||||
elif not vault:
|
||||
reason = "energy_class_not_vault_candidate"
|
||||
else:
|
||||
reason = "refused"
|
||||
return CrystallizationDecision(
|
||||
energy=energy,
|
||||
unitary_residual=residual,
|
||||
vault_candidate=vault,
|
||||
residual_closed=closed,
|
||||
may_speculative_seal=may_seal,
|
||||
reason=reason,
|
||||
epsilon_drift=float(epsilon_drift),
|
||||
)
|
||||
|
||||
|
||||
__all__ = [
|
||||
"CrystallizationDecision",
|
||||
"assess_wave_trajectory",
|
||||
"crystallization_for_holographic_seal",
|
||||
"energy_profile_from_wave",
|
||||
"fibonacci_tau_schedule",
|
||||
"recency_band_index",
|
||||
"wave_unitary_residual",
|
||||
]
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# ADR-0241: Wave-Field Driven Hyperbolic Atlas and Resonant Algebraic Cognition
|
||||
|
||||
**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
|
||||
**Status**: Proposed — substrate + entity suite + ADR-0242 packing/Fibonacci + P9 Trace A wave_seam + P10 Trace B wave_energy_boundary (residual→energy/τ/crystallization); remaining cohesion package P12 governance (+ optional P11 Rust); acceptance path: Joshua review
|
||||
**Date**: 2026-07-13
|
||||
**Deciders**: Joshua Shay + multi-model R&D
|
||||
**Traceability**: Issue #14, parent #10
|
||||
|
|
|
|||
|
|
@ -302,6 +302,7 @@ PY
|
|||
| 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) |
|
||||
| Energy boundary + multi-scale τ (P10 Trace B) | 🟢 `wave_energy_boundary` (wave residual → energy/trajectory; τ_n=F_n·τ_0; E0–E1 crystallization) |
|
||||
|
||||
### Subsumption map (Slice 2–3)
|
||||
| Operator | Delegation |
|
||||
|
|
@ -337,6 +338,7 @@ PY
|
|||
| 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 |
|
||||
| Energy boundary + multi-scale τ (P10) — 🟢 wave_energy_boundary | ADR-0241 P10 |
|
||||
| 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.
|
||||
|
|
|
|||
151
tests/test_adr_0241_wave_energy_boundary.py
Normal file
151
tests/test_adr_0241_wave_energy_boundary.py
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
"""P10 Trace B — wave residual → energy boundary + Fibonacci τ + crystallization.
|
||||
|
||||
ADR-0241 cohesion package P10:
|
||||
* Unitary residual from WaveManifold feeds energy / trajectory gates.
|
||||
* Multi-scale recency τ_n = F_n · τ_0 is a constants table (not dogma).
|
||||
* E0–E1 crystallization + closed residual may SPECULATIVE-seal; else refuse.
|
||||
* Serve remains quarantined from this module.
|
||||
"""
|
||||
|
||||
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.physics.energy import EnergyClass
|
||||
from core.physics.wave_energy_boundary import (
|
||||
CrystallizationDecision,
|
||||
assess_wave_trajectory,
|
||||
crystallization_for_holographic_seal,
|
||||
energy_profile_from_wave,
|
||||
fibonacci_tau_schedule,
|
||||
recency_band_index,
|
||||
wave_unitary_residual,
|
||||
)
|
||||
from core.physics.trajectory_invariants import TrajectoryInvariantError
|
||||
|
||||
_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)
|
||||
|
||||
|
||||
def _dirty() -> np.ndarray:
|
||||
v = np.zeros(32, dtype=np.float64)
|
||||
v[0] = 0.5
|
||||
v[1] = 0.5
|
||||
return v
|
||||
|
||||
|
||||
# --- Wave residual wiring ---------------------------------------------------
|
||||
|
||||
|
||||
def test_wave_unitary_residual_closed_under_eps():
|
||||
r = wave_unitary_residual(_closed(0.25))
|
||||
assert r < 1e-6
|
||||
|
||||
|
||||
def test_wave_unitary_residual_dirty_above_eps():
|
||||
r = wave_unitary_residual(_dirty())
|
||||
assert r > 1e-6
|
||||
|
||||
|
||||
def test_energy_profile_from_wave_uses_residual():
|
||||
profile = energy_profile_from_wave(_closed(0.1))
|
||||
assert profile.coherence_residual < 1e-6
|
||||
# Low residual + defaults → crystallizable class (E0/E1).
|
||||
assert profile.energy_class in {EnergyClass.E0, EnergyClass.E1}
|
||||
|
||||
|
||||
def test_energy_profile_from_wave_high_residual_feeds_raw():
|
||||
profile = energy_profile_from_wave(_dirty())
|
||||
# Operator clamps residual into [0,1] for the scalar mix.
|
||||
assert profile.coherence_residual > 0.0
|
||||
|
||||
|
||||
def test_assess_wave_trajectory_closed_path_energy_ok():
|
||||
steps = [_closed(0.1 * i, plane=6) for i in range(1, 5)]
|
||||
assessment = assess_wave_trajectory(steps)
|
||||
assert assessment.energy_ok is True
|
||||
assert assessment.n_steps == 4
|
||||
assert assessment.within_replay_bound is True
|
||||
|
||||
|
||||
def test_assess_wave_trajectory_refuses_empty():
|
||||
with pytest.raises(TrajectoryInvariantError):
|
||||
assess_wave_trajectory([])
|
||||
|
||||
|
||||
# --- Fibonacci multi-scale τ ------------------------------------------------
|
||||
|
||||
|
||||
def test_fibonacci_tau_schedule_matches_F_n_tau0():
|
||||
# F_1=1, F_2=1, F_3=2, F_4=3, F_5=5
|
||||
taus = fibonacci_tau_schedule(tau0=0.5, levels=5)
|
||||
assert taus == (0.5, 0.5, 1.0, 1.5, 2.5)
|
||||
|
||||
|
||||
def test_fibonacci_tau_schedule_rejects_bad_inputs():
|
||||
with pytest.raises(ValueError):
|
||||
fibonacci_tau_schedule(tau0=0.0, levels=3)
|
||||
with pytest.raises(ValueError):
|
||||
fibonacci_tau_schedule(tau0=1.0, levels=0)
|
||||
|
||||
|
||||
def test_recency_band_index_progressive():
|
||||
taus = fibonacci_tau_schedule(tau0=1.0, levels=5) # 1,1,2,3,5
|
||||
assert recency_band_index(0.5, taus) == 0
|
||||
assert recency_band_index(1.0, taus) == 0
|
||||
assert recency_band_index(1.5, taus) == 2
|
||||
assert recency_band_index(10.0, taus) == len(taus) # beyond schedule
|
||||
|
||||
|
||||
# --- Crystallization ↔ holographic seal policy ------------------------------
|
||||
|
||||
|
||||
def test_crystallization_closed_e0_may_speculative_seal():
|
||||
decision = crystallization_for_holographic_seal(_closed(0.12))
|
||||
assert isinstance(decision, CrystallizationDecision)
|
||||
assert decision.residual_closed is True
|
||||
assert decision.vault_candidate is True
|
||||
assert decision.may_speculative_seal is True
|
||||
assert decision.energy.energy_class.vault_candidate is True
|
||||
|
||||
|
||||
def test_crystallization_dirty_refuses_seal():
|
||||
decision = crystallization_for_holographic_seal(_dirty())
|
||||
assert decision.residual_closed is False
|
||||
assert decision.may_speculative_seal is False
|
||||
|
||||
|
||||
def test_crystallization_high_activity_not_vault_candidate():
|
||||
# Force E3/E4 via structural inputs while residual stays closed.
|
||||
decision = crystallization_for_holographic_seal(
|
||||
_closed(0.05),
|
||||
convergence_density=20,
|
||||
activation_count=20,
|
||||
current_cycle=1,
|
||||
last_activation_cycle=1,
|
||||
anchor_adjacent=True,
|
||||
)
|
||||
assert decision.residual_closed is True
|
||||
assert decision.vault_candidate is False
|
||||
assert decision.may_speculative_seal is False
|
||||
|
||||
|
||||
# --- Serve quarantine -------------------------------------------------------
|
||||
|
||||
|
||||
def test_serve_runtime_does_not_import_wave_energy_boundary():
|
||||
tree = ast.parse((_ROOT / "chat/runtime.py").read_text(encoding="utf-8"))
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.ImportFrom) and node.module:
|
||||
assert "wave_energy_boundary" not in node.module
|
||||
if isinstance(node, ast.Import):
|
||||
for alias in node.names:
|
||||
assert "wave_energy_boundary" not in alias.name
|
||||
|
|
@ -62,6 +62,7 @@ def test_phase0_a04_serve_path_quarantines_wave_and_fibonacci():
|
|||
"fibonacci_search",
|
||||
"atlas_packing",
|
||||
"wave_seam", # P9 Trace A — contemplation only, never serve
|
||||
"wave_energy_boundary", # P10 Trace B — energy/τ gate, never serve
|
||||
}
|
||||
banned_substrings = (
|
||||
"wave_manifold",
|
||||
|
|
@ -69,6 +70,7 @@ def test_phase0_a04_serve_path_quarantines_wave_and_fibonacci():
|
|||
"fibonacci_search",
|
||||
"atlas_packing",
|
||||
"wave_seam",
|
||||
"wave_energy_boundary",
|
||||
)
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.Import):
|
||||
|
|
|
|||
Loading…
Reference in a new issue