feat(A.3 #24): LocalAgreement-n commit policy

New streaming::commit_policy module implementing ufal's
LocalAgreement-n pattern: tokens emitted by the streaming ASR
pipeline stay tentative until N consecutive passes produce the same
prefix, at which point the agreed prefix commits.

Types:
- Token: text + absolute start/end seconds. PartialEq is text-only so
  identical words from overlapping Whisper windows compare equal even
  when their timestamps drift.
- CommitDecision { newly_committed, tentative }: the partition fed
  back to the live-session worker after each pass.
- CommitPolicy enum with LocalAgreement { n }. Default is n=2 (ufal).
- LocalAgreement: stateful committer with push/flush/reset and a
  last_committed_end_secs accessor. Brief item #25 uses the latter
  to compute the sample-index drain target for aggressive buffer trim.

Invariants exercised by tests:
- first pass is all tentative (need 2 passes to commit under n=2)
- two matching passes commit their common prefix
- divergent second pass commits nothing
- extending agreement commits only the newly-agreed tokens
- tentative tail tracks latest pass only (no stale guesses)
- committed prefix never shrinks, even if later passes contradict
- flush emits any tentative-but-not-committed tail at session end
- flush on empty history is a no-op
- reset clears all commit state
- n=3 requires three matching passes before anything commits
- CommitPolicy::default() is LocalAgreement { n: 2 }

Integration into src-tauri/src/commands/live.rs deferred — the
tentative/committed split needs the B-side 'tentative: bool' field on
LiveResultMessage.segments (workstream-B #24 UI contract) and
validation against real streaming captures before going live.
This commit is contained in:
2026-04-22 07:50:18 +01:00
parent 05eea41649
commit da2340325f
3 changed files with 366 additions and 1 deletions

View File

@@ -11,6 +11,8 @@ pub use local_engine::{load_parakeet, LocalEngine, SpeechModelAdapter, TimedTran
#[cfg(feature = "whisper")]
pub use local_engine::load_whisper;
pub use model_manager::{download, is_downloaded, list_downloaded, model_dir, models_dir};
pub use streaming::{RmsVadChunker, VadChunk, VadChunker};
pub use streaming::{
CommitDecision, CommitPolicy, LocalAgreement, RmsVadChunker, Token, VadChunk, VadChunker,
};
pub use transcriber::{Transcriber, TranscriberCapabilities};
pub use transcribe_rs::SpeechModel;