"""Label-free lesion subspace interface (IMPLEMENTATION_SPEC ยง4). A LesionSubspace is fit ONLY on a label-free CT token bank. It exposes: - fit(token_bank): build L(x) without any labels/masks, - project(Z): P_L Z, - membership_score(Z): per-token lesion-membership score (for Gate 1). Every concrete fit() runs inside subspace_construction_guard() so any accidental label/mask read raises LabelLeakError (tests/test_label_leak.py enforces this). """ from __future__ import annotations from typing import Protocol, runtime_checkable import torch @runtime_checkable class LesionSubspace(Protocol): def fit(self, token_bank: torch.Tensor) -> "LesionSubspace": ... # label-free ONLY def project(self, Z: torch.Tensor) -> torch.Tensor: ... # P_L Z def membership_score(self, Z: torch.Tensor) -> torch.Tensor: ... # per-token, Gate 1