Merge pull request 'feat(third-door): GoldTether harmonized residual + α=Φ(R) constraint control (ADR-0238 §2.3, #18)' (#24) from feat/goldtether-alpha-control-gold-set into main
Some checks failed
full-pytest / full pytest (-m "not quarantine" -n 2) (push) Failing after 5s
lane-shas / verify pinned lane SHAs (push) Failing after 22s

This commit is contained in:
Joshua Matthew-Catudio Shay 2026-07-12 18:19:25 +00:00
commit 2118726dfe
2 changed files with 272 additions and 0 deletions

View file

@ -27,6 +27,25 @@ _CLOSURE_TOL = 1e-6
_NEAR_ZERO = 1e-12
_PSEUDOSCALAR_IDX = 31
_TELEMETRY_SCHEMA = "goldtether_coherence_v1"
_E4_IDX = 4
_E5_IDX = 5
def _primal_gold_invariants() -> list:
"""R&D-Revised §5 bootstrapping seeds: the identity versor and the two
conformal null directions ``n_o = 0.5(e5-e4)`` and ``n_inf = e4+e5``.
Coordinate-free algebraic anchors so the geometric distance term never
degenerates to drift-only at cold start.
"""
ident = np.zeros(N_COMPONENTS, dtype=np.float64)
ident[0] = 1.0
n_o = np.zeros(N_COMPONENTS, dtype=np.float64)
n_o[_E5_IDX] = 0.5
n_o[_E4_IDX] = -0.5
n_inf = np.zeros(N_COMPONENTS, dtype=np.float64)
n_inf[_E4_IDX] = 1.0
n_inf[_E5_IDX] = 1.0
return [ident, n_o, n_inf]
class OperatingMode(str, Enum):
@ -102,6 +121,11 @@ class GoldTetherMonitor:
autonomy_step: float = 0.01
hitl_floor_threshold: float = 0.7
hitl_autonomy_threshold: float = 0.5
# Harmonized residual + alpha control law (ADR-0238 §2.3 / R&D-Revised §2.3).
w_drift: float = 0.5
r_floor: float = 0.1
r_critical: float = 1.0
gold_invariants: list = field(default_factory=_primal_gold_invariants, compare=False)
@property
def supervised_autonomy_level(self) -> float:
@ -158,6 +182,101 @@ class GoldTetherMonitor:
self.floor = 0.0
self.history.clear()
# --- Harmonized residual + alpha control law (ADR-0238 §2.3) ---------------
def goldtether_residual(self, F: np.ndarray) -> float:
"""Scale-harmonized coherence residual (ADR-0238 §2.3):
R = w·(drift / ε_drift) + (1w)·(min_{I𝓘_gold} FI_F / F_F)
The algebraic drift term (normalized by the numerical floor ε_drift) and
the geometric distance-to-gold term (normalized by F) are each scaled to
``[0, O(1)]`` so neither masks the other the exact defect §2.3 exists to
fix. This is the ALIGNMENT signal that drives the constraint weight α; the
raw :func:`coherence_residual` stays the fail-closed *closure* gate.
"""
F_arr = _as_mv(F)
drift = coherence_residual(F_arr)
drift_term = drift / self.epsilon_drift if self.epsilon_drift > 0.0 else drift
scale = float(np.linalg.norm(F_arr))
if self.gold_invariants and scale > _NEAR_ZERO:
min_dist = min(
float(np.linalg.norm(F_arr - np.asarray(inv, dtype=np.float64)))
for inv in self.gold_invariants
)
geo_term = min_dist / scale
else:
geo_term = 0.0
w = float(self.w_drift)
return float(w * drift_term + (1.0 - w) * geo_term)
def alpha_constraint(
self,
F: np.ndarray,
*,
mode: OperatingMode | str = OperatingMode.PRACTICE,
) -> float:
"""Human-constraint weight ``α ∈ [0,1]`` for the supervised transition
surface (R&D-Revised §2.3): ``α = Φ(R_gt; r_floor, r_critical)`` a smooth
step of the *instantaneous* harmonized residual composed with the
earned-autonomy ceiling and the serve-never-autonomous rule.
``α = 0`` fully autonomous (trust self); ``α = 1`` full human override.
Earned autonomy sets the FLOOR on α: the engine may never act more
autonomously than it has earned over its trajectory, and SERVE is pinned
to full override.
"""
op = OperatingMode(mode)
if op is OperatingMode.SERVE:
return 1.0
r = self.goldtether_residual(F)
lo, hi = float(self.r_floor), float(self.r_critical)
if r <= lo:
phi = 0.0
elif r >= hi or hi <= lo:
phi = 1.0
else:
phi = (r - lo) / (hi - lo)
alpha_floor = 1.0 - float(self.autonomy)
return float(min(1.0, max(phi, alpha_floor)))
def supervised_transition(
self,
v_self: np.ndarray,
v_constraint: np.ndarray,
F: np.ndarray,
*,
mode: OperatingMode | str = OperatingMode.PRACTICE,
) -> np.ndarray:
"""Blend the engine's own transition ``v_self`` toward the human/gold
``v_constraint`` by the residual-driven constraint weight α.
``α=0 v_self`` (autonomous), ``α=1 v_constraint`` (override).
Rides the exact geodesic (`supervised_blend`), so closure is preserved.
"""
alpha = self.alpha_constraint(F, mode=mode)
return self.supervised_blend(v_self, v_constraint, alpha)
def promote_gold_invariant(self, F: np.ndarray, *, authorized: bool = False) -> None:
"""Add a state versor to 𝓘_gold. CALLER-GATED: the ADR-0092 signed /
replay-verified promotion happens in the caller; this refuses to
self-authorize (one-mutation-path discipline). The full replay-verified
promotion pipeline + principal-axis decay are deferred (issue #18 follow-up).
"""
if not authorized:
raise ValueError(
"promote_gold_invariant requires explicit authorization (ADR-0092 gate)"
)
self.gold_invariants.append(_as_mv(F).copy())
def prune_gold_invariants(self, max_size: int = 64) -> None:
"""Bound 𝓘_gold (decay hook), always retaining the three primal seeds.
Full principal-axis pruning (R&D-Revised §5) is deferred."""
max_size = max(3, int(max_size))
if len(self.gold_invariants) > max_size:
primal = self.gold_invariants[:3]
recent = self.gold_invariants[3:][-(max_size - 3):]
self.gold_invariants = primal + recent
def measure(self, F: np.ndarray, reference: Optional[np.ndarray] = None) -> CoherenceResidual:
"""Structured residual (primary + optional geometric distance to reference)."""
F_arr = _as_mv(F)

View file

@ -0,0 +1,153 @@
"""ADR-0238 §2.3 / R&D-Revised §2.3 — harmonized GoldTether residual + α=Φ(R).
The prior GoldTether shipped only the drift term and an "earned-autonomy" ramp
found in neither blueprint. This adds the scale-harmonized residual (drift +
distance-to-gold-set), the gold-invariant set (primal seeds), and the
α=Φ(R_gt) constraint-weight control law composed with the earned-autonomy
ceiling and the serve-never-autonomous rule, so the two mechanisms operate at
their two timescales (lifetime ceiling × per-transition blend) rather than
compete. See `docs/research/third-door-blueprint-fidelity.md` finding #4 (#18).
"""
from __future__ import annotations
import numpy as np
import pytest
from algebra.rotor import make_rotor_from_angle
from algebra.versor import versor_condition
from core.physics.goldtether import GoldTetherMonitor, OperatingMode, coherence_residual
def _id() -> np.ndarray:
v = np.zeros(32, dtype=np.float64)
v[0] = 1.0
return v
# --- gold-invariant set (R&D §5 bootstrapping seeds) -----------------------
def test_primal_gold_seeds():
m = GoldTetherMonitor()
assert len(m.gold_invariants) == 3
ident, n_o, n_inf = m.gold_invariants
assert ident[0] == 1.0
assert n_o[5] == 0.5 and n_o[4] == -0.5 # n_o = 0.5(e5 - e4)
assert n_inf[4] == 1.0 and n_inf[5] == 1.0 # n_inf = e4 + e5
# --- harmonized residual (§2.3) --------------------------------------------
def test_harmonized_residual_zero_on_identity():
# identity is both closed (drift 0) and a seed (distance 0)
assert GoldTetherMonitor().goldtether_residual(_id()) == 0.0
def test_harmonized_residual_nonneg_and_geo_driven_on_closed_versor():
m = GoldTetherMonitor()
F = make_rotor_from_angle(1.0)
r = m.goldtether_residual(F)
assert r >= 0.0
# on a closed distant versor the geo term dominates → strictly above drift-only
assert r > coherence_residual(F)
def test_harmonized_residual_explodes_on_drift_fail_closed():
m = GoldTetherMonitor()
dirty = np.zeros(32, dtype=np.float64)
dirty[0] = 0.5
dirty[1] = 0.5
assert m.goldtether_residual(dirty) > 1.0 # drift/ε makes non-closure loud
m.autonomy = 1.0
assert m.alpha_constraint(dirty) == 1.0 # → full override
# --- α = Φ(R) control law (§2.3) -------------------------------------------
def test_alpha_serve_is_always_full_override():
m = GoldTetherMonitor()
m.autonomy = 1.0
assert m.alpha_constraint(_id(), mode=OperatingMode.SERVE) == 1.0
def test_alpha_earned_autonomy_is_the_floor():
m = GoldTetherMonitor() # fresh: autonomy 0
assert m.alpha_constraint(_id()) == 1.0 # cannot go autonomous yet
m.autonomy = 0.4
for th in (0.0, 0.5, 1.0, 2.0):
a = m.alpha_constraint(make_rotor_from_angle(th))
assert a >= 1.0 - m.autonomy - 1e-12 # α floored by (1 earned)
def test_alpha_autonomous_when_earned_and_coherent():
m = GoldTetherMonitor()
m.autonomy = 1.0
assert m.alpha_constraint(_id()) == 0.0 # earned + on-seed + closed
def test_alpha_smooth_step_thresholds():
m = GoldTetherMonitor()
m.autonomy = 1.0
F = make_rotor_from_angle(1.0)
r = m.goldtether_residual(F)
m.r_floor, m.r_critical = r + 0.1, r + 0.2
assert m.alpha_constraint(F) == 0.0 # below floor → autonomous
m.r_floor, m.r_critical = r - 0.2, r - 0.1
assert m.alpha_constraint(F) == 1.0 # above critical → override
m.r_floor, m.r_critical = r - 0.1, r + 0.1
assert 0.0 < m.alpha_constraint(F) < 1.0 # in the ramp
def test_alpha_monotone_non_decreasing_in_distance():
m = GoldTetherMonitor()
m.autonomy = 1.0
m.r_floor, m.r_critical = 0.0, 1.0
prev = -1.0
for th in np.linspace(0.05, 3.0, 25):
a = m.alpha_constraint(make_rotor_from_angle(float(th)))
assert 0.0 <= a <= 1.0
assert a >= prev - 1e-9
prev = a
def test_alpha_determinism_replay():
F = make_rotor_from_angle(0.7)
m1 = GoldTetherMonitor()
m2 = GoldTetherMonitor()
m1.autonomy = m2.autonomy = 0.5
assert m1.alpha_constraint(F) == m2.alpha_constraint(F)
# --- supervised transition surface -----------------------------------------
def test_supervised_transition_endpoints_and_closure():
m = GoldTetherMonitor()
src, tgt = _id(), make_rotor_from_angle(0.6)
# fresh (autonomy 0) → α = 1 → transition lands on the constraint
out = m.supervised_transition(src, tgt, _id())
assert np.allclose(out, tgt, atol=1e-6)
assert versor_condition(out) < 1e-6
# earned + coherent → α = 0 → transition stays on self
m.autonomy = 1.0
out = m.supervised_transition(src, tgt, _id())
assert np.allclose(out, src)
# --- gold-set mutation discipline ------------------------------------------
def test_promote_requires_explicit_authorization():
m = GoldTetherMonitor()
with pytest.raises(ValueError):
m.promote_gold_invariant(make_rotor_from_angle(0.3))
m.promote_gold_invariant(make_rotor_from_angle(0.3), authorized=True)
assert len(m.gold_invariants) == 4
def test_prune_retains_primal_seeds():
m = GoldTetherMonitor()
for i in range(50):
m.promote_gold_invariant(make_rotor_from_angle(0.01 * i + 0.01), authorized=True)
m.prune_gold_invariants(max_size=10)
assert len(m.gold_invariants) == 10
assert m.gold_invariants[0][0] == 1.0 # identity seed retained
assert m.gold_invariants[1][5] == 0.5 # n_o seed retained