# kcode-speaker-model 0.1.0
Deterministic, cohort-scoped fitting and identification over validated `kcode-speaker-types` values.
## API
```rust
pub const GEMINI_11: FeatureMask;
pub const GEMINI_20: FeatureMask;
pub const ALL_35: FeatureMask;
pub struct ModelConfig {
pub mask: FeatureMask,
pub components: u8,
pub relevance: f64,
pub variance_floor: f64,
pub absolute_threshold: f64,
pub margin_threshold: f64,
}
pub struct FitInput<'a> {
pub cohort_id: &'a Key,
pub samples: &'a [LabeledSample],
pub config: ModelConfig,
}
pub struct ModelSnapshot { /* private immutable state */ }
pub struct CandidateScore {
pub speaker_id: Key,
pub llr: f64,
}
pub enum Decision {
Known { speaker_id: Key },
Unknown,
}
pub struct Identification {
pub decision: Decision,
pub best: CandidateScore,
pub runner_up: Option<CandidateScore>,
pub absolute_pass: bool,
pub margin_pass: bool,
}
pub fn fit(input: FitInput<'_>) -> Result<ModelSnapshot, ModelError>;
pub fn identify(
model: &ModelSnapshot,
cohort_id: &Key,
features: &FeatureVector,
) -> Result<Identification, ModelError>;
pub fn encode(model: &ModelSnapshot) -> Result<Vec<u8>, ModelError>;
pub fn decode(bytes: &[u8]) -> Result<ModelSnapshot, ModelError>;
```
## Contract
`fit` requires nonempty, uniquely identified samples belonging to the requested cohort, at least one represented speaker, `1..=samples.len()` components, positive finite relevance and variance floor, finite thresholds, and nonzero finite population standard deviation for every selected feature. Samples have equal weight. Selected features follow ascending frozen mask index. Normalization is learned only from the supplied training rows.
Fitting uses a deterministic diagonal GMM with 200 maximum EM updates and `1e-8` relative tolerance; a nonconverged result is rejected. Speaker models use mean-only MAP adaptation. No configuration defaults or empirical suitability are implied.
`identify` requires the snapshot cohort. It returns descending LLR scores with speaker-key tie order. `Known` requires `best.llr >= absolute_threshold` and `best.llr - runner_up.llr >= margin_threshold`; equality passes. With one enrolled speaker, `runner_up` is `None`, `margin_pass` is true, and only the absolute gate controls. Identification does not mutate or train the snapshot.
Snapshots are opaque, immutable, cohort-bound, and versioned. Any training-data change requires a fresh `fit`. `encode` emits deterministic versioned JSON for system artifact storage. `decode` accepts only a fully valid supported snapshot and rejects malformed, incompatible, nonfinite, dimensionally inconsistent, or noncanonical artifacts with `ModelError`. Concurrent reads are independent; this library performs no persistence.