core/sensorium/efferent.py
Shay b4fb9df8e7 feat(sensorium): fail-closed efferent gate for actuating decode (ADR-0198 §3)
DefaultEfferentGate is a capability/shape pre-filter only; it does not
lower decoded actions into safety/ethics pack verdicts (ADR-0198 §3 /
§1.2 Gap B). ModalityRegistry.decode/decode_batch now refuse fail-closed
any emission through a gate whose enforces_action_verdicts is False,
unless an explicit allow_unverified_efferent sandbox opt-in is set.

A real motor decoder thus cannot emit through the capability-only gate;
the §3 verdict-lowering gate must be built and installed first. No
production caller of the decode path exists today, so this closes the
latent hazard before a motor decoder makes it load-bearing. Adds two
falsifiable tests (fail-closed refusal; verdict-enforcing gate allowed).
Disjoint from the GSM8K serving path.
2026-06-03 22:03:35 -07:00

113 lines
3.6 KiB
Python

"""Concrete efferent gate policy and trace-safe decision records."""
from __future__ import annotations
from dataclasses import dataclass
import numpy as np
from sensorium.audio.checksum import sha256_json
from sensorium.protocol import CL41_DIM, AuthorityToken, EfferentVerdict
@dataclass(frozen=True, slots=True)
class EfferentEmissionTrace:
"""Trace-safe record of an efferent admission or refusal."""
pack_id: str
admitted: bool
reason: str
authority_sha256: str
policy_sha256: str
capability: str
trace_sha256: str
def as_dict(self) -> dict[str, object]:
return {
"pack_id": self.pack_id,
"admitted": self.admitted,
"reason": self.reason,
"authority_sha256": self.authority_sha256,
"policy_sha256": self.policy_sha256,
"capability": self.capability,
"trace_sha256": self.trace_sha256,
}
@dataclass(frozen=True, slots=True)
class DefaultEfferentGate:
"""Capability-scoped efferent gate.
Admission requires a valid ``(32,)`` vector and one of:
``decode:<pack_id>``, ``decode:*``, or ``*`` in the authority token.
"""
policy_id: str = "default-efferent-v1"
@property
def policy_sha256(self) -> str:
return sha256_json({
"policy_id": self.policy_id,
"required_capability": "decode:<pack_id>",
"wildcards": ["decode:*", "*"],
"shape": [CL41_DIM],
})
@property
def enforces_action_verdicts(self) -> bool:
"""Capability/shape pre-filter only — does NOT lower the decoded action
into the safety/ethics pack verdicts required by ADR-0198 §3. The
registry refuses actuating emission through this gate unless an explicit
sandbox opt-in is set. A future §3 verdict-enforcing gate returns True.
"""
return False
def admit(
self,
pack_id: str,
mv: np.ndarray,
authority: AuthorityToken,
) -> EfferentVerdict:
vec = np.asarray(mv, dtype=np.float32)
if vec.shape != (CL41_DIM,):
return EfferentVerdict(
admitted=False,
reason=f"invalid efferent vector shape: {vec.shape}",
authority_sha256=authority.authority_sha256,
policy_sha256=self.policy_sha256,
)
required = f"decode:{pack_id}"
caps = set(authority.capabilities)
admitted = required in caps or "decode:*" in caps or "*" in caps
return EfferentVerdict(
admitted=admitted,
reason="admitted" if admitted else f"missing capability: {required}",
authority_sha256=authority.authority_sha256,
policy_sha256=self.policy_sha256,
)
def trace(
self,
pack_id: str,
authority: AuthorityToken,
verdict: EfferentVerdict,
) -> EfferentEmissionTrace:
capability = f"decode:{pack_id}"
payload = {
"kind": "EfferentEmissionTrace",
"pack_id": pack_id,
"admitted": verdict.admitted,
"reason": verdict.reason,
"authority_sha256": authority.authority_sha256,
"policy_sha256": verdict.policy_sha256,
"capability": capability,
}
return EfferentEmissionTrace(
pack_id=pack_id,
admitted=verdict.admitted,
reason=verdict.reason,
authority_sha256=authority.authority_sha256,
policy_sha256=verdict.policy_sha256,
capability=capability,
trace_sha256=sha256_json(payload),
)