Wire the ADR-0242 §5 pinned primitives into the contemplation runner (ADR-0243 §2.4): contemplate_surprise_history() gates the newest caller-timed ADR-0239 dual-operator observation through is_discovery_eligible, the measured history through cross_band_discovery_gate (F5/F6/F7 persistence), and only then emits a DiscoveryCandidate via the existing emit_surprise_discovery -> DiscoveryCandidateSink. Proposal-plumbing only: the sole side effect is sink.emit(). Surprise-signal sourcing (the Lane A open question): ContemplationFinding carries no surprise measurement and the report-mining paths have no geometry, so nothing is fabricated for them — the canonical carrier is the ADR-0239 dual audit dict (SelfAuthorshipMiner / ADR-0240 harness), consumed as explicit SurpriseObservations with caller-supplied logical time (deterministic, no wall clock). Give propose_kappa_line_search its live caller (ADR-0242 §5-P1): evals/analogical_transfer/kappa_calibration.py calibrate_transfer_kappa, confined to the ADR-0240 calibration pipeline per R-04; kappa_search_event fires exactly once when a sink is passed. Proposal-only — no GoldTetherMonitor mutation. A-04 hardening found during review: chat/runtime.py idle_tick lazily imports core.contemplation.runner inside the serve process, and the package __init__ eagerly pulled wave_seam -> holographic_vault (a serve-banned module) — a PRE-EXISTING process-level quarantine breach. Closed by making the wave-seam re-exports lazy (PEP 562) and keeping the multi_scale_energy gate import function-local; pinned by a new dynamic idle-tick-edge test in test_serve_quarantine_transitive.py. Pinned primitives untouched: is_discovery_eligible, cross_band_discovery_gate, candidate_from_surprise_dual signatures unchanged; no changes to cognitive_lifecycle.py or chat/runtime.py.
114 lines
4.4 KiB
Python
114 lines
4.4 KiB
Python
"""ADR-0242 §5-P1 — live κ line-search caller (calibration pipeline only).
|
|
|
|
`core.physics.goldtether.propose_kappa_line_search` and its internal
|
|
`kappa_search_event` telemetry emission were fully implemented and pinned
|
|
(`tests/test_adr_0242_carry_seams.py`) but had zero live call sites. This
|
|
module is the live caller, confined to the ADR-0240 analogical-transfer
|
|
calibration pipeline per the master plan's R-04 mitigation ("trace
|
|
generation ... limited strictly to the calibration and training-loop
|
|
pipelines" — never a hot/serve path; `chat/runtime.py` must never import
|
|
this package).
|
|
|
|
What is calibrated: in `core.physics.surprise.dual_operator` the
|
|
productive-transfer threshold is κ-scaled (``thr = productive_threshold /
|
|
κ``). The objective below proposes the in-bounds κ whose scaled threshold
|
|
sits closest to the worst measured Procrustes residual of the calibration
|
|
corpus — i.e. κ is tuned so the acceptance bar tracks the corpus's actual
|
|
structural-residual scale. The result is PROPOSAL-ONLY: nothing here
|
|
mutates `GoldTetherMonitor` state, COHERENT standing, or serve autonomy;
|
|
failures fall back to baseline κ = 1.0 inside the search itself.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import math
|
|
from typing import Any, Sequence, cast
|
|
|
|
import numpy as np
|
|
|
|
from core.physics.dynamic_manifold import conformal_procrustes
|
|
from core.physics.goldtether import kappa_search_event, propose_kappa_line_search
|
|
from evals.analogical_transfer.harness import TransferCase, make_fixture_pair
|
|
|
|
|
|
def calibrate_transfer_kappa(
|
|
cases: Sequence[TransferCase] | None = None,
|
|
*,
|
|
productive_threshold: float = 0.35,
|
|
lower: float = 0.1,
|
|
upper: float = 2.0,
|
|
evaluation_budget: int = 16,
|
|
sink: Any | None = None,
|
|
) -> dict[str, Any]:
|
|
"""Propose a κ for the transfer corridor via Fibonacci section search.
|
|
|
|
Per-case Procrustes residuals are measured ONCE, outside the search
|
|
loop, so the κ objective is cheap arithmetic (R-04: bounded
|
|
calibration cost). Cases whose residual is not measurable
|
|
(Procrustes refusal or non-finite residual) are excluded and counted;
|
|
if none remain the calibration refuses (typed ``ValueError``) rather
|
|
than proposing κ from nothing.
|
|
|
|
When ``sink`` is provided (any ``emit(line: str)`` object), the
|
|
§5-P1 ``kappa_search_event`` fires exactly once from inside
|
|
:func:`core.physics.goldtether.propose_kappa_line_search`.
|
|
"""
|
|
corpus = tuple(cases) if cases is not None else (make_fixture_pair(),)
|
|
if not corpus:
|
|
raise ValueError("calibrate_transfer_kappa: cases must be non-empty")
|
|
threshold = float(productive_threshold)
|
|
if not math.isfinite(threshold) or threshold <= 0.0:
|
|
raise ValueError("productive_threshold must be finite and > 0")
|
|
|
|
residuals: list[float] = []
|
|
refused = 0
|
|
for case in corpus:
|
|
try:
|
|
# conformal_procrustes accepts sequences of 32-vectors (same call
|
|
# shape as the harness); its annotation is narrower than runtime.
|
|
proc_residual = float(
|
|
conformal_procrustes(
|
|
cast(np.ndarray, case.source),
|
|
cast(np.ndarray, case.target),
|
|
)[1]
|
|
)
|
|
except ValueError:
|
|
refused += 1
|
|
continue
|
|
if not math.isfinite(proc_residual):
|
|
refused += 1
|
|
continue
|
|
residuals.append(proc_residual)
|
|
if not residuals:
|
|
raise ValueError(
|
|
"calibrate_transfer_kappa refused: no admissible cases "
|
|
f"({refused} of {len(corpus)} procrustes-refused or non-finite)"
|
|
)
|
|
|
|
# Worst measured structural residual is the binding acceptance constraint.
|
|
r_star = max(residuals)
|
|
|
|
def residual_fn(kappa: float) -> float:
|
|
return (threshold / float(kappa) - r_star) ** 2
|
|
|
|
proposed_kappa, outcome = propose_kappa_line_search(
|
|
residual_fn,
|
|
lower=float(lower),
|
|
upper=float(upper),
|
|
evaluation_budget=int(evaluation_budget),
|
|
objective_id="analogical_transfer_kappa",
|
|
objective_version="v1",
|
|
sink=sink,
|
|
)
|
|
return {
|
|
"kind": "analogical_transfer_kappa_calibration",
|
|
"proposed_kappa": float(proposed_kappa),
|
|
"productive_threshold": threshold,
|
|
"max_procrustes_residual": r_star,
|
|
"case_count": len(residuals),
|
|
"refused_case_count": refused,
|
|
"event": kappa_search_event(proposed_kappa, outcome),
|
|
}
|
|
|
|
|
|
__all__ = ["calibrate_transfer_kappa"]
|