from __future__ import annotations from dataclasses import dataclass from .config import Settings @dataclass(frozen=True, slots=True) class AuthorizationDecision: level: str read_only: bool requires_confirmation: bool reason: str def classify_voice_authorization( speaker_id: str | None, confidence: float, settings: Settings | None = None, ) -> AuthorizationDecision: """Map speaker identity confidence to a safety tier. Voice identity is advisory. Dangerous changes still require explicit approval elsewhere in the protocol. """ settings = settings or Settings() if not speaker_id: return AuthorizationDecision( level="unknown", read_only=True, requires_confirmation=True, reason="No enrolled speaker matched this utterance.", ) if confidence >= settings.speaker_confirmed_threshold: return AuthorizationDecision( level="confirmed", read_only=False, requires_confirmation=False, reason=f"Speaker {speaker_id} matched above confirmed threshold.", ) if confidence >= settings.speaker_probable_threshold: return AuthorizationDecision( level="probable", read_only=False, requires_confirmation=True, reason=f"Speaker {speaker_id} matched above probable threshold only.", ) return AuthorizationDecision( level="unknown", read_only=True, requires_confirmation=True, reason=f"Speaker {speaker_id} confidence below probable threshold.", )