core/tests/test_ring3_integrity_handoff.py
Shay 05ae8cb1b4 feat(ring2-ring3): multi-port residual protocol + integrity-coordinated handoff
Rings 2 and 3 of the ADR-0246 preflight §9, built exactly as the brief bounds
them. ADR-0247 + ADR-0248 both **Proposed** — no self-Accept.

Ring 2 (core/ports/residual_protocol.py — ADR-0247):
  the 7-stage shared control grammar: witness -> typed residual decomposition
  -> permitted operator selection -> bounded operation or abstention ->
  re-certification -> action decision -> append-only replay record.
  Port-agnostic (no registry, no unified scheduler — §7 non-goal #2 honored);
  v1 operators are ZERO-BOUND only (nonzero fails closed — no-silent-correction
  doctrine); unaccounted residual fails closed; re-certification RAISES on
  witness drift during a zero-bound pass; replay chain is append-only,
  full-SHA-256 content-addressed, tamper-evident (verify_replay_chain).
  NOTE: named core/ports/ because core/protocol/ is the existing CTP v0 wire
  format (collision checked before naming).

Ring 2 adapters (core/ports/adapters.py): IdentityPort (ADR-0246 grade-1
  geometry; typed channels travel IN the witness so decompose is a pure
  re-shaping, no hidden state; admit = evaluate_admission, single source of
  truth) + PrecisionPort (ADR-0244 §2.5 cast transport; ServingState subjects)
  — two genuinely non-identical native geometries + a synthetic third port
  proving grammar agnosticism.

Ring 3 (core/ports/integrity_handoff.py — ADR-0248):
  the coordination seam ('Integrity coordinates handoffs; it does not replace
  content-bearing cognition'): fuses Ring-2 port decisions + existing
  EpistemicState/NormativeClearance into content-free proceed/hedge/abstain
  (conjunctive, strongest-restriction-wins; fail-closed on missing/invalid
  evidence; binds replay-chain tip digest; handoff itself content-addressed).
  Weak epistemic standing hedges (mirrors hedge doctrine) — only integrity
  violations silence a turn. OBSERVE-ONLY: no serve consumer yet; that is a
  future flag-gated unit. Remaining Ring-3 programme honestly listed open
  (world-model, governed-learning consumption, discourse widening).

Both pure/deterministic/off-serving (A-04 pinned); brief §0a/§9 updated.

[Verification]: uv run core test --suite smoke -q => 176 passed; Ring 2/3 +
ADR-0246 suites + D4 gate surfaces => 125 passed (28 new Ring-2/3 pins);
run log docs/audit/artifacts/ring2-ring3-runlog.txt
2026-07-17 23:56:01 -07:00

170 lines
5.9 KiB
Python

"""Ring 3 — integrity-coordinated handoff pins.
The preflight (ADR-0246 brief §9) fixes Ring 3's coordination role: "Integrity
coordinates handoffs; it does not replace content-bearing cognition." These pin
the pure coordinator that fuses the Ring-2 per-port action decisions with the
EXISTING content-organ types (EpistemicState, NormativeClearance) into a single
typed handoff for discourse/composition consumers:
* any port abstain → ABSTAIN (integrity floor is conjunctive);
* normative VIOLATED/SUPPRESSED → ABSTAIN; UNASSESSABLE → at most HEDGE;
* weak epistemic standing (undetermined/speculative-class) → at most HEDGE;
* strong standing + all ports proceed + cleared → PROCEED;
* the handoff binds the replay chain (content-addressed) so the decision is
auditable back to every port's evidence;
* the coordinator NEVER fabricates content — it returns a routing decision
only (pinned by its output type having no surface/content fields).
"""
from __future__ import annotations
import pytest
from core.epistemic_state import EpistemicState, NormativeClearance
from core.ports.integrity_handoff import (
HANDOFF_ABSTAIN,
HANDOFF_HEDGE,
HANDOFF_PROCEED,
IntegrityHandoff,
coordinate_handoff,
)
from core.ports.residual_protocol import PortWitness, ResidualDecomposition, run_residual_protocol
class _Port:
schema_version = "toy_v1"
def __init__(self, port_id, value):
self.port_id = port_id
self._value = value
def witness(self, subject):
return PortWitness(
port_id=self.port_id, schema_version=self.schema_version,
measurements=(("residual", self._value),),
)
def decompose(self, witness):
return ResidualDecomposition(
port_id=self.port_id,
channels=(("scalar", dict(witness.measurements)["residual"]),),
unaccounted=0.0, unaccounted_tol=1e-9,
)
def admit(self, subject, decomposition):
value = dict(decomposition.channels)["scalar"]
return (True, ()) if value <= 0.5 else (False, (f"{self.port_id}:refused",))
def _chain(*port_values):
chain = ()
for port_id, value in port_values:
chain, _ = run_residual_protocol(_Port(port_id, value), None, chain)
return chain
def test_all_proceed_cleared_verified_gives_proceed():
chain = _chain(("identity", 0.1), ("precision", 0.2))
handoff = coordinate_handoff(
chain,
epistemic_state=EpistemicState.VERIFIED,
normative_clearance=NormativeClearance.CLEARED,
)
assert handoff.handoff == HANDOFF_PROCEED
assert handoff.port_actions == (("identity", "proceed"), ("precision", "proceed"))
def test_any_port_abstain_forces_abstain():
chain = _chain(("identity", 0.1), ("precision", 0.9))
handoff = coordinate_handoff(
chain,
epistemic_state=EpistemicState.VERIFIED,
normative_clearance=NormativeClearance.CLEARED,
)
assert handoff.handoff == HANDOFF_ABSTAIN
assert any("precision" in r for r in handoff.reasons)
@pytest.mark.parametrize("clearance", [NormativeClearance.VIOLATED, NormativeClearance.SUPPRESSED])
def test_normative_violation_forces_abstain(clearance):
chain = _chain(("identity", 0.1))
handoff = coordinate_handoff(
chain, epistemic_state=EpistemicState.VERIFIED, normative_clearance=clearance,
)
assert handoff.handoff == HANDOFF_ABSTAIN
def test_unassessable_clearance_caps_at_hedge():
chain = _chain(("identity", 0.1))
handoff = coordinate_handoff(
chain,
epistemic_state=EpistemicState.VERIFIED,
normative_clearance=NormativeClearance.UNASSESSABLE,
)
assert handoff.handoff == HANDOFF_HEDGE
@pytest.mark.parametrize(
"state",
[
EpistemicState.UNDETERMINED,
EpistemicState.UNVERIFIED_POSSIBLE,
EpistemicState.UNVERIFIED_NOVEL,
EpistemicState.AMBIGUOUS,
EpistemicState.CONTRADICTED,
],
)
def test_weak_epistemic_standing_caps_at_hedge(state):
chain = _chain(("identity", 0.1))
handoff = coordinate_handoff(
chain, epistemic_state=state, normative_clearance=NormativeClearance.CLEARED,
)
assert handoff.handoff in (HANDOFF_HEDGE, HANDOFF_ABSTAIN)
assert handoff.handoff == HANDOFF_HEDGE # hedge, not abstain: content may still surface qualified
def test_handoff_binds_replay_chain_digest():
chain = _chain(("identity", 0.1))
handoff = coordinate_handoff(
chain,
epistemic_state=EpistemicState.VERIFIED,
normative_clearance=NormativeClearance.CLEARED,
)
assert handoff.chain_tip_digest == chain[-1].record_digest()
assert len(handoff.handoff_digest()) == 64
int(handoff.handoff_digest(), 16)
# deterministic
again = coordinate_handoff(
chain,
epistemic_state=EpistemicState.VERIFIED,
normative_clearance=NormativeClearance.CLEARED,
)
assert again.handoff_digest() == handoff.handoff_digest()
def test_empty_chain_fails_closed():
handoff = coordinate_handoff(
(),
epistemic_state=EpistemicState.VERIFIED,
normative_clearance=NormativeClearance.CLEARED,
)
assert handoff.handoff == HANDOFF_ABSTAIN
assert any("no_port_evidence" in r for r in handoff.reasons)
def test_coordinator_never_carries_content():
# Ring 3 contract: integrity coordinates handoffs, it does NOT replace
# content-bearing cognition. The handoff type must carry no content/surface
# fields — only routing, attribution, and digests.
fields = set(IntegrityHandoff.__dataclass_fields__)
assert "surface" not in fields and "content" not in fields and "text" not in fields
assert {"handoff", "reasons", "port_actions", "chain_tip_digest"} <= fields
def test_module_is_pure_offserving():
import core.ports.integrity_handoff as mod
assert mod.__file__ is not None
with open(mod.__file__, encoding="utf-8") as fh:
src = fh.read()
assert "import chat" not in src and "from chat" not in src