Source code for nlp_shap.masking.builder
"""View-based masked snapshots with structural sharing."""
from __future__ import annotations
from dataclasses import dataclass
from ..domain.coalition import CoalitionMask
from ..domain.conversation import ConversationSnapshot
from ..domain.players import PlayerSet
from ..protocols.masking import AbsencePolicy
from .codec import MaskCodec
[docs]
@dataclass(frozen=True, slots=True)
class MaskedSnapshot:
"""Shared view over a conversation snapshot and coalition mask."""
base: ConversationSnapshot
"""Underlying snapshot shared across coalition evaluations."""
players: PlayerSet
"""Ordered players aligned with the coalition mask."""
mask: CoalitionMask
"""Presence mask selecting which players remain in the coalition."""
policy_name: str
"""Registered absence-policy identifier used to render the view."""
def __post_init__(self) -> None:
self.mask.validate_against(self.players)
@property
def base_snapshot_id(self) -> str:
"""Return the shared base snapshot identifier."""
return self.base.snapshot_id
@property
def mask_hash(self) -> int:
"""Return a stable hash for the coalition mask."""
return MaskCodec.hash_mask(self.mask.present)
[docs]
class MaskBuilder:
"""Build masked snapshot views without copying the base conversation."""
def __init__(self, policy: AbsencePolicy) -> None:
self._policy = policy
@property
def policy_name(self) -> str:
"""Return the configured absence-policy identifier."""
return self._policy.name
[docs]
def view(
self,
snapshot: ConversationSnapshot,
players: PlayerSet,
mask: CoalitionMask,
) -> MaskedSnapshot:
"""Create a masked view that shares ``snapshot`` across coalitions."""
mask.validate_against(players)
return MaskedSnapshot(
base=snapshot,
players=players,
mask=mask,
policy_name=self._policy.name,
)
[docs]
def render(self, masked: MaskedSnapshot) -> ConversationSnapshot:
"""Materialize a coalition-specific conversation snapshot."""
if masked.policy_name != self._policy.name:
msg = (
f"masked view policy {masked.policy_name!r} does not match "
f"builder policy {self._policy.name!r}"
)
raise ValueError(msg)
return self._policy.apply(masked.base, masked.players, masked.mask)