Speaker voice match — reference-environment index gate (Stage 9)

Voice matching prefers a rebuildable file matrix under speaker_profiles/.cache/voice/indexes/ when present and digest-fresh. Tree scan remains the degrade path on miss or rebuild failure. No SQLite / vector-DB dependency.

Reference dataset

  • 500 active profiles

  • Several thousand trusted voice samples (1–20 per profile)

  • 1–5 query excerpts per unidentified occurrence

Advisory targets (not CI ms gates)

Hot path

Advisory p95

Analyse one speaker (cached model)

2 s

Full compatible-ref scan

500 ms

Peak RSS over baseline

+512 MB

Measurement (2026-07-23)

Synthetic in-process benchmark via scripts/measure_speaker_voice_match_index.py (500 profiles × 5 refs = 2500 × 192 float32; 3 queries):

Metric

Result

Full-scan matmul

~0.4 ms (well under 500 ms advisory)

Index-resident matmul

~0.3 ms

Estimated matrix RSS

~1.8 MB (well under +512 MB advisory)

Decision: Ship the digest-keyed file matrix anyway to avoid repeated .npy tree opens on the hot path. Matmul alone does not breach advisories; I/O amplification on scan does. Prefer file matrix over ANN; SQLite / vector DB only if the file index still fails a future measured env.

Related: speaker_profiles_reference_env_index_gate.md.

Index layout

.cache/voice/indexes/{model_generation_id}/{corpus_digest_dir}/
  meta.json    # voice_ref_index.v1 + embedding_ids / profile_ids
  matrix.npy   # float32 (N, dim)

Keyed by model_generation_id + reference_corpus_digest. Rebuild on miss; never block analyse on rebuild failure.