Merge pull request 'feat(adr-0243): Phase 3 Lane C — ADR-0240 PASS → integrate_biography wiring' (#58) from feat/adr-0243-phase3-lane-c-biography into main
This commit is contained in:
commit
d5db97f0e2
5 changed files with 444 additions and 0 deletions
|
|
@ -144,6 +144,11 @@ _LAZY_EXPORTS: dict[str, str] = {
|
|||
"propositional_entails": "core.physics.cognitive_lifecycle",
|
||||
"relax_to_ground": "core.physics.cognitive_lifecycle",
|
||||
"uniform_assignment_state": "core.physics.cognitive_lifecycle",
|
||||
# biography_wiring — ADR-0243 §2.5 validated-PASS → biography integration (never serve)
|
||||
"BiographyIntegrationError": "core.physics.biography_wiring",
|
||||
"BiographyProvenanceRecord": "core.physics.biography_wiring",
|
||||
"biography_provenance_record": "core.physics.biography_wiring",
|
||||
"integrate_validated_biography": "core.physics.biography_wiring",
|
||||
}
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
|
@ -206,6 +211,12 @@ if TYPE_CHECKING: # static-analysis only — never imported at runtime (serve q
|
|||
relax_to_ground,
|
||||
uniform_assignment_state,
|
||||
)
|
||||
from core.physics.biography_wiring import (
|
||||
BiographyIntegrationError,
|
||||
BiographyProvenanceRecord,
|
||||
biography_provenance_record,
|
||||
integrate_validated_biography,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"SalienceOperator", "SalienceMap", "FieldRegion",
|
||||
|
|
@ -285,6 +296,10 @@ __all__ = [
|
|||
"propositional_entails",
|
||||
"relax_to_ground",
|
||||
"uniform_assignment_state",
|
||||
"BiographyIntegrationError",
|
||||
"BiographyProvenanceRecord",
|
||||
"biography_provenance_record",
|
||||
"integrate_validated_biography",
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
219
core/physics/biography_wiring.py
Normal file
219
core/physics/biography_wiring.py
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
"""core.physics.biography_wiring — ADR-0240 PASS → biography integration (ADR-0243 §2.5).
|
||||
|
||||
First live caller of :func:`core.physics.biography.integrate_biography`.
|
||||
Gates on a validation report's report-level PASS signal (``report.wrong == 0``
|
||||
— the harness has no literal PASS type; ``wrong == 0`` is its acceptance
|
||||
criterion) and re-asserts the I-01 closure invariant at this call site,
|
||||
failing closed with a typed error.
|
||||
|
||||
Ruling (Shay, 2026-07-17, Lane C open question): this wiring is a *direct*
|
||||
integration, not a proposal-gated mutation — ``integrate_biography`` is a pure
|
||||
recompute (reconstruction-over-storage; the blade is derived state, never
|
||||
persisted), so D-5/I-03 proposal-only discipline does not attach here. The
|
||||
ruling is structurally pinned: this module must import no vault store and no
|
||||
``evals`` package (guarded by tests/test_adr_0243_biography_wiring.py). Any
|
||||
future durable blade storage or trajectory auto-sealing breaks that pin and
|
||||
reopens the mutation-vs-proposal question.
|
||||
|
||||
Report-level granularity is deliberate: ADR-0243 §2.5 integrates a validated
|
||||
*sequence*, and wrong=0 doctrine forbids cherry-picking correct transfers out
|
||||
of a session that also produced wrongs. Refusals do not block (the harness's
|
||||
own ``all_correct_or_refused`` semantics), but a session with zero correct
|
||||
transfers has validated nothing and is refused — no confabulated wisdom.
|
||||
|
||||
The report carries no versors (scalar evidence only) and the harness is
|
||||
consumed as-is, so the caller supplies the lived trajectory alongside the
|
||||
report; the provenance record binds the two by content hash.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Mapping, Protocol, Sequence
|
||||
|
||||
import numpy as np
|
||||
|
||||
from algebra.backend import versor_condition
|
||||
from core.physics.biography import BiographyHolonomyBlade, integrate_biography
|
||||
|
||||
_CLOSURE = 1e-6
|
||||
_PROVENANCE_SCHEMA = "biography_provenance_v1"
|
||||
_ADR_REFS = ("ADR-0240", "ADR-0243")
|
||||
|
||||
|
||||
class BiographyIntegrationError(ValueError):
|
||||
"""Fail-closed refusal from :func:`integrate_validated_biography`.
|
||||
|
||||
Subclasses ``ValueError`` so a caller that fail-closes on ``ValueError``
|
||||
records it as a refusal rather than crashing (same contract as
|
||||
:class:`core.physics.surprise.SurpriseResidualError`).
|
||||
"""
|
||||
|
||||
def __init__(self, reason: str, **disclosure) -> None:
|
||||
self.reason = reason
|
||||
self.disclosure = dict(disclosure)
|
||||
super().__init__(f"biography integration refused [{reason}]: {self.disclosure}")
|
||||
|
||||
|
||||
class TransferCaseResult(Protocol):
|
||||
"""Per-case slice of the ADR-0240 report this wiring consumes."""
|
||||
|
||||
case_id: str
|
||||
residual: float
|
||||
correct: bool
|
||||
refused: bool
|
||||
reason: str
|
||||
|
||||
|
||||
class ValidationReportLike(Protocol):
|
||||
"""Structural view of ``evals.analogical_transfer.harness.AnalogicalTransferReport``.
|
||||
|
||||
Typed structurally so core.physics does not import ``evals`` (layering:
|
||||
evals composes core, never the reverse). Any validated-experience source
|
||||
exposing this shape can drive biography integration.
|
||||
"""
|
||||
|
||||
results: Sequence[TransferCaseResult]
|
||||
counts: Mapping[str, int]
|
||||
max_residual: float
|
||||
wrong: int
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class BiographyProvenanceRecord:
|
||||
"""Append-only audit record binding a PASS report to a biography integration.
|
||||
|
||||
An evidence record, not a proposal — nothing awaits ratification (the blade
|
||||
is derived state; see module docstring ruling). Closure-proof discipline
|
||||
modeled on :class:`core.physics.self_authorship.AuthorshipProposal`; the
|
||||
append-only audit role mirrors :class:`core.physics.identity.TurnEvent`.
|
||||
"""
|
||||
|
||||
record_id: str
|
||||
schema_version: str
|
||||
n_cases: int
|
||||
counts: Mapping[str, int]
|
||||
wrong: int
|
||||
max_residual: float
|
||||
case_outcomes: tuple[tuple[str, str], ...] # (case_id, reason), report order
|
||||
trajectory_hash: str
|
||||
n_steps: int
|
||||
alpha: float
|
||||
closure_proof: Mapping[str, float]
|
||||
adr_refs: tuple[str, ...]
|
||||
|
||||
def as_dict(self) -> dict[str, Any]:
|
||||
return {
|
||||
"record_id": self.record_id,
|
||||
"schema_version": self.schema_version,
|
||||
"n_cases": self.n_cases,
|
||||
"counts": dict(self.counts),
|
||||
"wrong": self.wrong,
|
||||
"max_residual": self.max_residual,
|
||||
"case_outcomes": [list(pair) for pair in self.case_outcomes],
|
||||
"trajectory_hash": self.trajectory_hash,
|
||||
"n_steps": self.n_steps,
|
||||
"alpha": self.alpha,
|
||||
"closure_proof": dict(self.closure_proof),
|
||||
"adr_refs": list(self.adr_refs),
|
||||
}
|
||||
|
||||
|
||||
def _content_id(payload: Mapping[str, Any]) -> str:
|
||||
raw = json.dumps(payload, sort_keys=True, separators=(",", ":"), default=str)
|
||||
return hashlib.sha256(raw.encode("utf-8")).hexdigest()[:24]
|
||||
|
||||
|
||||
def biography_provenance_record(
|
||||
report: ValidationReportLike,
|
||||
blade: BiographyHolonomyBlade,
|
||||
*,
|
||||
alpha: float,
|
||||
) -> BiographyProvenanceRecord:
|
||||
"""Build the append-only provenance record for one validated integration."""
|
||||
counts = {k: int(v) for k, v in sorted(report.counts.items())}
|
||||
case_outcomes = tuple((r.case_id, r.reason) for r in report.results)
|
||||
closure_proof = {
|
||||
"blade_closure": float(blade.closure),
|
||||
"blade_versor_condition": float(versor_condition(blade.blade)),
|
||||
"closure_tol": _CLOSURE,
|
||||
}
|
||||
body = {
|
||||
"schema_version": _PROVENANCE_SCHEMA,
|
||||
"n_cases": len(report.results),
|
||||
"counts": counts,
|
||||
"wrong": int(report.wrong),
|
||||
"max_residual": float(report.max_residual),
|
||||
"case_outcomes": [list(pair) for pair in case_outcomes],
|
||||
"trajectory_hash": blade.trajectory_hash,
|
||||
"n_steps": int(blade.n_steps),
|
||||
"alpha": float(alpha),
|
||||
"closure_proof": closure_proof,
|
||||
"adr_refs": list(_ADR_REFS),
|
||||
}
|
||||
return BiographyProvenanceRecord(
|
||||
record_id=f"bioprov-{_content_id(body)}",
|
||||
schema_version=_PROVENANCE_SCHEMA,
|
||||
n_cases=len(report.results),
|
||||
counts=counts,
|
||||
wrong=int(report.wrong),
|
||||
max_residual=float(report.max_residual),
|
||||
case_outcomes=case_outcomes,
|
||||
trajectory_hash=blade.trajectory_hash,
|
||||
n_steps=int(blade.n_steps),
|
||||
alpha=float(alpha),
|
||||
closure_proof=closure_proof,
|
||||
adr_refs=_ADR_REFS,
|
||||
)
|
||||
|
||||
|
||||
def integrate_validated_biography(
|
||||
report: ValidationReportLike,
|
||||
trajectory: Sequence[np.ndarray],
|
||||
*,
|
||||
alpha: float = 0.5,
|
||||
) -> tuple[BiographyHolonomyBlade, BiographyProvenanceRecord]:
|
||||
"""Integrate a lived trajectory into biography, gated on report-level PASS.
|
||||
|
||||
Refuses (typed, fail-closed) unless the report validated at least one
|
||||
transfer with zero wrongs. Re-asserts I-01 closure on the returned blade at
|
||||
this call site (modeled on tests/test_third_door_cohesion.py I-01) rather
|
||||
than trusting the callee's internal checks.
|
||||
"""
|
||||
n_cases = len(report.results)
|
||||
if n_cases == 0:
|
||||
raise BiographyIntegrationError("empty_report")
|
||||
if int(report.wrong) != 0:
|
||||
raise BiographyIntegrationError(
|
||||
"report_not_pass",
|
||||
wrong=int(report.wrong),
|
||||
counts={k: int(v) for k, v in sorted(report.counts.items())},
|
||||
)
|
||||
n_correct = sum(1 for r in report.results if r.correct)
|
||||
if n_correct == 0:
|
||||
# wrong == 0 with everything refused validates nothing (ADR-0243 §2.5
|
||||
# integrates a *validated* sequence) — refuse, no confabulated wisdom.
|
||||
raise BiographyIntegrationError(
|
||||
"no_validated_transfers",
|
||||
n_cases=n_cases,
|
||||
refused=sum(1 for r in report.results if r.refused),
|
||||
)
|
||||
|
||||
try:
|
||||
blade = integrate_biography(trajectory, alpha=alpha)
|
||||
except ValueError as exc:
|
||||
raise BiographyIntegrationError("trajectory_rejected", detail=str(exc)) from exc
|
||||
|
||||
cond = float(versor_condition(blade.blade))
|
||||
if blade.closure >= _CLOSURE or cond >= _CLOSURE:
|
||||
raise BiographyIntegrationError(
|
||||
"i01_closure_violation",
|
||||
closure=float(blade.closure),
|
||||
versor_condition=cond,
|
||||
closure_tol=_CLOSURE,
|
||||
)
|
||||
|
||||
record = biography_provenance_record(report, blade, alpha=alpha)
|
||||
return blade, record
|
||||
207
tests/test_adr_0243_biography_wiring.py
Normal file
207
tests/test_adr_0243_biography_wiring.py
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
"""ADR-0243 §2.5 Lane C — ADR-0240 harness PASS → integrate_biography wiring.
|
||||
|
||||
Covers: live-harness PASS drives a real integration with I-01 asserts and a
|
||||
provenance record; non-PASS reports must not integrate (fail-closed typed
|
||||
refusals); the direct-integration ruling is structurally pinned (wiring module
|
||||
imports no vault store and no evals package).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import dataclasses
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from algebra.rotor import make_rotor_from_angle
|
||||
from algebra.versor import versor_condition
|
||||
from core.physics.biography import BiographyHolonomyBlade, integrate_biography
|
||||
from core.physics.biography_wiring import (
|
||||
BiographyIntegrationError,
|
||||
integrate_validated_biography,
|
||||
)
|
||||
from evals.analogical_transfer.harness import (
|
||||
AnalogicalTransferReport,
|
||||
TransferResult,
|
||||
make_fixture_pair,
|
||||
run_analogical_transfer,
|
||||
)
|
||||
|
||||
_CLOSURE = 1e-6
|
||||
_ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def _trajectory() -> list[np.ndarray]:
|
||||
return [make_rotor_from_angle(0.1 * (i + 1), bivector_idx=6 + (i % 3)) for i in range(4)]
|
||||
|
||||
|
||||
def _result(
|
||||
case_id: str = "c1",
|
||||
*,
|
||||
correct: bool = True,
|
||||
refused: bool = False,
|
||||
reason: str = "transfer_ok",
|
||||
residual: float = 0.01,
|
||||
) -> TransferResult:
|
||||
return TransferResult(
|
||||
case_id=case_id,
|
||||
residual=residual,
|
||||
goldtether_before=0.0,
|
||||
goldtether_after=0.0,
|
||||
correct=correct,
|
||||
refused=refused,
|
||||
reason=reason,
|
||||
)
|
||||
|
||||
|
||||
def _report(results: list[TransferResult]) -> AnalogicalTransferReport:
|
||||
counts = {
|
||||
"correct": sum(1 for r in results if r.correct),
|
||||
"wrong": sum(1 for r in results if not r.correct and not r.refused),
|
||||
"refused": sum(1 for r in results if r.refused),
|
||||
}
|
||||
finite = [r.residual for r in results if np.isfinite(r.residual)]
|
||||
return AnalogicalTransferReport(
|
||||
results=tuple(results),
|
||||
counts=counts,
|
||||
max_residual=float(max(finite, default=0.0)),
|
||||
wrong=counts["wrong"],
|
||||
)
|
||||
|
||||
|
||||
# --- PASS path ----------------------------------------------------------------
|
||||
|
||||
|
||||
def test_live_harness_pass_drives_integration():
|
||||
"""A real ADR-0240 harness PASS report drives a live integrate_biography call."""
|
||||
report = run_analogical_transfer([make_fixture_pair()])
|
||||
assert report.wrong == 0 and report.all_correct_or_refused
|
||||
|
||||
traj = _trajectory()
|
||||
blade, record = integrate_validated_biography(report, traj)
|
||||
|
||||
# I-01 at the wiring seam (same asserts as test_third_door_cohesion I-01)
|
||||
assert blade.closure < _CLOSURE
|
||||
assert versor_condition(blade.blade) < _CLOSURE
|
||||
|
||||
assert record.record_id.startswith("bioprov-")
|
||||
assert record.schema_version == "biography_provenance_v1"
|
||||
assert record.wrong == 0
|
||||
assert record.n_cases == 1
|
||||
assert record.counts["correct"] == 1
|
||||
assert record.case_outcomes == (
|
||||
("fixture-nullcloud-similarity-transfer-v2", "transfer_ok"),
|
||||
)
|
||||
# Record binds the report to the exact trajectory that was integrated
|
||||
assert record.trajectory_hash == integrate_biography(traj).trajectory_hash
|
||||
assert record.n_steps == blade.n_steps
|
||||
assert record.adr_refs == ("ADR-0240", "ADR-0243")
|
||||
assert record.closure_proof["blade_closure"] == blade.closure
|
||||
|
||||
|
||||
def test_provenance_record_deterministic():
|
||||
report = run_analogical_transfer([make_fixture_pair()])
|
||||
traj = _trajectory()
|
||||
_, rec1 = integrate_validated_biography(report, traj)
|
||||
_, rec2 = integrate_validated_biography(report, traj)
|
||||
assert rec1.record_id == rec2.record_id
|
||||
assert rec1.as_dict() == rec2.as_dict()
|
||||
assert json.dumps(rec1.as_dict(), sort_keys=True) # JSONL-serializable
|
||||
|
||||
|
||||
# --- must-reject paths --------------------------------------------------------
|
||||
|
||||
|
||||
def test_wrong_report_refuses():
|
||||
report = _report([_result(), _result("c2", correct=False, reason="residual_above_threshold", residual=9.0)])
|
||||
assert report.wrong == 1
|
||||
with pytest.raises(BiographyIntegrationError) as exc_info:
|
||||
integrate_validated_biography(report, _trajectory())
|
||||
assert exc_info.value.reason == "report_not_pass"
|
||||
|
||||
|
||||
def test_live_harness_wrong_refuses():
|
||||
"""A real harness run that produces a wrong must not integrate."""
|
||||
case = make_fixture_pair()
|
||||
bad = dataclasses.replace(
|
||||
case, expected_novel=make_rotor_from_angle(2.0, bivector_idx=8)
|
||||
)
|
||||
report = run_analogical_transfer([bad])
|
||||
assert report.wrong >= 1
|
||||
with pytest.raises(BiographyIntegrationError) as exc_info:
|
||||
integrate_validated_biography(report, _trajectory())
|
||||
assert exc_info.value.reason == "report_not_pass"
|
||||
|
||||
|
||||
def test_all_refused_validates_nothing():
|
||||
"""wrong == 0 with zero correct transfers validated nothing — refuse."""
|
||||
report = _report(
|
||||
[
|
||||
_result("c1", correct=False, refused=True, reason="refused:x", residual=float("inf")),
|
||||
_result("c2", correct=False, refused=True, reason="closure_failed", residual=0.5),
|
||||
]
|
||||
)
|
||||
assert report.wrong == 0 and report.all_correct_or_refused
|
||||
with pytest.raises(BiographyIntegrationError) as exc_info:
|
||||
integrate_validated_biography(report, _trajectory())
|
||||
assert exc_info.value.reason == "no_validated_transfers"
|
||||
|
||||
|
||||
def test_empty_report_refused():
|
||||
with pytest.raises(BiographyIntegrationError) as exc_info:
|
||||
integrate_validated_biography(_report([]), _trajectory())
|
||||
assert exc_info.value.reason == "empty_report"
|
||||
|
||||
|
||||
def test_bad_trajectory_rejected():
|
||||
report = _report([_result()])
|
||||
with pytest.raises(BiographyIntegrationError) as exc_info:
|
||||
integrate_validated_biography(report, [np.zeros(32, dtype=np.float64)])
|
||||
assert exc_info.value.reason == "trajectory_rejected"
|
||||
|
||||
|
||||
def test_i01_violation_fails_closed_at_call_site(monkeypatch):
|
||||
"""The wiring's own I-01 gate must trip even if the callee returns a bad blade."""
|
||||
open_blade = BiographyHolonomyBlade(
|
||||
blade=make_rotor_from_angle(0.3),
|
||||
n_steps=1,
|
||||
trajectory_hash="deadbeef",
|
||||
closure=1.0,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
"core.physics.biography_wiring.integrate_biography",
|
||||
lambda trajectory, *, alpha: open_blade,
|
||||
)
|
||||
with pytest.raises(BiographyIntegrationError) as exc_info:
|
||||
integrate_validated_biography(_report([_result()]), _trajectory())
|
||||
assert exc_info.value.reason == "i01_closure_violation"
|
||||
|
||||
|
||||
# --- structural pin of the direct-integration ruling --------------------------
|
||||
|
||||
|
||||
def test_wiring_imports_no_vault_store_and_no_evals():
|
||||
"""Ruling pin: direct integration is legitimate only while the wiring makes
|
||||
no durable write and stays layered below evals. If this test breaks, the
|
||||
mutation-vs-proposal question reopens — do not weaken it."""
|
||||
probe = (
|
||||
"import importlib, sys, json;"
|
||||
"importlib.import_module('core.physics.biography_wiring');"
|
||||
"banned=['core.physics.holographic_vault','evals'];"
|
||||
"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 = json.loads(result.stdout.strip().splitlines()[-1])
|
||||
assert leaked == [], f"biography_wiring loaded banned modules: {leaked}"
|
||||
|
|
@ -29,6 +29,7 @@ _BANNED = (
|
|||
"core.physics.multi_scale_energy",
|
||||
"core.physics.sensorium_wave_feed",
|
||||
"core.physics.cognitive_lifecycle", # ADR-0243 lifecycle — never serve
|
||||
"core.physics.biography_wiring", # ADR-0243 §2.5 PASS→biography wiring — never serve
|
||||
# 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".
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ def test_phase0_a04_serve_path_quarantines_wave_and_fibonacci():
|
|||
"multi_scale_energy", # ADR-0242 V2 research multi-band E_n(t), never serve
|
||||
"sensorium_wave_feed", # D7 I-04 sensorium→ψ feed, never serve
|
||||
"cognitive_lifecycle", # ADR-0243 ingress→relaxation→egress, never serve
|
||||
"biography_wiring", # ADR-0243 §2.5 PASS→biography wiring, never serve
|
||||
}
|
||||
banned_substrings = (
|
||||
"holographic_vault",
|
||||
|
|
@ -82,6 +83,7 @@ def test_phase0_a04_serve_path_quarantines_wave_and_fibonacci():
|
|||
"multi_scale_energy",
|
||||
"sensorium_wave_feed",
|
||||
"cognitive_lifecycle",
|
||||
"biography_wiring",
|
||||
)
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.Import):
|
||||
|
|
|
|||
Loading…
Reference in a new issue