fix(physics): close A-04 transitive serve breach — lazy Tier-2 barrel exports + process-level guard

Importing chat.runtime transitively loaded 5 off-serving modules
(wave_manifold, holographic_vault, fibonacci_search, multi_scale_energy,
wave_energy_boundary) through the core/physics package barrel — falsifying
the 'serve path not wired' acceptance row while the direct-AST A-04 pin
stayed green.

Reconciliation (ruled 2026-07-15): one substrate, two tiers.
- T1 sanctioned serve substrate: wave_manifold (goldtether/surprise/
  biography delegate to it) — stays eager, removed from the A-04 ban list.
- T2 off-serving (holographic_vault, fibonacci_search, wave_energy_boundary,
  multi_scale_energy): converted to PEP 562 lazy __getattr__ exports so the
  serve process never loads them; 'from core.physics import X' still works
  for off-serving callers. TYPE_CHECKING block keeps static analysis intact.
- New tests/test_serve_quarantine_transitive.py enforces the process-level
  invariant via a clean-interpreter sys.modules probe (RED against the old
  barrel, GREEN now).

Evidence: docs/research/adr-0241-0242-adversarial-and-fidelity-findings.md
(Finding #2). 179 affected tests green.
This commit is contained in:
Shay 2026-07-15 12:48:45 -07:00
parent 4853a55ced
commit c8160cacba
3 changed files with 153 additions and 32 deletions

View file

@ -78,36 +78,81 @@ from core.physics.trajectory_invariants import (
relative_holonomy,
trajectory_divergence,
)
from core.physics.holographic_vault import (
HolographicVaultError,
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 (
BASELINE_KAPPA,
BoundedUnimodalObjective,
FibonacciSearchCertificate,
OptimizationFailure,
fibonacci_number,
fibonacci_section_search,
propose_kappa_from_search,
)
from core.physics.multi_scale_energy import (
comparative_residual_separation,
dyadic_tau_schedule,
multi_scale_energy_for_schedule,
multi_scale_energy_vector,
schedule_mid_span_fraction,
)
# --- Off-serving (Tier-2) LAZY exports — serve quarantine (ADR-0241/0242) --------
# These are OFF-SERVING extensions: durable memory (holographic_vault) and
# evidence-gated optimization / research thermodynamics (fibonacci_search,
# wave_energy_boundary, multi_scale_energy). Eager-importing them here would drag
# the whole substrate into the serve process (chat.runtime) via this package barrel
# — the A-04 transitive breach documented in
# docs/research/adr-0241-0242-adversarial-and-fidelity-findings.md (Finding #2).
# They stay importable as `from core.physics import X` via PEP 562 __getattr__, but
# resolve lazily only on explicit off-serving access. Guarded by
# tests/test_serve_quarantine_transitive.py.
#
# NOTE (Joshua ruling 2026-07-15): wave_manifold is Tier-1 sanctioned serve
# substrate (goldtether/surprise/biography delegate to it) and stays eager above.
_LAZY_EXPORTS: dict[str, str] = {
# holographic_vault — durable memory (L10 / persistence gate)
"HolographicVaultError": "core.physics.holographic_vault",
"HolographicVaultStore": "core.physics.holographic_vault",
"SealedMode": "core.physics.holographic_vault",
# wave_energy_boundary — P10 Trace B energy/τ gate (never serve)
"CrystallizationDecision": "core.physics.wave_energy_boundary",
"assess_wave_trajectory": "core.physics.wave_energy_boundary",
"crystallization_for_holographic_seal": "core.physics.wave_energy_boundary",
"energy_profile_from_wave": "core.physics.wave_energy_boundary",
"fibonacci_tau_schedule": "core.physics.wave_energy_boundary",
"recency_band_index": "core.physics.wave_energy_boundary",
"wave_unitary_residual": "core.physics.wave_energy_boundary",
# fibonacci_search — V1 evidence-gated optimization (never serve)
"BASELINE_KAPPA": "core.physics.fibonacci_search",
"BoundedUnimodalObjective": "core.physics.fibonacci_search",
"FibonacciSearchCertificate": "core.physics.fibonacci_search",
"OptimizationFailure": "core.physics.fibonacci_search",
"fibonacci_number": "core.physics.fibonacci_search",
"fibonacci_section_search": "core.physics.fibonacci_search",
"propose_kappa_from_search": "core.physics.fibonacci_search",
# multi_scale_energy — V2 research multi-band E_n(t) (never serve)
"comparative_residual_separation": "core.physics.multi_scale_energy",
"dyadic_tau_schedule": "core.physics.multi_scale_energy",
"multi_scale_energy_for_schedule": "core.physics.multi_scale_energy",
"multi_scale_energy_vector": "core.physics.multi_scale_energy",
"schedule_mid_span_fraction": "core.physics.multi_scale_energy",
}
from typing import TYPE_CHECKING
if TYPE_CHECKING: # static-analysis only — never imported at runtime (serve quarantine)
from core.physics.holographic_vault import (
HolographicVaultError,
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 (
BASELINE_KAPPA,
BoundedUnimodalObjective,
FibonacciSearchCertificate,
OptimizationFailure,
fibonacci_number,
fibonacci_section_search,
propose_kappa_from_search,
)
from core.physics.multi_scale_energy import (
comparative_residual_separation,
dyadic_tau_schedule,
multi_scale_energy_for_schedule,
multi_scale_energy_vector,
schedule_mid_span_fraction,
)
__all__ = [
"SalienceOperator", "SalienceMap", "FieldRegion",
@ -163,3 +208,16 @@ __all__ = [
"multi_scale_energy_vector",
"schedule_mid_span_fraction",
]
def __getattr__(name: str): # PEP 562 — lazy off-serving (Tier-2) exports
module = _LAZY_EXPORTS.get(name)
if module is None:
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
import importlib
return getattr(importlib.import_module(module), name)
def __dir__() -> list[str]:
return sorted(set(globals()) | set(_LAZY_EXPORTS))

View file

@ -0,0 +1,60 @@
"""A-04 (transitive) — the serve process must not LOAD the wave/fibonacci substrate.
The existing `test_phase0_a04_serve_path_quarantines_wave_and_fibonacci` walks only
`chat/runtime.py`'s own AST import nodes, so it catches DIRECT imports only. The
stated invariant is process-level ("serve path stays quarantined"; modules labelled
"never serve"). This pin enforces the stated invariant: importing `chat.runtime` in
a clean interpreter must not pull any banned module into `sys.modules`.
RED until the `core/physics/__init__.py` barrel stops eagerly importing the
off-serving substrate (Finding #2, docs/research/adr-0241-0242-adversarial-and-fidelity-findings.md).
"""
from __future__ import annotations
import subprocess
import sys
from pathlib import Path
_ROOT = Path(__file__).resolve().parents[1]
# Genuinely off-serving; must never load into the serve process.
_BANNED = (
"core.physics.holographic_vault",
"core.physics.fibonacci_search",
"core.physics.fibonacci_word_schedule",
"core.physics.atlas_packing",
"core.physics.wave_seam",
"core.physics.wave_energy_boundary",
"core.physics.multi_scale_energy",
"core.physics.sensorium_wave_feed",
# NOTE: core.physics.wave_manifold is intentionally excluded pending the
# Joshua design ruling (goldtether delegates to it). Add it here if the
# ruling is "quarantine wave_manifold for real".
)
def test_import_chat_runtime_does_not_load_offserving_substrate():
probe = (
"import importlib, sys, json;"
"importlib.import_module('chat.runtime');"
f"banned={list(_BANNED)!r};"
"leaked=sorted(m for m in sys.modules for b in banned if m==b or m.startswith(b+'.'));"
"print(json.dumps(leaked))"
)
result = subprocess.run(
[sys.executable, "-c", probe],
cwd=str(_ROOT),
capture_output=True,
text=True,
env={"PYTHONPATH": str(_ROOT), "PATH": ""},
)
assert result.returncode == 0, f"probe failed: {result.stderr[-2000:]}"
leaked = result.stdout.strip().splitlines()[-1]
import json as _json
leaked_list = _json.loads(leaked)
assert not leaked_list, (
"serve process transitively loaded off-serving modules "
f"(A-04 breach via core/physics barrel): {leaked_list}"
)

View file

@ -56,8 +56,12 @@ def test_phase0_a04_serve_path_quarantines_wave_and_fibonacci():
runtime_path = _ROOT / "chat/runtime.py"
src = runtime_path.read_text()
tree = ast.parse(src)
# Tier-2 OFF-SERVING modules only. wave_manifold is Tier-1 sanctioned serve
# substrate (goldtether/surprise/biography delegate to it) per the 2026-07-15
# reconciliation — see docs/research/adr-0241-0242-adversarial-and-fidelity-findings.md.
# Process-level (transitive) quarantine of these is enforced by
# tests/test_serve_quarantine_transitive.py; this pin catches direct imports.
banned_roots = {
"wave_manifold",
"holographic_vault",
"fibonacci_search",
"fibonacci_word_schedule",
@ -68,7 +72,6 @@ def test_phase0_a04_serve_path_quarantines_wave_and_fibonacci():
"sensorium_wave_feed", # D7 I-04 sensorium→ψ feed, never serve
}
banned_substrings = (
"wave_manifold",
"holographic_vault",
"fibonacci_search",
"fibonacci_word_schedule",