use super::*;
use kcode_k1_audio_classification_event_format::*;
use kcode_speaker_v3_analysis::*;
const TEXT: &str = "[high] Speaker 1: exact words";
type Current = Option<FragmentProjection>;
type Applied = (ProjectionEffect, bool);
fn id(value: u8) -> TxId {
TxId::from_bytes([value; 12])
}
fn label(value: u32) -> LocalSpeakerLabel {
LocalSpeakerLabel::new(value).unwrap()
}
fn analysis(labels: &[u32]) -> ExecutedAnalysis {
let mut ogg = vec![0; 29];
ogg[..4].copy_from_slice(b"OggS");
ogg[26..28].copy_from_slice(&[1, 1]);
ExecutedAnalysis {
envelope: AnalysisEnvelope {
audio: OggAudioMetadata::from_bytes(&ogg, 1, None).unwrap(),
analysis: StructuredAnalysis {
transcript: TEXT.into(),
speakers: labels
.iter()
.map(|value| StructuredSpeaker {
speaker: label(*value),
language: "English".into(),
features: FeatureVector24::default(),
features_usable_for_training: false,
})
.collect(),
},
gemini: GeminiCohort::new("gemini"),
structurer: StructurerProvenance::new("terra"),
},
label_extractor: StructurerProvenance::new("labels"),
}
}
fn queue() -> V5 {
V5::Queue(QueueV2 {
audio_object_id: id(1),
})
}
fn progress() -> V5 {
V5::Progress(ProgressV1 {
fragment_id: id(1),
update: ProgressUpdateV1::LlmJobStarted {
sequence: 1,
stage: FragmentStageV1::Transcript,
name: "legacy".into(),
},
})
}
fn completion(labels: &[u32]) -> V5 {
V5::TranscriptionComplete(TranscriptionCompleteV1 {
fragment_id: id(1),
analysis: analysis(labels),
})
}
fn start() -> V6 {
V6::AttemptStarted(AttemptStartedV1 { fragment_id: id(1) })
}
fn transcript(attempt: TxId) -> V6 {
V6::GeminiTranscript(GeminiTranscriptV1 {
fragment_id: id(1),
attempt_txid: attempt,
transcript: TEXT.into(),
})
}
fn labels(attempt: TxId, values: &[u32]) -> V6 {
V6::TerraSpeakerLabels(TerraSpeakerLabelsV1 {
fragment_id: id(1),
attempt_txid: attempt,
speakers: values.iter().copied().map(label).collect(),
})
}
fn feature(attempt: TxId, speaker: u32) -> V6 {
V6::GeminiFeatureBundle(GeminiFeatureBundleV1 {
fragment_id: id(1),
attempt_txid: attempt,
speaker: label(speaker),
packets: ["one".into(), "two".into(), "three".into()],
})
}
fn final_payload(fragment: TxId, attempt: TxId, completion_v5: Vec<u8>) -> Vec<u8> {
encode_final_event_v7(&AttemptFinalAnalysisV1 {
fragment_id: fragment,
attempt_txid: attempt,
completion_v5,
})
.unwrap()
}
fn apply(current: &mut Current, callback: TxId, payload: Vec<u8>) -> Applied {
let result = fold(current.as_ref(), callback, &payload).unwrap();
let changed = result.replacement.is_some();
if let Some(next) = result.replacement {
*current = Some(next);
}
(result.effect, changed)
}
fn apply5(current: &mut Current, callback: TxId, event: &V5) -> Applied {
apply(current, callback, encode_event(event).unwrap())
}
fn apply6(current: &mut Current, callback: TxId, event: &V6) -> Applied {
apply(current, callback, encode_event_v6(event).unwrap())
}
fn running() -> Current {
let mut current = None;
apply5(&mut current, id(1), &queue());
apply6(&mut current, id(2), &start());
current
}
fn assert_no_change(current: &mut Current, callback: u8, payload: Vec<u8>) {
assert_eq!(
apply(current, id(callback), payload),
(ProjectionEffect::None, false)
);
}
#[test]
fn format_dispatch_composes_v5_effect_and_v6_replacement() {
let mut current = None;
assert_eq!(
apply5(&mut current, id(1), &queue()),
(ProjectionEffect::Start, true)
);
assert!(current.as_ref().unwrap().needs_work());
assert_eq!(
apply6(&mut current, id(2), &start()),
(ProjectionEffect::None, true)
);
let plan = current.as_ref().unwrap().resume_plan();
assert!(
plan.interrupted
&& plan.active_attempt == Some(id(2))
&& current.as_ref().unwrap().needs_work()
);
}
#[test]
fn v7_completion_overlay_resume_and_late_classification() {
let mut current = running();
assert_no_change(&mut current, 3, final_payload(id(1), id(9), vec![255]));
apply6(&mut current, id(4), &transcript(id(2)));
apply6(&mut current, id(5), &labels(id(2), &[2, 1]));
apply6(&mut current, id(6), &feature(id(2), 1));
apply6(&mut current, id(7), &feature(id(2), 2));
let valid = final_payload(id(1), id(2), encode_event(&completion(&[2, 1])).unwrap());
assert_eq!(
apply(&mut current, id(8), valid.clone()),
(ProjectionEffect::None, true)
);
let projection = current.as_ref().unwrap();
let visible = projection.visible_status();
assert_eq!(
(visible.state, visible.interim_txid),
(OverallState::Completed, Some(id(8)))
);
assert_eq!(visible.transcript.state, StageState::Succeeded);
assert_eq!(visible.speaker_labels.state, StageState::Succeeded);
assert_eq!(visible.speaker_features.state, StageState::Succeeded);
assert_eq!(visible.structuring.state, StageState::Succeeded);
let plan = projection.resume_plan();
assert_eq!(plan.transcript.as_deref(), Some(TEXT));
assert_eq!(plan.speaker_labels, Some(vec![label(2), label(1)]));
assert_eq!(plan.speaker_features[0].speaker(), label(2));
assert_eq!(plan.speaker_features[1].speaker(), label(1));
assert!(plan.final_analysis.is_some());
assert!(!plan.interrupted && plan.active_attempt.is_none() && !projection.needs_work());
assert_no_change(&mut current, 9, valid);
assert_no_change(&mut current, 10, final_payload(id(1), id(2), vec![255]));
assert_eq!(current.unwrap().visible_status().interim_txid, Some(id(8)));
let mut zero = running();
apply6(&mut zero, id(3), &labels(id(2), &[]));
let projection = zero.as_ref().unwrap();
let plan = projection.resume_plan();
assert_eq!(
projection.visible_status().speaker_labels.state,
StageState::Succeeded
);
assert_eq!(plan.speaker_labels, Some(Vec::new()));
assert!(plan.speaker_features.is_empty());
assert!(plan.interrupted && projection.needs_work());
}
#[test]
fn validate_labels_accepts_retained_legacy_completion_during_repair() {
let mut current = None;
apply5(&mut current, id(2), &queue());
apply5(&mut current, id(3), &progress());
apply5(&mut current, id(4), &completion(&[1]));
let confirmed = SpeakerLabelV1 {
speaker: label(1),
person_id: None,
};
assert_eq!(current.unwrap().validate_labels(&[confirmed]), Ok(id(4)));
}
#[cfg(feature = "testkit")]
#[test]
fn testkit_uses_state_owned_bounded_errors() {
let mut current = running();
current
.as_mut()
.unwrap()
.inject_errors((0..=5_000).map(|value| value.to_string()).collect());
let status = current.unwrap().visible_status();
assert!(status.errors_truncated && status.errors.len() == 5_000);
}