Codex commited on
Commit
b9b02f6
·
1 Parent(s): 8f9062d

Harden endpoint audio delivery

Browse files
README.md CHANGED
@@ -92,6 +92,8 @@ the runtime additionally verifies the exact weight SHA-256 before deserializatio
92
  每第四個 retry 使用 completion-headroom(4.2 CJK / 3.6 ASCII)。Refill 使用
93
  `root seed + global generation offset`,不會重新生成其他已覆蓋 chunks。三種 policy 都只改 native-duration endpoint estimate,
94
  margin 固定 +1 latent step、`min_len` 固定為 2,不會為了播放目標語速硬撐 generation loop。
 
 
95
  選中完整 trajectory 或 coverage-sequence-DP 混合路徑後,log 會記錄每個 chunk 的 candidate、seed、policy、實際 CFG,
96
  並記錄每個已嘗試 row-local ordinal 的 schedule CFG。Ordinal 0 與正偶數使用 primary CFG 3.0,
97
  正奇數使用 alternate CFG 2.0;含 URL/email component 的 chunk 仍有 CFG 3.0 的內容安全下限。
@@ -103,8 +105,9 @@ speech-unit counter;只有 URL/email-conditioned native endpoint estimate 對
103
  採用除以 2 的保守 counter。這個 counter 刻意同時決定 adaptive weak-stop 的
104
  `expected_steps` progress 與 `max_len` hard cap;兩者屬於同一份 native endpoint plan,
105
  但不會進入播放 pace、chunk planning 或 32/800 work accounting,`min_len` 仍固定為 2。
106
- 終端 outcome 另輸出 content-free canonical evidence schema v5,包含 original chunk indices、
107
  row-local ordinal、network provenance、CFG contract、32/800 預算用量與 selected-path 交叉檢查,
 
108
  每個 local row 的 independent-large-v3 attempted/pass/proof-count/result attestation,以及
109
  local、joined、independent-large-v3 與 final gate 的 bounded SQUIM scalar,
110
  不包含 target/transcript/audio/embedding。
@@ -115,8 +118,15 @@ local、joined、independent-large-v3 與 final gate 的 bounded SQUIM scalar,
115
  不會執行 refill 或 DP。若失敗,之後只做單 chunk refill,不再生成第二條完整 trajectory。
116
  Ragged DP 可混合已通過 hard gate 的 chunks,
117
  以及下述唯一 boundary-only、drop 不超過 0.15 的 DP-only chunks。切段保留標點,並依逗號、分號或句末標點
118
- 插入不同長度的停頓。輸出最後會套用保守的 RMS floor peak limit,通過所有 verifier
119
- 後才明確量化為 PCM16;不讓 Gradio float ndarray peak normalization,以免額外放大底噪。
 
 
 
 
 
 
 
120
  完成 RMS matching、edge fade、pause、crossfade 與使用者 speed 後,服務會再對最終整段 waveform
121
  執行 normalized target 的 prefix/whole/suffix/tail、pace 與 speaker anchor/boundary gate,並要求
122
  turbo 與 full large-v3 的語意 hard intersection;這個 post-join gate 失敗時不會回傳先前已通過的
 
92
  每第四個 retry 使用 completion-headroom(4.2 CJK / 3.6 ASCII)。Refill 使用
93
  `root seed + global generation offset`,不會重新生成其他已覆蓋 chunks。三種 policy 都只改 native-duration endpoint estimate,
94
  margin 固定 +1 latent step、`min_len` 固定為 2,不會為了播放目標語速硬撐 generation loop。
95
+ 唯一例外是 completion-headroom 的一至兩單位短句:其 sparse retry 將 hard cap 下限提高到 5 steps,
96
+ 讓第一個 eligible weak-stop 有一次真正的 threshold 判定機會;所有額外內容仍須通過雙 ASR 與 tail=0。
97
  選中完整 trajectory 或 coverage-sequence-DP 混合路徑後,log 會記錄每個 chunk 的 candidate、seed、policy、實際 CFG,
98
  並記錄每個已嘗試 row-local ordinal 的 schedule CFG。Ordinal 0 與正偶數使用 primary CFG 3.0,
99
  正奇數使用 alternate CFG 2.0;含 URL/email component 的 chunk 仍有 CFG 3.0 的內容安全下限。
 
105
  採用除以 2 的保守 counter。這個 counter 刻意同時決定 adaptive weak-stop 的
106
  `expected_steps` progress 與 `max_len` hard cap;兩者屬於同一份 native endpoint plan,
107
  但不會進入播放 pace、chunk planning 或 32/800 work accounting,`min_len` 仍固定為 2。
108
+ 終端 outcome 另輸出 content-free canonical evidence schema v6,包含 original chunk indices、
109
  row-local ordinal、network provenance、CFG contract、32/800 預算用量與 selected-path 交叉檢查,
110
+ 每個 chunk 的 stop reason、pre-fade endpoint energy、generated/hard-stop steps,
111
  每個 local row 的 independent-large-v3 attempted/pass/proof-count/result attestation,以及
112
  local、joined、independent-large-v3 與 final gate 的 bounded SQUIM scalar,
113
  不包含 target/transcript/audio/embedding。
 
118
  不會執行 refill 或 DP。若失敗,之後只做單 chunk refill,不再生成第二條完整 trajectory。
119
  Ragged DP 可混合已通過 hard gate 的 chunks,
120
  以及下述唯一 boundary-only、drop 不超過 0.15 的 DP-only chunks。切段保留標點,並依逗號、分號或句末標點
121
+ 插入不同長度的停頓。已通過 hard gate 的候選再加入 bounded endpoint soft cost:
122
+ 任何到達 hard cap(即使 threshold 恰於同一步 crossing)皆加 0.05,加上 `0.02 ×`
123
+ 最後 5 ms RMS/全波形 peak。只有在目前 preferred 候選到達 hard cap 時,才允許真正於 cap
124
+ 前自然停止的候選使用最多 STOI 0.02/PESQ 0.03 的 preferred-tier slack;speaker 與 boundary
125
+ 在既有長度 gate 適用時仍須完整達到 preferred 門檻,所有 hard gate 亦維持不變。
126
+ 輸出最後會套用保守的 RMS floor 與 peak limit、固定 5 ms cosine-squared 收尾與 180 ms silence,
127
+ 接著先量化到 PCM16 並以 WAV decoder 等價波形執行 joined/final verifier。公開 wrapper 再編碼時
128
+ 逐 sample 冪等,因此驗證的就是使用者收到的 PCM codes;同時不讓 Gradio 對 float ndarray
129
+ 再做 peak normalization,以免額外放大底噪。
130
  完成 RMS matching、edge fade、pause、crossfade 與使用者 speed 後,服務會再對最終整段 waveform
131
  執行 normalized target 的 prefix/whole/suffix/tail、pace 與 speaker anchor/boundary gate,並要求
132
  turbo 與 full large-v3 的語意 hard intersection;這個 post-join gate 失敗時不會回傳先前已通過的
app.py CHANGED
@@ -2,7 +2,7 @@
2
 
3
  from __future__ import annotations
4
 
5
- from dataclasses import replace
6
  from importlib import metadata as importlib_metadata
7
  import inspect
8
  import json
@@ -103,6 +103,7 @@ from production import (
103
  normalize_spoken_forms,
104
  punctuation_pause_seconds,
105
  pcm16_audio_output,
 
106
  plan_generation_chunks,
107
  select_generation_cps,
108
  set_generation_seed,
@@ -133,6 +134,7 @@ from quality_runtime import (
133
  candidate_gate_evidence,
134
  active_audio_rms_db,
135
  active_audio_median_f0_hz,
 
136
  format_cascade_evidence_log,
137
  generation_cfg_for_candidate_offset,
138
  generation_policy_for_candidate_offset,
@@ -191,6 +193,7 @@ QUALITY_MEDIUM_CHUNK_UNITS = 24
191
  CROSSFADE_MS = 80.0
192
  CHUNK_EDGE_FADE_MS = 80.0
193
  CHUNK_RMS_MATCH_DB = 4.0
 
194
  NETWORK_GENERATION_MIN_UNITS = 8
195
  NETWORK_GENERATION_TARGET_UNITS = 32
196
  NETWORK_GENERATION_MAX_UNITS = 36
@@ -375,6 +378,15 @@ def _apply_speed(
375
  )
376
 
377
 
 
 
 
 
 
 
 
 
 
378
  def _generate_chunk(
379
  text: str,
380
  centroid: torch.Tensor,
@@ -384,7 +396,7 @@ def _generate_chunk(
384
  request_seed: int,
385
  policy: GenerationPolicy,
386
  network_conditioned: bool = False,
387
- ) -> np.ndarray:
388
  generation_cps = (
389
  policy.ascii_cps
390
  if network_conditioned
@@ -407,6 +419,19 @@ def _generate_chunk(
407
  add_terminal_punctuation=count_speech_units(text) >= MIN_ENDPOINT_CUE_UNITS,
408
  duration_units=endpoint_duration_units,
409
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
410
  # Do not hold generation open to enforce pace. The model can finish the
411
  # requested text early; extending its latent sequence creates tail speech.
412
  min_len = 2
@@ -445,6 +470,16 @@ def _generate_chunk(
445
  finally:
446
  if _STOP_CONTROLLER is not None:
447
  _STOP_CONTROLLER.end()
 
 
 
 
 
 
 
 
 
 
448
  if _STOP_CONTROLLER is not None:
449
  print(
450
  "[BlueMagpie] endpoint "
@@ -458,9 +493,21 @@ def _generate_chunk(
458
  f"duration_units={endpoint_duration_units} "
459
  f"duration_counter={'network_conservative' if network_conditioned else 'public'} "
460
  f"expected_steps={expected_steps} hard_stop_steps={hard_stop_steps} "
461
- f"min_len={min_len}"
 
462
  )
463
  audio = audio.detach().float().cpu().numpy().reshape(-1)
 
 
 
 
 
 
 
 
 
 
 
464
  pace_speed = target_pace_speed(
465
  audio.size,
466
  SR,
@@ -498,7 +545,7 @@ def _generate_chunk(
498
  try:
499
  corrected_active_duration = active_voiced_duration_seconds(corrected, SR)
500
  except (TypeError, ValueError, RuntimeError, OverflowError):
501
- return corrected
502
  rerender_speed = active_pace_correction_speed(
503
  corrected_active_duration,
504
  text,
@@ -535,7 +582,7 @@ def _generate_chunk(
535
  try:
536
  final_active_duration = active_voiced_duration_seconds(final_audio, SR)
537
  except (TypeError, ValueError, RuntimeError, OverflowError):
538
- return final_audio
539
  observed_cps = count_speech_units(text) / final_active_duration
540
  if observed_cps > QUALITY_MAX_PACE_CPS:
541
  fallback_residual = active_pace_correction_speed(
@@ -555,12 +602,14 @@ def _generate_chunk(
555
  f"residual_rate={fallback_residual:.6f} "
556
  f"total_rate={fallback_speed:.6f}"
557
  )
558
- return _apply_speed(
559
- audio,
560
- fallback_speed,
561
- network_conditioned=False,
 
 
562
  )
563
- return final_audio
564
 
565
 
566
  def _speaker_anchor_array(centroid: torch.Tensor) -> np.ndarray:
@@ -583,9 +632,10 @@ def _generate_trajectory(
583
  policy: GenerationPolicy,
584
  network_cfg_min: float = NETWORK_TEXT_CFG_MIN,
585
  network_conditioned: tuple[bool, ...] | None = None,
586
- ) -> tuple[np.ndarray, ...]:
587
  scheduled_cfg = float(cfg)
588
  trajectory: list[np.ndarray] = []
 
589
  if network_conditioned is not None and len(network_conditioned) != len(chunks):
590
  raise ValueError("network provenance must align with generation chunks")
591
  for local_chunk_index, chunk in enumerate(chunks):
@@ -617,18 +667,18 @@ def _generate_trajectory(
617
  f"network_floor_applied={network_floor_applied} "
618
  f"short_floor_applied={short_floor_applied}"
619
  )
620
- trajectory.append(
621
- _generate_chunk(
622
- chunk,
623
- centroid,
624
- cfg=network_adjusted_cfg,
625
- steps=steps,
626
- request_seed=request_seed,
627
- policy=policy,
628
- network_conditioned=network_chunk,
629
- )
630
  )
631
- return tuple(trajectory)
 
 
632
 
633
 
634
  def _attach_transition_f0(
@@ -1099,8 +1149,14 @@ def _assemble_trajectory_audio(
1099
  max_gain=3.0,
1100
  )
1101
  waveform = _apply_speed(waveform, playback_speed)
1102
- finish_fade_ms = 0.0 if count_speech_units("".join(chunks)) <= 6 else 5.0
1103
- return finish_audio(waveform, SR, fade_ms=finish_fade_ms)
 
 
 
 
 
 
1104
 
1105
 
1106
  def _verification_metric_log_fields(verification) -> str:
@@ -1504,6 +1560,10 @@ def _synthesize(
1504
  anchor = _speaker_anchor_array(centroid)
1505
  independent_cache = WholeWaveformVerificationCache()
1506
  generation_context_by_seed: dict[int, CandidateGenerationContext] = {}
 
 
 
 
1507
 
1508
  def canonical_chunks_for_context(
1509
  generation_context: CandidateGenerationContext,
@@ -1714,7 +1774,7 @@ def _synthesize(
1714
  candidate_chunks,
1715
  generation_context=generation_context,
1716
  )
1717
- return _generate_trajectory(
1718
  candidate_chunks,
1719
  centroid,
1720
  cfg=candidate_cfg(candidate_ordinal),
@@ -1723,6 +1783,10 @@ def _synthesize(
1723
  policy=generation_policy_for_candidate_offset(candidate_ordinal),
1724
  network_conditioned=network_flags,
1725
  )
 
 
 
 
1726
 
1727
  def candidate_generation_evidence(
1728
  candidate_index: int,
@@ -1773,6 +1837,11 @@ def _synthesize(
1773
  strict=True,
1774
  )
1775
  )
 
 
 
 
 
1776
  return CandidateGenerationEvidence(
1777
  chunk_indices=chunk_indices,
1778
  chunk_text_units=tuple(
@@ -1784,6 +1853,18 @@ def _synthesize(
1784
  chunk_candidate_ordinals=candidate_ordinals,
1785
  network_conditioned=network_flags,
1786
  chunk_text_variants=text_variants,
 
 
 
 
 
 
 
 
 
 
 
 
1787
  )
1788
 
1789
  try:
@@ -1855,6 +1936,7 @@ def _synthesize(
1855
  preferred_min_squim_audio_duration_seconds=(
1856
  QUALITY_PREFERRED_SQUIM_MIN_DURATION_SECONDS
1857
  ),
 
1858
  )
1859
  except NoQualifiedCandidateError as error:
1860
  print(
 
2
 
3
  from __future__ import annotations
4
 
5
+ from dataclasses import dataclass, replace
6
  from importlib import metadata as importlib_metadata
7
  import inspect
8
  import json
 
103
  normalize_spoken_forms,
104
  punctuation_pause_seconds,
105
  pcm16_audio_output,
106
+ pcm16_verification_waveform,
107
  plan_generation_chunks,
108
  select_generation_cps,
109
  set_generation_seed,
 
134
  candidate_gate_evidence,
135
  active_audio_rms_db,
136
  active_audio_median_f0_hz,
137
+ endpoint_tail_energy_ratio,
138
  format_cascade_evidence_log,
139
  generation_cfg_for_candidate_offset,
140
  generation_policy_for_candidate_offset,
 
193
  CROSSFADE_MS = 80.0
194
  CHUNK_EDGE_FADE_MS = 80.0
195
  CHUNK_RMS_MATCH_DB = 4.0
196
+ FINAL_ENDPOINT_FADE_MS = 5.0
197
  NETWORK_GENERATION_MIN_UNITS = 8
198
  NETWORK_GENERATION_TARGET_UNITS = 32
199
  NETWORK_GENERATION_MAX_UNITS = 36
 
378
  )
379
 
380
 
381
+ @dataclass(frozen=True)
382
+ class _ChunkGenerationOutcome:
383
+ audio: np.ndarray
384
+ stop_reason: str
385
+ endpoint_energy_ratio: float
386
+ generated_steps: int
387
+ hard_stop_steps: int
388
+
389
+
390
  def _generate_chunk(
391
  text: str,
392
  centroid: torch.Tensor,
 
396
  request_seed: int,
397
  policy: GenerationPolicy,
398
  network_conditioned: bool = False,
399
+ ) -> _ChunkGenerationOutcome:
400
  generation_cps = (
401
  policy.ascii_cps
402
  if network_conditioned
 
419
  add_terminal_punctuation=count_speech_units(text) >= MIN_ENDPOINT_CUE_UNITS,
420
  duration_units=endpoint_duration_units,
421
  )
422
+ public_text_units = count_speech_units(text)
423
+ short_headroom_max_units = int(
424
+ getattr(policy, "short_headroom_max_units", 0)
425
+ )
426
+ short_hard_stop_floor_steps = int(
427
+ getattr(policy, "short_hard_stop_floor_steps", 0)
428
+ )
429
+ short_headroom_floor_applied = bool(
430
+ 0 < public_text_units <= short_headroom_max_units
431
+ and hard_stop_steps < short_hard_stop_floor_steps
432
+ )
433
+ if short_headroom_floor_applied:
434
+ hard_stop_steps = short_hard_stop_floor_steps
435
  # Do not hold generation open to enforce pace. The model can finish the
436
  # requested text early; extending its latent sequence creates tail speech.
437
  min_len = 2
 
470
  finally:
471
  if _STOP_CONTROLLER is not None:
472
  _STOP_CONTROLLER.end()
473
+ stop_reason = (
474
+ _STOP_CONTROLLER.last_stop_reason
475
+ if _STOP_CONTROLLER is not None
476
+ else "native_stop"
477
+ )
478
+ generated_steps = (
479
+ _STOP_CONTROLLER.last_generated_steps
480
+ if _STOP_CONTROLLER is not None
481
+ else hard_stop_steps
482
+ )
483
  if _STOP_CONTROLLER is not None:
484
  print(
485
  "[BlueMagpie] endpoint "
 
493
  f"duration_units={endpoint_duration_units} "
494
  f"duration_counter={'network_conservative' if network_conditioned else 'public'} "
495
  f"expected_steps={expected_steps} hard_stop_steps={hard_stop_steps} "
496
+ f"min_len={min_len} "
497
+ f"short_headroom_floor_applied={short_headroom_floor_applied}"
498
  )
499
  audio = audio.detach().float().cpu().numpy().reshape(-1)
500
+
501
+ def outcome(waveform: np.ndarray) -> _ChunkGenerationOutcome:
502
+ normalized = np.asarray(waveform, dtype=np.float32).reshape(-1)
503
+ return _ChunkGenerationOutcome(
504
+ audio=normalized,
505
+ stop_reason=stop_reason,
506
+ endpoint_energy_ratio=endpoint_tail_energy_ratio(normalized, SR),
507
+ generated_steps=generated_steps,
508
+ hard_stop_steps=hard_stop_steps,
509
+ )
510
+
511
  pace_speed = target_pace_speed(
512
  audio.size,
513
  SR,
 
545
  try:
546
  corrected_active_duration = active_voiced_duration_seconds(corrected, SR)
547
  except (TypeError, ValueError, RuntimeError, OverflowError):
548
+ return outcome(corrected)
549
  rerender_speed = active_pace_correction_speed(
550
  corrected_active_duration,
551
  text,
 
582
  try:
583
  final_active_duration = active_voiced_duration_seconds(final_audio, SR)
584
  except (TypeError, ValueError, RuntimeError, OverflowError):
585
+ return outcome(final_audio)
586
  observed_cps = count_speech_units(text) / final_active_duration
587
  if observed_cps > QUALITY_MAX_PACE_CPS:
588
  fallback_residual = active_pace_correction_speed(
 
602
  f"residual_rate={fallback_residual:.6f} "
603
  f"total_rate={fallback_speed:.6f}"
604
  )
605
+ return outcome(
606
+ _apply_speed(
607
+ audio,
608
+ fallback_speed,
609
+ network_conditioned=False,
610
+ )
611
  )
612
+ return outcome(final_audio)
613
 
614
 
615
  def _speaker_anchor_array(centroid: torch.Tensor) -> np.ndarray:
 
632
  policy: GenerationPolicy,
633
  network_cfg_min: float = NETWORK_TEXT_CFG_MIN,
634
  network_conditioned: tuple[bool, ...] | None = None,
635
+ ) -> tuple[tuple[np.ndarray, ...], tuple[_ChunkGenerationOutcome, ...]]:
636
  scheduled_cfg = float(cfg)
637
  trajectory: list[np.ndarray] = []
638
+ endpoint_outcomes: list[_ChunkGenerationOutcome] = []
639
  if network_conditioned is not None and len(network_conditioned) != len(chunks):
640
  raise ValueError("network provenance must align with generation chunks")
641
  for local_chunk_index, chunk in enumerate(chunks):
 
667
  f"network_floor_applied={network_floor_applied} "
668
  f"short_floor_applied={short_floor_applied}"
669
  )
670
+ outcome = _generate_chunk(
671
+ chunk,
672
+ centroid,
673
+ cfg=network_adjusted_cfg,
674
+ steps=steps,
675
+ request_seed=request_seed,
676
+ policy=policy,
677
+ network_conditioned=network_chunk,
 
 
678
  )
679
+ trajectory.append(outcome.audio)
680
+ endpoint_outcomes.append(outcome)
681
+ return tuple(trajectory), tuple(endpoint_outcomes)
682
 
683
 
684
  def _attach_transition_f0(
 
1149
  max_gain=3.0,
1150
  )
1151
  waveform = _apply_speed(waveform, playback_speed)
1152
+ waveform = finish_audio(
1153
+ waveform,
1154
+ SR,
1155
+ fade_ms=FINAL_ENDPOINT_FADE_MS,
1156
+ )
1157
+ # Joined/final ASR, SQUIM, and speaker gates must inspect the exact
1158
+ # decoder-equivalent waveform represented by the public PCM16 response.
1159
+ return pcm16_verification_waveform(waveform)
1160
 
1161
 
1162
  def _verification_metric_log_fields(verification) -> str:
 
1560
  anchor = _speaker_anchor_array(centroid)
1561
  independent_cache = WholeWaveformVerificationCache()
1562
  generation_context_by_seed: dict[int, CandidateGenerationContext] = {}
1563
+ generation_endpoint_evidence_by_seed: dict[
1564
+ int,
1565
+ tuple[_ChunkGenerationOutcome, ...],
1566
+ ] = {}
1567
 
1568
  def canonical_chunks_for_context(
1569
  generation_context: CandidateGenerationContext,
 
1774
  candidate_chunks,
1775
  generation_context=generation_context,
1776
  )
1777
+ trajectory, endpoint_outcomes = _generate_trajectory(
1778
  candidate_chunks,
1779
  centroid,
1780
  cfg=candidate_cfg(candidate_ordinal),
 
1783
  policy=generation_policy_for_candidate_offset(candidate_ordinal),
1784
  network_conditioned=network_flags,
1785
  )
1786
+ if len(endpoint_outcomes) != len(candidate_chunks):
1787
+ raise ValueError("generation endpoint evidence is incomplete")
1788
+ generation_endpoint_evidence_by_seed[seed] = endpoint_outcomes
1789
+ return trajectory
1790
 
1791
  def candidate_generation_evidence(
1792
  candidate_index: int,
 
1837
  strict=True,
1838
  )
1839
  )
1840
+ endpoint_outcomes = generation_endpoint_evidence_by_seed.get(seed)
1841
+ if endpoint_outcomes is None or len(endpoint_outcomes) != len(
1842
+ candidate_chunks
1843
+ ):
1844
+ raise ValueError("generation endpoint evidence is missing")
1845
  return CandidateGenerationEvidence(
1846
  chunk_indices=chunk_indices,
1847
  chunk_text_units=tuple(
 
1853
  chunk_candidate_ordinals=candidate_ordinals,
1854
  network_conditioned=network_flags,
1855
  chunk_text_variants=text_variants,
1856
+ chunk_stop_reasons=tuple(
1857
+ outcome.stop_reason for outcome in endpoint_outcomes
1858
+ ),
1859
+ chunk_endpoint_energy_ratios=tuple(
1860
+ outcome.endpoint_energy_ratio for outcome in endpoint_outcomes
1861
+ ),
1862
+ chunk_generated_steps=tuple(
1863
+ outcome.generated_steps for outcome in endpoint_outcomes
1864
+ ),
1865
+ chunk_hard_stop_steps=tuple(
1866
+ outcome.hard_stop_steps for outcome in endpoint_outcomes
1867
+ ),
1868
  )
1869
 
1870
  try:
 
1936
  preferred_min_squim_audio_duration_seconds=(
1937
  QUALITY_PREFERRED_SQUIM_MIN_DURATION_SECONDS
1938
  ),
1939
+ require_endpoint_evidence=True,
1940
  )
1941
  except NoQualifiedCandidateError as error:
1942
  print(
production.py CHANGED
@@ -419,8 +419,9 @@ class StopHysteresisController(nn.Module):
419
  should_stop = eligible and self._hits >= self.consecutive
420
  stop_reason = "stop_threshold" if should_stop else "running"
421
  if self._hard_stop_steps > 0 and generated_steps >= self._hard_stop_steps:
422
- should_stop = True
423
- stop_reason = "hard_stop"
 
424
  self._step += 1
425
  self.last_generated_steps = generated_steps
426
  self.last_stop_reason = stop_reason
@@ -3116,7 +3117,15 @@ def finish_audio(
3116
  max(0, int(round(float(fade_ms) * int(sample_rate) / 1000.0))),
3117
  )
3118
  if fade_samples > 0:
3119
- signal[-fade_samples:] *= np.linspace(1.0, 0.0, fade_samples, dtype=np.float32)
 
 
 
 
 
 
 
 
3120
  silence_samples = max(
3121
  0,
3122
  int(round(float(trailing_silence_ms) * int(sample_rate) / 1000.0)),
@@ -4602,17 +4611,51 @@ def _peak_rms(audio: np.ndarray) -> tuple[float, float]:
4602
  return peak, rms
4603
 
4604
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4605
  def pcm16_audio_output(
4606
  sample_rate: int,
4607
  audio: np.ndarray,
4608
  ) -> tuple[int, np.ndarray]:
4609
- """Serialize finite mono float audio as PCM16 without peak normalization.
4610
 
4611
  Gradio peak-normalizes floating-point ndarray outputs before writing them.
4612
  Returning explicit PCM16 preserves the level already selected by the
4613
  production loudness/peak limiter, including its intended noise headroom.
4614
- This helper is deliberately a serialization boundary: quality evaluation
4615
- and speaker verification continue to consume the original float waveform.
4616
  """
4617
 
4618
  if isinstance(sample_rate, (bool, np.bool_)):
@@ -4623,23 +4666,7 @@ def pcm16_audio_output(
4623
  raise ValueError("sample_rate must be a positive integer") from error
4624
  if rate_hz <= 0:
4625
  raise ValueError("sample_rate must be a positive integer")
4626
-
4627
- values = np.asarray(audio)
4628
- if values.ndim != 1 or values.size <= 0 or not np.issubdtype(
4629
- values.dtype,
4630
- np.floating,
4631
- ):
4632
- raise ValueError("audio must be a non-empty mono floating-point array")
4633
- finite = values.astype(np.float64, copy=False)
4634
- if not np.isfinite(finite).all():
4635
- raise ValueError("audio must contain only finite samples")
4636
- if float(np.max(np.abs(finite))) > 1.0:
4637
- raise ValueError("audio samples must be bounded to [-1, 1]")
4638
-
4639
- # 32767 is intentional: it gives a symmetric mapping and, unlike Gradio's
4640
- # float conversion, never divides by the waveform peak.
4641
- pcm = np.rint(finite * 32767.0).astype(np.int16)
4642
- return int(rate_hz), pcm
4643
 
4644
 
4645
  def match_chunk_rms(reference: np.ndarray, chunk: np.ndarray, max_adjust_db: float = 4.0) -> np.ndarray:
 
419
  should_stop = eligible and self._hits >= self.consecutive
420
  stop_reason = "stop_threshold" if should_stop else "running"
421
  if self._hard_stop_steps > 0 and generated_steps >= self._hard_stop_steps:
422
+ if not should_stop:
423
+ should_stop = True
424
+ stop_reason = "hard_stop"
425
  self._step += 1
426
  self.last_generated_steps = generated_steps
427
  self.last_stop_reason = stop_reason
 
3117
  max(0, int(round(float(fade_ms) * int(sample_rate) / 1000.0))),
3118
  )
3119
  if fade_samples > 0:
3120
+ phase = np.linspace(
3121
+ 0.0,
3122
+ np.pi / 2.0,
3123
+ fade_samples,
3124
+ dtype=np.float32,
3125
+ )
3126
+ envelope = np.square(np.cos(phase))
3127
+ envelope[-1] = 0.0
3128
+ signal[-fade_samples:] *= envelope
3129
  silence_samples = max(
3130
  0,
3131
  int(round(float(trailing_silence_ms) * int(sample_rate) / 1000.0)),
 
4611
  return peak, rms
4612
 
4613
 
4614
+ def encode_pcm16(audio: np.ndarray) -> np.ndarray:
4615
+ """Encode finite mono audio with the standard signed PCM16 scale."""
4616
+
4617
+ values = np.asarray(audio)
4618
+ if values.ndim != 1 or values.size <= 0 or not np.issubdtype(
4619
+ values.dtype,
4620
+ np.floating,
4621
+ ):
4622
+ raise ValueError("audio must be a non-empty mono floating-point array")
4623
+ finite = values.astype(np.float64, copy=False)
4624
+ if not np.isfinite(finite).all():
4625
+ raise ValueError("audio must contain only finite samples")
4626
+ if float(np.max(np.abs(finite))) > 1.0:
4627
+ raise ValueError("audio samples must be bounded to [-1, 1]")
4628
+
4629
+ scaled = np.rint(finite * 32768.0)
4630
+ return np.clip(scaled, -32768.0, 32767.0).astype(np.int16)
4631
+
4632
+
4633
+ def decode_pcm16(pcm: np.ndarray) -> np.ndarray:
4634
+ """Decode one mono PCM16 buffer exactly as a WAV reader does."""
4635
+
4636
+ values = np.asarray(pcm)
4637
+ if values.ndim != 1 or values.size <= 0 or values.dtype != np.int16:
4638
+ raise ValueError("pcm must be a non-empty mono int16 array")
4639
+ return values.astype(np.float32) / np.float32(32768.0)
4640
+
4641
+
4642
+ def pcm16_verification_waveform(audio: np.ndarray) -> np.ndarray:
4643
+ """Return the decoder-equivalent waveform for the exact public PCM codes."""
4644
+
4645
+ return decode_pcm16(encode_pcm16(audio))
4646
+
4647
+
4648
  def pcm16_audio_output(
4649
  sample_rate: int,
4650
  audio: np.ndarray,
4651
  ) -> tuple[int, np.ndarray]:
4652
+ """Serialize verified mono float audio as PCM16 without peak normalization.
4653
 
4654
  Gradio peak-normalizes floating-point ndarray outputs before writing them.
4655
  Returning explicit PCM16 preserves the level already selected by the
4656
  production loudness/peak limiter, including its intended noise headroom.
4657
+ Callers should verify ``pcm16_verification_waveform(audio)``; encoding that
4658
+ canonical waveform here is sample-for-sample idempotent.
4659
  """
4660
 
4661
  if isinstance(sample_rate, (bool, np.bool_)):
 
4666
  raise ValueError("sample_rate must be a positive integer") from error
4667
  if rate_hz <= 0:
4668
  raise ValueError("sample_rate must be a positive integer")
4669
+ return int(rate_hz), encode_pcm16(audio)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4670
 
4671
 
4672
  def match_chunk_rms(reference: np.ndarray, chunk: np.ndarray, max_adjust_db: float = 4.0) -> np.ndarray:
quality_runtime.py CHANGED
@@ -61,7 +61,12 @@ RELEASE_SPEAKER_TRIGGER_SECONDS = 1.48
61
  SEQUENCE_FALLBACK_MAX_LOCAL_BOUNDARY_SPEAKER_DROP = 0.15
62
  SEQUENCE_FALLBACK_SPEAKER_WEIGHT = 0.05
63
  SEQUENCE_FALLBACK_BOUNDARY_WEIGHT = 0.10
64
- CASCADE_EVIDENCE_SCHEMA_VERSION = 5
 
 
 
 
 
65
  CASCADE_EVIDENCE_LOG_PREFIX = "[BlueMagpie] cascade evidence "
66
  CASCADE_EVIDENCE_MAX_ATTEMPTS = ADAPTIVE_CASCADE_STAGE_LIMITS[-1]
67
  CASCADE_EVIDENCE_MAX_LOCAL_RESULTS = ADAPTIVE_CASCADE_STAGE_LIMITS[-1]
@@ -76,6 +81,9 @@ _CASCADE_EVIDENCE_SELECTION_MODES = frozenset(
76
  {"whole_trajectory", "sequence_dp", "coverage_sequence_dp"}
77
  )
78
  _CFG_FLOOR_REASONS = frozenset({"network", "short_text"})
 
 
 
79
  _CASCADE_EVIDENCE_REJECTION_CODES = frozenset(
80
  {
81
  "boundary_speaker_drop",
@@ -115,6 +123,8 @@ class GenerationPolicy:
115
  cjk_cps: float
116
  ascii_cps: float
117
  hard_stop_margin_steps: int
 
 
118
 
119
 
120
  @dataclass(frozen=True)
@@ -151,6 +161,8 @@ COMPLETION_HEADROOM_GENERATION_POLICY = GenerationPolicy(
151
  cjk_cps=4.2,
152
  ascii_cps=3.6,
153
  hard_stop_margin_steps=1,
 
 
154
  )
155
  MIXED_CFG_SCHEDULE = "row_ordinal_zero_and_even_primary_odd_alternate"
156
  MIXED_CFG_PRIMARY = 3.0
@@ -1446,6 +1458,40 @@ def active_audio_rms_db(audio: np.ndarray | Sequence[float], *, top_db: float =
1446
  return 20.0 * math.log10(rms)
1447
 
1448
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1449
  def active_audio_median_f0_hz(
1450
  audio: np.ndarray | Sequence[float],
1451
  sample_rate: int,
@@ -1521,6 +1567,10 @@ class ChunkCandidateArtifact:
1521
  speaker_embedding: np.ndarray | None = None
1522
  rms_db: float | None = None
1523
  median_f0_hz: float | None = None
 
 
 
 
1524
 
1525
 
1526
  @dataclass(frozen=True)
@@ -1584,6 +1634,10 @@ class CandidateGenerationEvidence:
1584
  chunk_candidate_ordinals: tuple[int, ...] = ()
1585
  network_conditioned: tuple[bool, ...] = ()
1586
  chunk_text_variants: tuple[str, ...] = ()
 
 
 
 
1587
 
1588
 
1589
  @dataclass(frozen=True)
@@ -1602,6 +1656,10 @@ class CandidateAttemptEvidence:
1602
  chunk_candidate_ordinals: tuple[int, ...]
1603
  network_conditioned: tuple[bool, ...]
1604
  chunk_text_variants: tuple[str, ...]
 
 
 
 
1605
  scheduled_cfg: float | None
1606
  effective_cfgs: tuple[float, ...]
1607
  floor_reasons: tuple[tuple[str, ...], ...]
@@ -2530,6 +2588,12 @@ def _candidate_attempt_evidence_payload(
2530
  "chunk_policies": chunk_policies,
2531
  "chunk_text_variants": list(evidence.chunk_text_variants),
2532
  "network_conditioned": list(evidence.network_conditioned),
 
 
 
 
 
 
2533
  "scheduled_cfg": evidence.scheduled_cfg,
2534
  "effective_cfgs": list(evidence.effective_cfgs),
2535
  "floor_reasons": [list(reasons) for reasons in evidence.floor_reasons],
@@ -2619,7 +2683,12 @@ def _selected_generation_evidence_payload(
2619
  policies: list[str | None] = []
2620
  network_conditioned: list[bool | None] = []
2621
  chunk_text_variants: list[str | None] = []
 
 
 
 
2622
  complete = True
 
2623
  for chunk_index, candidate_index in enumerate(
2624
  selection.chunk_candidate_indices
2625
  ):
@@ -2633,6 +2702,11 @@ def _selected_generation_evidence_payload(
2633
  policies.append(None)
2634
  network_conditioned.append(None)
2635
  chunk_text_variants.append(None)
 
 
 
 
 
2636
  continue
2637
  try:
2638
  local_index = attempt.chunk_indices.index(chunk_index)
@@ -2647,6 +2721,11 @@ def _selected_generation_evidence_payload(
2647
  policies.append(None)
2648
  network_conditioned.append(None)
2649
  chunk_text_variants.append(None)
 
 
 
 
 
2650
  continue
2651
  try:
2652
  ordinal = attempt.chunk_candidate_ordinals[local_index]
@@ -2672,8 +2751,41 @@ def _selected_generation_evidence_payload(
2672
  except IndexError:
2673
  complete = False
2674
  chunk_text_variants.append(None)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2675
  return {
2676
  "complete": complete,
 
2677
  "chunk_scheduled_cfgs": scheduled_cfgs,
2678
  "chunk_effective_cfgs": effective_cfgs,
2679
  "chunk_floor_reasons": floor_reasons,
@@ -2681,9 +2793,47 @@ def _selected_generation_evidence_payload(
2681
  "chunk_policies": policies,
2682
  "network_conditioned": network_conditioned,
2683
  "chunk_text_variants": chunk_text_variants,
 
 
 
 
2684
  }
2685
 
2686
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2687
  def format_cascade_evidence_log(
2688
  diagnostics: CascadeDiagnostics,
2689
  *,
@@ -2723,6 +2873,19 @@ def format_cascade_evidence_log(
2723
  "generated_text_unit_limit must be an integer between 1 and 800"
2724
  )
2725
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2726
  selected: dict[str, Any] | None = None
2727
  if selection is not None:
2728
  if not isinstance(selection, CascadeResult):
@@ -2759,7 +2922,6 @@ def format_cascade_evidence_log(
2759
  ),
2760
  }
2761
 
2762
- attempts = diagnostics.attempts[:CASCADE_EVIDENCE_MAX_ATTEMPTS]
2763
  generation_evidence_complete = bool(attempts) and all(
2764
  attempt.scheduled_cfg is not None
2765
  and len(attempt.chunk_indices) == len(attempt.chunk_text_units)
@@ -2771,6 +2933,10 @@ def format_cascade_evidence_log(
2771
  and bool(attempt.chunk_indices)
2772
  for attempt in attempts
2773
  )
 
 
 
 
2774
  generated_chunk_count = sum(len(attempt.chunk_indices) for attempt in attempts)
2775
  generated_text_units = sum(
2776
  sum(attempt.chunk_text_units) for attempt in attempts
@@ -2804,6 +2970,7 @@ def format_cascade_evidence_log(
2804
  },
2805
  "attempt_count": len(diagnostics.attempts),
2806
  "generation_evidence_complete": generation_evidence_complete,
 
2807
  "generated_chunk_count": generated_chunk_count,
2808
  "generated_text_units": generated_text_units,
2809
  "attempts": [
@@ -3285,6 +3452,7 @@ def _validated_candidate_generation_evidence(
3285
  chunks: tuple[str, ...],
3286
  expected_candidate_ordinals: tuple[int, ...],
3287
  require_explicit_candidate_ordinals: bool,
 
3288
  ) -> CandidateGenerationEvidence:
3289
  """Validate deterministic CFG evidence supplied by the hosted app."""
3290
 
@@ -3326,6 +3494,55 @@ def _validated_candidate_generation_evidence(
3326
  chunk_text_variants = value.chunk_text_variants
3327
  else:
3328
  chunk_text_variants = ("base",) * len(chunks)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3329
  raw_ordinals = value.chunk_candidate_ordinals
3330
  if not raw_ordinals:
3331
  if require_explicit_candidate_ordinals:
@@ -3406,6 +3623,10 @@ def _validated_candidate_generation_evidence(
3406
  chunk_candidate_ordinals=candidate_ordinals,
3407
  network_conditioned=network_conditioned,
3408
  chunk_text_variants=chunk_text_variants,
 
 
 
 
3409
  )
3410
 
3411
 
@@ -3447,6 +3668,20 @@ def _candidate_attempt_evidence(
3447
  chunk_text_variants=(
3448
  generation.chunk_text_variants if generation is not None else ()
3449
  ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3450
  scheduled_cfg=(generation.scheduled_cfg if generation is not None else None),
3451
  effective_cfgs=(generation.effective_cfgs if generation is not None else ()),
3452
  floor_reasons=(generation.floor_reasons if generation is not None else ()),
@@ -3598,7 +3833,17 @@ def _sequence_fallback_search(
3598
  except ValueError:
3599
  speaker_artifact_valid = False
3600
  if speaker_artifact_valid:
3601
- score = adjusted_result.score
 
 
 
 
 
 
 
 
 
 
3602
  local_scores[chunk_index].append(score)
3603
  sequence_results.append(tuple(adjusted_results))
3604
 
@@ -3981,6 +4226,50 @@ def _validate_coverage_evidence(
3981
  return verification
3982
 
3983
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3984
  def _coverage_artifact_is_valid(
3985
  result: CandidateGateResult,
3986
  artifact: ChunkCandidateArtifact,
@@ -4006,6 +4295,8 @@ def _coverage_artifact_is_valid(
4006
  minimum=1.0,
4007
  ) is None:
4008
  return False
 
 
4009
  embedding = artifact.speaker_embedding
4010
  if result.speaker_gate_applied is True and embedding is None:
4011
  return False
@@ -4018,6 +4309,127 @@ def _coverage_artifact_is_valid(
4018
  return True
4019
 
4020
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4021
  def _coverage_local_candidate(
4022
  *,
4023
  candidate_index: int,
@@ -4042,6 +4454,11 @@ def _coverage_local_candidate(
4042
  return None
4043
  if not _coverage_artifact_is_valid(adjusted, artifact):
4044
  raise RuntimeError("local verifier passed without valid acoustic evidence")
 
 
 
 
 
4045
  return _RaggedChunkCandidate(
4046
  candidate_index=candidate_index,
4047
  seed=seed,
@@ -4132,6 +4549,7 @@ def run_coverage_adaptive_cascade(
4132
  preferred_min_squim_stoi: float | None = None,
4133
  preferred_min_squim_pesq: float | None = None,
4134
  preferred_min_squim_audio_duration_seconds: float = 0.0,
 
4135
  ) -> CascadeResult:
4136
  """Run one whole trajectory, then deterministic low-coverage refills.
4137
 
@@ -4168,6 +4586,12 @@ def run_coverage_adaptive_cascade(
4168
  generation_evidence_factory
4169
  ):
4170
  raise ValueError("generation_evidence_factory must be callable")
 
 
 
 
 
 
4171
  if candidate_generation_text_transform is not None and not callable(
4172
  candidate_generation_text_transform
4173
  ):
@@ -4408,6 +4832,7 @@ def run_coverage_adaptive_cascade(
4408
  chunks=candidate_chunks,
4409
  expected_candidate_ordinals=expected_ordinals,
4410
  require_explicit_candidate_ordinals=context_aware_evidence,
 
4411
  )
4412
  except Exception as error:
4413
  raise RuntimeError("candidate generation evidence is invalid") from error
@@ -4461,6 +4886,11 @@ def run_coverage_adaptive_cascade(
4461
  chunk_count,
4462
  verifier_name="whole candidate verifier",
4463
  )
 
 
 
 
 
4464
  diagnostic_candidates.append(
4465
  _VerifiedTrajectoryCandidate(
4466
  candidate_index=0,
@@ -4687,6 +5117,11 @@ def run_coverage_adaptive_cascade(
4687
  1,
4688
  verifier_name="refill candidate verifier",
4689
  )
 
 
 
 
 
4690
  latest_local_results[chunk_index] = refill_verification.candidate_results[0]
4691
  diagnostic_candidates.append(
4692
  _VerifiedTrajectoryCandidate(
@@ -4729,14 +5164,67 @@ def run_coverage_adaptive_cascade(
4729
  min_squim_audio_duration_seconds=preferred_squim_duration,
4730
  )
4731
  ):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4732
  return CascadeResult(
4733
- trajectory=refill_trajectory,
4734
- verification=refill_verification,
4735
- seed=seed,
4736
- candidate_index=next_candidate_index,
4737
  attempted_seeds=tuple(attempted_seeds),
4738
- chunk_candidate_indices=(next_candidate_index,),
4739
- chunk_seeds=(seed,),
4740
  selection_mode="whole_trajectory",
4741
  diagnostics=_cascade_diagnostics(diagnostic_candidates),
4742
  generated_chunk_count=generated_chunks,
 
61
  SEQUENCE_FALLBACK_MAX_LOCAL_BOUNDARY_SPEAKER_DROP = 0.15
62
  SEQUENCE_FALLBACK_SPEAKER_WEIGHT = 0.05
63
  SEQUENCE_FALLBACK_BOUNDARY_WEIGHT = 0.10
64
+ ENDPOINT_TAIL_WINDOW_MS = 5.0
65
+ ENDPOINT_HARD_STOP_PENALTY = 0.05
66
+ ENDPOINT_ENERGY_WEIGHT = 0.02
67
+ ENDPOINT_PREFERRED_SQUIM_STOI_SLACK = 0.02
68
+ ENDPOINT_PREFERRED_SQUIM_PESQ_SLACK = 0.03
69
+ CASCADE_EVIDENCE_SCHEMA_VERSION = 6
70
  CASCADE_EVIDENCE_LOG_PREFIX = "[BlueMagpie] cascade evidence "
71
  CASCADE_EVIDENCE_MAX_ATTEMPTS = ADAPTIVE_CASCADE_STAGE_LIMITS[-1]
72
  CASCADE_EVIDENCE_MAX_LOCAL_RESULTS = ADAPTIVE_CASCADE_STAGE_LIMITS[-1]
 
81
  {"whole_trajectory", "sequence_dp", "coverage_sequence_dp"}
82
  )
83
  _CFG_FLOOR_REASONS = frozenset({"network", "short_text"})
84
+ _GENERATION_STOP_REASONS = frozenset(
85
+ {"hard_stop", "native_stop", "stop_threshold"}
86
+ )
87
  _CASCADE_EVIDENCE_REJECTION_CODES = frozenset(
88
  {
89
  "boundary_speaker_drop",
 
123
  cjk_cps: float
124
  ascii_cps: float
125
  hard_stop_margin_steps: int
126
+ short_headroom_max_units: int = 0
127
+ short_hard_stop_floor_steps: int = 0
128
 
129
 
130
  @dataclass(frozen=True)
 
161
  cjk_cps=4.2,
162
  ascii_cps=3.6,
163
  hard_stop_margin_steps=1,
164
+ short_headroom_max_units=2,
165
+ short_hard_stop_floor_steps=5,
166
  )
167
  MIXED_CFG_SCHEDULE = "row_ordinal_zero_and_even_primary_odd_alternate"
168
  MIXED_CFG_PRIMARY = 3.0
 
1458
  return 20.0 * math.log10(rms)
1459
 
1460
 
1461
+ def endpoint_tail_energy_ratio(
1462
+ audio: np.ndarray | Sequence[float],
1463
+ sample_rate: int,
1464
+ *,
1465
+ window_ms: float = ENDPOINT_TAIL_WINDOW_MS,
1466
+ ) -> float:
1467
+ """Measure pre-fade endpoint RMS relative to the waveform peak.
1468
+
1469
+ The ratio is intentionally scale-independent and is measured before final
1470
+ fade/padding. A strongly voiced forced endpoint approaches one, while a
1471
+ naturally quiet endpoint approaches zero.
1472
+ """
1473
+
1474
+ waveform = _mono_audio(audio)
1475
+ if isinstance(sample_rate, (bool, np.bool_)):
1476
+ raise ValueError("sample_rate must be a positive integer")
1477
+ try:
1478
+ rate = operator.index(sample_rate)
1479
+ duration_ms = float(window_ms)
1480
+ except (TypeError, ValueError, OverflowError) as error:
1481
+ raise ValueError("endpoint window must be finite and positive") from error
1482
+ if rate <= 0 or not math.isfinite(duration_ms) or duration_ms <= 0.0:
1483
+ raise ValueError("endpoint window must be finite and positive")
1484
+ window = max(1, int(round(duration_ms * int(rate) / 1000.0)))
1485
+ tail = waveform[-min(waveform.size, window) :]
1486
+ peak = float(np.max(np.abs(waveform)))
1487
+ if not math.isfinite(peak) or peak <= 1.0e-8:
1488
+ return 0.0
1489
+ tail_rms = float(np.sqrt(np.mean(np.square(tail, dtype=np.float64))))
1490
+ if not math.isfinite(tail_rms) or tail_rms < 0.0:
1491
+ raise ValueError("endpoint energy is invalid")
1492
+ return float(np.clip(tail_rms / peak, 0.0, 1.0))
1493
+
1494
+
1495
  def active_audio_median_f0_hz(
1496
  audio: np.ndarray | Sequence[float],
1497
  sample_rate: int,
 
1567
  speaker_embedding: np.ndarray | None = None
1568
  rms_db: float | None = None
1569
  median_f0_hz: float | None = None
1570
+ stop_reason: str | None = None
1571
+ endpoint_energy_ratio: float | None = None
1572
+ generated_steps: int | None = None
1573
+ hard_stop_steps: int | None = None
1574
 
1575
 
1576
  @dataclass(frozen=True)
 
1634
  chunk_candidate_ordinals: tuple[int, ...] = ()
1635
  network_conditioned: tuple[bool, ...] = ()
1636
  chunk_text_variants: tuple[str, ...] = ()
1637
+ chunk_stop_reasons: tuple[str, ...] = ()
1638
+ chunk_endpoint_energy_ratios: tuple[float, ...] = ()
1639
+ chunk_generated_steps: tuple[int, ...] = ()
1640
+ chunk_hard_stop_steps: tuple[int, ...] = ()
1641
 
1642
 
1643
  @dataclass(frozen=True)
 
1656
  chunk_candidate_ordinals: tuple[int, ...]
1657
  network_conditioned: tuple[bool, ...]
1658
  chunk_text_variants: tuple[str, ...]
1659
+ chunk_stop_reasons: tuple[str, ...]
1660
+ chunk_endpoint_energy_ratios: tuple[float, ...]
1661
+ chunk_generated_steps: tuple[int, ...]
1662
+ chunk_hard_stop_steps: tuple[int, ...]
1663
  scheduled_cfg: float | None
1664
  effective_cfgs: tuple[float, ...]
1665
  floor_reasons: tuple[tuple[str, ...], ...]
 
2588
  "chunk_policies": chunk_policies,
2589
  "chunk_text_variants": list(evidence.chunk_text_variants),
2590
  "network_conditioned": list(evidence.network_conditioned),
2591
+ "chunk_stop_reasons": list(evidence.chunk_stop_reasons),
2592
+ "chunk_endpoint_energy_ratios": list(
2593
+ evidence.chunk_endpoint_energy_ratios
2594
+ ),
2595
+ "chunk_generated_steps": list(evidence.chunk_generated_steps),
2596
+ "chunk_hard_stop_steps": list(evidence.chunk_hard_stop_steps),
2597
  "scheduled_cfg": evidence.scheduled_cfg,
2598
  "effective_cfgs": list(evidence.effective_cfgs),
2599
  "floor_reasons": [list(reasons) for reasons in evidence.floor_reasons],
 
2683
  policies: list[str | None] = []
2684
  network_conditioned: list[bool | None] = []
2685
  chunk_text_variants: list[str | None] = []
2686
+ stop_reasons: list[str | None] = []
2687
+ endpoint_energy_ratios: list[float | None] = []
2688
+ generated_steps: list[int | None] = []
2689
+ hard_stop_steps: list[int | None] = []
2690
  complete = True
2691
+ endpoint_complete = True
2692
  for chunk_index, candidate_index in enumerate(
2693
  selection.chunk_candidate_indices
2694
  ):
 
2702
  policies.append(None)
2703
  network_conditioned.append(None)
2704
  chunk_text_variants.append(None)
2705
+ stop_reasons.append(None)
2706
+ endpoint_energy_ratios.append(None)
2707
+ generated_steps.append(None)
2708
+ hard_stop_steps.append(None)
2709
+ endpoint_complete = False
2710
  continue
2711
  try:
2712
  local_index = attempt.chunk_indices.index(chunk_index)
 
2721
  policies.append(None)
2722
  network_conditioned.append(None)
2723
  chunk_text_variants.append(None)
2724
+ stop_reasons.append(None)
2725
+ endpoint_energy_ratios.append(None)
2726
+ generated_steps.append(None)
2727
+ hard_stop_steps.append(None)
2728
+ endpoint_complete = False
2729
  continue
2730
  try:
2731
  ordinal = attempt.chunk_candidate_ordinals[local_index]
 
2751
  except IndexError:
2752
  complete = False
2753
  chunk_text_variants.append(None)
2754
+ try:
2755
+ stop_reason = attempt.chunk_stop_reasons[local_index]
2756
+ endpoint_energy_ratio = (
2757
+ attempt.chunk_endpoint_energy_ratios[local_index]
2758
+ )
2759
+ generated_step_count = attempt.chunk_generated_steps[local_index]
2760
+ hard_stop_step_count = attempt.chunk_hard_stop_steps[local_index]
2761
+ except IndexError:
2762
+ endpoint_complete = False
2763
+ stop_reasons.append(None)
2764
+ endpoint_energy_ratios.append(None)
2765
+ generated_steps.append(None)
2766
+ hard_stop_steps.append(None)
2767
+ else:
2768
+ endpoint_artifact = ChunkCandidateArtifact(
2769
+ stop_reason=stop_reason,
2770
+ endpoint_energy_ratio=endpoint_energy_ratio,
2771
+ generated_steps=generated_step_count,
2772
+ hard_stop_steps=hard_stop_step_count,
2773
+ )
2774
+ if (
2775
+ stop_reason is None
2776
+ or endpoint_energy_ratio is None
2777
+ or generated_step_count is None
2778
+ or hard_stop_step_count is None
2779
+ or not _endpoint_artifact_is_valid(endpoint_artifact)
2780
+ ):
2781
+ endpoint_complete = False
2782
+ stop_reasons.append(stop_reason)
2783
+ endpoint_energy_ratios.append(endpoint_energy_ratio)
2784
+ generated_steps.append(generated_step_count)
2785
+ hard_stop_steps.append(hard_stop_step_count)
2786
  return {
2787
  "complete": complete,
2788
+ "endpoint_complete": endpoint_complete,
2789
  "chunk_scheduled_cfgs": scheduled_cfgs,
2790
  "chunk_effective_cfgs": effective_cfgs,
2791
  "chunk_floor_reasons": floor_reasons,
 
2793
  "chunk_policies": policies,
2794
  "network_conditioned": network_conditioned,
2795
  "chunk_text_variants": chunk_text_variants,
2796
+ "chunk_stop_reasons": stop_reasons,
2797
+ "chunk_endpoint_energy_ratios": endpoint_energy_ratios,
2798
+ "chunk_generated_steps": generated_steps,
2799
+ "chunk_hard_stop_steps": hard_stop_steps,
2800
  }
2801
 
2802
 
2803
+ def _attempt_endpoint_evidence_is_complete(
2804
+ attempt: CandidateAttemptEvidence,
2805
+ ) -> bool:
2806
+ """Validate every bounded endpoint row before declaring it complete."""
2807
+
2808
+ row_count = len(attempt.chunk_indices)
2809
+ endpoint_rows = (
2810
+ attempt.chunk_stop_reasons,
2811
+ attempt.chunk_endpoint_energy_ratios,
2812
+ attempt.chunk_generated_steps,
2813
+ attempt.chunk_hard_stop_steps,
2814
+ )
2815
+ if row_count == 0 or any(len(row) != row_count for row in endpoint_rows):
2816
+ return False
2817
+ return all(
2818
+ reason is not None
2819
+ and energy is not None
2820
+ and generated is not None
2821
+ and hard_stop is not None
2822
+ and _endpoint_artifact_is_valid(
2823
+ ChunkCandidateArtifact(
2824
+ stop_reason=reason,
2825
+ endpoint_energy_ratio=energy,
2826
+ generated_steps=generated,
2827
+ hard_stop_steps=hard_stop,
2828
+ )
2829
+ )
2830
+ for reason, energy, generated, hard_stop in zip(
2831
+ *endpoint_rows,
2832
+ strict=True,
2833
+ )
2834
+ )
2835
+
2836
+
2837
  def format_cascade_evidence_log(
2838
  diagnostics: CascadeDiagnostics,
2839
  *,
 
2873
  "generated_text_unit_limit must be an integer between 1 and 800"
2874
  )
2875
 
2876
+ attempts = diagnostics.attempts[:CASCADE_EVIDENCE_MAX_ATTEMPTS]
2877
+ for attempt in attempts:
2878
+ endpoint_rows = (
2879
+ attempt.chunk_stop_reasons,
2880
+ attempt.chunk_endpoint_energy_ratios,
2881
+ attempt.chunk_generated_steps,
2882
+ attempt.chunk_hard_stop_steps,
2883
+ )
2884
+ if any(endpoint_rows) and not _attempt_endpoint_evidence_is_complete(
2885
+ attempt
2886
+ ):
2887
+ raise ValueError("canonical endpoint evidence is invalid")
2888
+
2889
  selected: dict[str, Any] | None = None
2890
  if selection is not None:
2891
  if not isinstance(selection, CascadeResult):
 
2922
  ),
2923
  }
2924
 
 
2925
  generation_evidence_complete = bool(attempts) and all(
2926
  attempt.scheduled_cfg is not None
2927
  and len(attempt.chunk_indices) == len(attempt.chunk_text_units)
 
2933
  and bool(attempt.chunk_indices)
2934
  for attempt in attempts
2935
  )
2936
+ endpoint_evidence_complete = bool(attempts) and all(
2937
+ _attempt_endpoint_evidence_is_complete(attempt)
2938
+ for attempt in attempts
2939
+ )
2940
  generated_chunk_count = sum(len(attempt.chunk_indices) for attempt in attempts)
2941
  generated_text_units = sum(
2942
  sum(attempt.chunk_text_units) for attempt in attempts
 
2970
  },
2971
  "attempt_count": len(diagnostics.attempts),
2972
  "generation_evidence_complete": generation_evidence_complete,
2973
+ "endpoint_evidence_complete": endpoint_evidence_complete,
2974
  "generated_chunk_count": generated_chunk_count,
2975
  "generated_text_units": generated_text_units,
2976
  "attempts": [
 
3452
  chunks: tuple[str, ...],
3453
  expected_candidate_ordinals: tuple[int, ...],
3454
  require_explicit_candidate_ordinals: bool,
3455
+ require_endpoint_evidence: bool,
3456
  ) -> CandidateGenerationEvidence:
3457
  """Validate deterministic CFG evidence supplied by the hosted app."""
3458
 
 
3494
  chunk_text_variants = value.chunk_text_variants
3495
  else:
3496
  chunk_text_variants = ("base",) * len(chunks)
3497
+ endpoint_rows = (
3498
+ value.chunk_stop_reasons,
3499
+ value.chunk_endpoint_energy_ratios,
3500
+ value.chunk_generated_steps,
3501
+ value.chunk_hard_stop_steps,
3502
+ )
3503
+ endpoint_evidence_present = any(endpoint_rows)
3504
+ if require_endpoint_evidence and not all(endpoint_rows):
3505
+ raise ValueError("generation endpoint evidence is required")
3506
+ if endpoint_evidence_present and not all(
3507
+ isinstance(row, tuple) and len(row) == len(chunks)
3508
+ for row in endpoint_rows
3509
+ ):
3510
+ raise ValueError("generation endpoint evidence does not match the attempt")
3511
+ stop_reasons: list[str] = []
3512
+ endpoint_energy_ratios: list[float] = []
3513
+ generated_steps: list[int] = []
3514
+ hard_stop_steps: list[int] = []
3515
+ if endpoint_evidence_present:
3516
+ for raw_reason, raw_energy, raw_generated, raw_hard_stop in zip(
3517
+ *endpoint_rows,
3518
+ strict=True,
3519
+ ):
3520
+ if raw_reason not in _GENERATION_STOP_REASONS:
3521
+ raise ValueError("generation stop reason is invalid")
3522
+ energy = _finite_float(raw_energy, minimum=0.0, maximum=1.0)
3523
+ if energy is None:
3524
+ raise ValueError("generation endpoint energy is invalid")
3525
+ if any(
3526
+ isinstance(value, (bool, np.bool_))
3527
+ for value in (raw_generated, raw_hard_stop)
3528
+ ):
3529
+ raise ValueError("generation endpoint steps are invalid")
3530
+ try:
3531
+ generated = operator.index(raw_generated)
3532
+ hard_stop = operator.index(raw_hard_stop)
3533
+ except (TypeError, ValueError, OverflowError) as error:
3534
+ raise ValueError("generation endpoint steps are invalid") from error
3535
+ if (
3536
+ not 1 <= generated <= 2_000
3537
+ or not 1 <= hard_stop <= 2_000
3538
+ or generated > hard_stop
3539
+ or (raw_reason == "hard_stop" and generated != hard_stop)
3540
+ ):
3541
+ raise ValueError("generation endpoint steps are invalid")
3542
+ stop_reasons.append(raw_reason)
3543
+ endpoint_energy_ratios.append(energy)
3544
+ generated_steps.append(int(generated))
3545
+ hard_stop_steps.append(int(hard_stop))
3546
  raw_ordinals = value.chunk_candidate_ordinals
3547
  if not raw_ordinals:
3548
  if require_explicit_candidate_ordinals:
 
3623
  chunk_candidate_ordinals=candidate_ordinals,
3624
  network_conditioned=network_conditioned,
3625
  chunk_text_variants=chunk_text_variants,
3626
+ chunk_stop_reasons=tuple(stop_reasons),
3627
+ chunk_endpoint_energy_ratios=tuple(endpoint_energy_ratios),
3628
+ chunk_generated_steps=tuple(generated_steps),
3629
+ chunk_hard_stop_steps=tuple(hard_stop_steps),
3630
  )
3631
 
3632
 
 
3668
  chunk_text_variants=(
3669
  generation.chunk_text_variants if generation is not None else ()
3670
  ),
3671
+ chunk_stop_reasons=(
3672
+ generation.chunk_stop_reasons if generation is not None else ()
3673
+ ),
3674
+ chunk_endpoint_energy_ratios=(
3675
+ generation.chunk_endpoint_energy_ratios
3676
+ if generation is not None
3677
+ else ()
3678
+ ),
3679
+ chunk_generated_steps=(
3680
+ generation.chunk_generated_steps if generation is not None else ()
3681
+ ),
3682
+ chunk_hard_stop_steps=(
3683
+ generation.chunk_hard_stop_steps if generation is not None else ()
3684
+ ),
3685
  scheduled_cfg=(generation.scheduled_cfg if generation is not None else None),
3686
  effective_cfgs=(generation.effective_cfgs if generation is not None else ()),
3687
  floor_reasons=(generation.floor_reasons if generation is not None else ()),
 
3833
  except ValueError:
3834
  speaker_artifact_valid = False
3835
  if speaker_artifact_valid:
3836
+ endpoint_cost = candidate_endpoint_selection_cost(
3837
+ artifact
3838
+ )
3839
+ adjusted_score = adjusted_result.score + endpoint_cost
3840
+ if math.isfinite(adjusted_score):
3841
+ adjusted_result = replace(
3842
+ adjusted_result,
3843
+ score=adjusted_score,
3844
+ )
3845
+ adjusted_results[-1] = adjusted_result
3846
+ score = adjusted_score
3847
  local_scores[chunk_index].append(score)
3848
  sequence_results.append(tuple(adjusted_results))
3849
 
 
4226
  return verification
4227
 
4228
 
4229
+ def _endpoint_artifact_is_valid(artifact: ChunkCandidateArtifact) -> bool:
4230
+ """Validate an optional all-or-none endpoint provenance row."""
4231
+
4232
+ endpoint_values = (
4233
+ artifact.stop_reason,
4234
+ artifact.endpoint_energy_ratio,
4235
+ artifact.generated_steps,
4236
+ artifact.hard_stop_steps,
4237
+ )
4238
+ if all(value is None for value in endpoint_values):
4239
+ return True
4240
+ if any(value is not None for value in endpoint_values):
4241
+ if any(value is None for value in endpoint_values):
4242
+ return False
4243
+ if artifact.stop_reason not in _GENERATION_STOP_REASONS:
4244
+ return False
4245
+ energy = _finite_float(
4246
+ artifact.endpoint_energy_ratio,
4247
+ minimum=0.0,
4248
+ maximum=1.0,
4249
+ )
4250
+ if energy is None or any(
4251
+ isinstance(value, (bool, np.bool_))
4252
+ for value in (artifact.generated_steps, artifact.hard_stop_steps)
4253
+ ):
4254
+ return False
4255
+ try:
4256
+ generated = operator.index(artifact.generated_steps)
4257
+ hard_stop = operator.index(artifact.hard_stop_steps)
4258
+ except (TypeError, ValueError, OverflowError):
4259
+ return False
4260
+ if (
4261
+ not 1 <= generated <= 2_000
4262
+ or not 1 <= hard_stop <= 2_000
4263
+ or generated > hard_stop
4264
+ or (
4265
+ artifact.stop_reason == "hard_stop"
4266
+ and generated != hard_stop
4267
+ )
4268
+ ):
4269
+ return False
4270
+ return True
4271
+
4272
+
4273
  def _coverage_artifact_is_valid(
4274
  result: CandidateGateResult,
4275
  artifact: ChunkCandidateArtifact,
 
4295
  minimum=1.0,
4296
  ) is None:
4297
  return False
4298
+ if not _endpoint_artifact_is_valid(artifact):
4299
+ return False
4300
  embedding = artifact.speaker_embedding
4301
  if result.speaker_gate_applied is True and embedding is None:
4302
  return False
 
4309
  return True
4310
 
4311
 
4312
+ def _bind_generation_endpoint_evidence(
4313
+ verification: TrajectoryGateResult,
4314
+ generation: CandidateGenerationEvidence | None,
4315
+ *,
4316
+ required: bool,
4317
+ ) -> TrajectoryGateResult:
4318
+ """Attach validated generation endpoint provenance to chunk artifacts."""
4319
+
4320
+ if generation is None or not generation.chunk_stop_reasons:
4321
+ if required:
4322
+ raise RuntimeError("candidate endpoint evidence is missing")
4323
+ return verification
4324
+ row_count = len(verification.chunk_artifacts)
4325
+ endpoint_rows = (
4326
+ generation.chunk_stop_reasons,
4327
+ generation.chunk_endpoint_energy_ratios,
4328
+ generation.chunk_generated_steps,
4329
+ generation.chunk_hard_stop_steps,
4330
+ )
4331
+ if any(len(row) != row_count for row in endpoint_rows):
4332
+ raise RuntimeError("candidate endpoint evidence is misaligned")
4333
+ artifacts = tuple(
4334
+ replace(
4335
+ artifact,
4336
+ stop_reason=reason,
4337
+ endpoint_energy_ratio=energy,
4338
+ generated_steps=generated,
4339
+ hard_stop_steps=hard_stop,
4340
+ )
4341
+ for artifact, reason, energy, generated, hard_stop in zip(
4342
+ verification.chunk_artifacts,
4343
+ *endpoint_rows,
4344
+ strict=True,
4345
+ )
4346
+ )
4347
+ if any(
4348
+ not _coverage_artifact_is_valid(result, artifact)
4349
+ for result, artifact in zip(
4350
+ verification.candidate_results,
4351
+ artifacts,
4352
+ strict=True,
4353
+ )
4354
+ if result.comparison.passed is True
4355
+ ):
4356
+ raise RuntimeError("candidate endpoint evidence is invalid")
4357
+ return replace(verification, chunk_artifacts=artifacts)
4358
+
4359
+
4360
+ def candidate_endpoint_selection_cost(
4361
+ artifact: ChunkCandidateArtifact,
4362
+ ) -> float:
4363
+ """Return a bounded soft preference for natural, quiet endpoints."""
4364
+
4365
+ if artifact.stop_reason is None and artifact.endpoint_energy_ratio is None:
4366
+ return 0.0
4367
+ if not _endpoint_artifact_is_valid(artifact):
4368
+ return math.inf
4369
+ energy = float(artifact.endpoint_energy_ratio)
4370
+ hard_stop = (
4371
+ ENDPOINT_HARD_STOP_PENALTY
4372
+ if _endpoint_artifact_reached_hard_cap(artifact)
4373
+ else 0.0
4374
+ )
4375
+ return hard_stop + ENDPOINT_ENERGY_WEIGHT * energy
4376
+
4377
+
4378
+ def _endpoint_artifact_reached_hard_cap(
4379
+ artifact: ChunkCandidateArtifact,
4380
+ ) -> bool:
4381
+ """Return whether endpoint evidence reached the configured hard cap.
4382
+
4383
+ A threshold crossing can coincide with the final permitted generation
4384
+ step. The stop reason correctly records that the model crossed the
4385
+ threshold, but endpoint selection must still treat it as cap-reached so it
4386
+ cannot evade the bounded hard-cap cost or natural-endpoint waiver rules.
4387
+ """
4388
+
4389
+ if not _endpoint_artifact_is_valid(artifact):
4390
+ return False
4391
+ if artifact.generated_steps is None or artifact.hard_stop_steps is None:
4392
+ return False
4393
+ return artifact.generated_steps >= artifact.hard_stop_steps
4394
+
4395
+
4396
+ def _preferred_natural_endpoint_waiver(
4397
+ verification: TrajectoryGateResult,
4398
+ artifact: ChunkCandidateArtifact,
4399
+ *,
4400
+ min_speaker_similarity: float | None,
4401
+ max_boundary_speaker_drop: float | None,
4402
+ min_squim_stoi: float | None,
4403
+ min_squim_pesq: float | None,
4404
+ min_squim_audio_duration_seconds: float,
4405
+ ) -> bool:
4406
+ """Allow only a tightly bounded quality trade for a true pre-cap stop."""
4407
+
4408
+ if (
4409
+ artifact.stop_reason != "stop_threshold"
4410
+ or _endpoint_artifact_reached_hard_cap(artifact)
4411
+ ):
4412
+ return False
4413
+ relaxed_stoi = (
4414
+ None
4415
+ if min_squim_stoi is None
4416
+ else max(0.0, min_squim_stoi - ENDPOINT_PREFERRED_SQUIM_STOI_SLACK)
4417
+ )
4418
+ relaxed_pesq = (
4419
+ None
4420
+ if min_squim_pesq is None
4421
+ else max(0.0, min_squim_pesq - ENDPOINT_PREFERRED_SQUIM_PESQ_SLACK)
4422
+ )
4423
+ return _preferred_release_verification(
4424
+ verification,
4425
+ min_speaker_similarity=min_speaker_similarity,
4426
+ max_boundary_speaker_drop=max_boundary_speaker_drop,
4427
+ min_squim_stoi=relaxed_stoi,
4428
+ min_squim_pesq=relaxed_pesq,
4429
+ min_squim_audio_duration_seconds=min_squim_audio_duration_seconds,
4430
+ )
4431
+
4432
+
4433
  def _coverage_local_candidate(
4434
  *,
4435
  candidate_index: int,
 
4454
  return None
4455
  if not _coverage_artifact_is_valid(adjusted, artifact):
4456
  raise RuntimeError("local verifier passed without valid acoustic evidence")
4457
+ endpoint_cost = candidate_endpoint_selection_cost(artifact)
4458
+ adjusted_score = adjusted.score + endpoint_cost
4459
+ if not math.isfinite(adjusted_score) or adjusted_score < 0.0:
4460
+ raise RuntimeError("local verifier passed without valid endpoint evidence")
4461
+ adjusted = replace(adjusted, score=adjusted_score)
4462
  return _RaggedChunkCandidate(
4463
  candidate_index=candidate_index,
4464
  seed=seed,
 
4549
  preferred_min_squim_stoi: float | None = None,
4550
  preferred_min_squim_pesq: float | None = None,
4551
  preferred_min_squim_audio_duration_seconds: float = 0.0,
4552
+ require_endpoint_evidence: bool = False,
4553
  ) -> CascadeResult:
4554
  """Run one whole trajectory, then deterministic low-coverage refills.
4555
 
 
4586
  generation_evidence_factory
4587
  ):
4588
  raise ValueError("generation_evidence_factory must be callable")
4589
+ if type(require_endpoint_evidence) is not bool:
4590
+ raise ValueError("require_endpoint_evidence must be a boolean")
4591
+ if require_endpoint_evidence and generation_evidence_factory is None:
4592
+ raise ValueError(
4593
+ "endpoint evidence requires a generation evidence factory"
4594
+ )
4595
  if candidate_generation_text_transform is not None and not callable(
4596
  candidate_generation_text_transform
4597
  ):
 
4832
  chunks=candidate_chunks,
4833
  expected_candidate_ordinals=expected_ordinals,
4834
  require_explicit_candidate_ordinals=context_aware_evidence,
4835
+ require_endpoint_evidence=require_endpoint_evidence,
4836
  )
4837
  except Exception as error:
4838
  raise RuntimeError("candidate generation evidence is invalid") from error
 
4886
  chunk_count,
4887
  verifier_name="whole candidate verifier",
4888
  )
4889
+ initial_verification = _bind_generation_endpoint_evidence(
4890
+ initial_verification,
4891
+ initial_generation_evidence,
4892
+ required=require_endpoint_evidence,
4893
+ )
4894
  diagnostic_candidates.append(
4895
  _VerifiedTrajectoryCandidate(
4896
  candidate_index=0,
 
5117
  1,
5118
  verifier_name="refill candidate verifier",
5119
  )
5120
+ refill_verification = _bind_generation_endpoint_evidence(
5121
+ refill_verification,
5122
+ refill_generation_evidence,
5123
+ required=require_endpoint_evidence,
5124
+ )
5125
  latest_local_results[chunk_index] = refill_verification.candidate_results[0]
5126
  diagnostic_candidates.append(
5127
  _VerifiedTrajectoryCandidate(
 
5164
  min_squim_audio_duration_seconds=preferred_squim_duration,
5165
  )
5166
  ):
5167
+ preferred_candidate = diagnostic_candidates[-1]
5168
+ preferred_artifact = preferred_candidate.verification.chunk_artifacts[0]
5169
+ preferred_reached_hard_cap = (
5170
+ _endpoint_artifact_reached_hard_cap(preferred_artifact)
5171
+ )
5172
+ selectable = [
5173
+ candidate
5174
+ for candidate in diagnostic_candidates
5175
+ if candidate.verification.passed is True
5176
+ and math.isfinite(candidate.verification.score)
5177
+ and len(candidate.verification.chunk_artifacts) == 1
5178
+ and (
5179
+ _preferred_release_verification(
5180
+ candidate.verification,
5181
+ min_speaker_similarity=preferred_similarity,
5182
+ max_boundary_speaker_drop=preferred_boundary,
5183
+ min_squim_stoi=preferred_stoi,
5184
+ min_squim_pesq=preferred_pesq,
5185
+ min_squim_audio_duration_seconds=(
5186
+ preferred_squim_duration
5187
+ ),
5188
+ )
5189
+ or (
5190
+ preferred_reached_hard_cap
5191
+ and _preferred_natural_endpoint_waiver(
5192
+ candidate.verification,
5193
+ candidate.verification.chunk_artifacts[0],
5194
+ min_speaker_similarity=preferred_similarity,
5195
+ max_boundary_speaker_drop=preferred_boundary,
5196
+ min_squim_stoi=preferred_stoi,
5197
+ min_squim_pesq=preferred_pesq,
5198
+ min_squim_audio_duration_seconds=(
5199
+ preferred_squim_duration
5200
+ ),
5201
+ )
5202
+ )
5203
+ )
5204
+ and math.isfinite(
5205
+ candidate_endpoint_selection_cost(
5206
+ candidate.verification.chunk_artifacts[0]
5207
+ )
5208
+ )
5209
+ ]
5210
+ selected_candidate = min(
5211
+ selectable,
5212
+ key=lambda candidate: (
5213
+ candidate.verification.score
5214
+ + candidate_endpoint_selection_cost(
5215
+ candidate.verification.chunk_artifacts[0]
5216
+ ),
5217
+ candidate.candidate_index,
5218
+ ),
5219
+ )
5220
  return CascadeResult(
5221
+ trajectory=selected_candidate.trajectory,
5222
+ verification=selected_candidate.verification,
5223
+ seed=selected_candidate.seed,
5224
+ candidate_index=selected_candidate.candidate_index,
5225
  attempted_seeds=tuple(attempted_seeds),
5226
+ chunk_candidate_indices=(selected_candidate.candidate_index,),
5227
+ chunk_seeds=(selected_candidate.seed,),
5228
  selection_mode="whole_trajectory",
5229
  diagnostics=_cascade_diagnostics(diagnostic_candidates),
5230
  generated_chunk_count=generated_chunks,
tests/test_coverage_adaptive.py CHANGED
@@ -1,3 +1,4 @@
 
1
  import json
2
  import math
3
 
@@ -368,6 +369,222 @@ def test_single_chunk_requires_joint_preferred_quality_and_speaker_for_early_ret
368
  assert payload["selection"]["generated_chunks"] == 3
369
 
370
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
371
  def test_single_chunk_final_cap_selects_lowest_bounded_soft_quality_cost():
372
  chunk = ("完整內容",)
373
  profiles = {
@@ -567,7 +784,7 @@ def test_refill_budget_accounts_exact_generated_chunks_and_text_units():
567
  selection=result,
568
  )
569
  payload = json.loads(line.removeprefix(CASCADE_EVIDENCE_LOG_PREFIX))
570
- assert payload["schema_version"] == 5
571
  assert payload["generation_evidence_complete"] is True
572
  assert payload["request_chunk_count"] == 2
573
  assert payload["generated_chunk_count"] == 3
@@ -590,6 +807,11 @@ def test_refill_budget_accounts_exact_generated_chunks_and_text_units():
590
  "chunk_policies": ["safe_duration", "base"],
591
  "network_conditioned": [False, False],
592
  "chunk_text_variants": ["base", "base"],
 
 
 
 
 
593
  }
594
 
595
 
 
1
+ from dataclasses import replace
2
  import json
3
  import math
4
 
 
369
  assert payload["selection"]["generated_chunks"] == 3
370
 
371
 
372
+ def test_preferred_refill_selects_prior_natural_endpoint_over_forced_candidate():
373
+ chunk = ("完整內容",)
374
+ generated = []
375
+ profiles = {
376
+ 10: (0.65, 1.15),
377
+ 11: (0.71, 1.19),
378
+ 12: (0.73, 1.21),
379
+ }
380
+
381
+ def verifier(trajectory, chunks, seed):
382
+ stoi, pesq = profiles[seed]
383
+ return _squim_verification(
384
+ chunks,
385
+ stoi=stoi,
386
+ pesq=pesq,
387
+ speaker_similarity=0.30,
388
+ )
389
+
390
+ def generation_evidence(candidate_index, seed, chunk_indices, candidate_chunks):
391
+ scheduled = generation_cfg_for_candidate_offset(candidate_index)
392
+ effective = max(3.0, scheduled)
393
+ threshold_stop = candidate_index == 1
394
+ return CandidateGenerationEvidence(
395
+ chunk_indices=chunk_indices,
396
+ chunk_text_units=(4,),
397
+ scheduled_cfg=scheduled,
398
+ effective_cfgs=(effective,),
399
+ floor_reasons=(("short_text",),) if effective != scheduled else ((),),
400
+ chunk_stop_reasons=(
401
+ ("stop_threshold",) if threshold_stop else ("hard_stop",)
402
+ ),
403
+ chunk_endpoint_energy_ratios=(
404
+ (0.10,) if threshold_stop else (0.90,)
405
+ ),
406
+ chunk_generated_steps=((4,) if threshold_stop else (5,)),
407
+ chunk_hard_stop_steps=(5,),
408
+ )
409
+
410
+ result = run_coverage_adaptive_cascade(
411
+ chunk,
412
+ 10,
413
+ lambda chunks, seed: generated.append(seed) or (f"audio-{seed}",),
414
+ verifier,
415
+ verifier,
416
+ sequence_final_verifier=lambda result, chunks: _exact_final(chunks),
417
+ generation_evidence_factory=generation_evidence,
418
+ max_generated_chunks=5,
419
+ max_generated_text_units=100,
420
+ preferred_min_speaker_similarity=0.25,
421
+ preferred_max_boundary_speaker_drop=0.05,
422
+ preferred_min_squim_stoi=0.72,
423
+ preferred_min_squim_pesq=1.20,
424
+ require_endpoint_evidence=True,
425
+ )
426
+
427
+ assert generated == [10, 11, 12]
428
+ assert result.candidate_index == 1
429
+ assert result.seed == 11
430
+ artifact = result.verification.chunk_artifacts[0]
431
+ assert artifact.stop_reason == "stop_threshold"
432
+ assert artifact.endpoint_energy_ratio == pytest.approx(0.10)
433
+ payload = json.loads(
434
+ format_cascade_evidence_log(
435
+ result.diagnostics,
436
+ outcome="returned",
437
+ generated_chunk_limit=5,
438
+ generated_text_unit_limit=100,
439
+ selection=result,
440
+ ).removeprefix(CASCADE_EVIDENCE_LOG_PREFIX)
441
+ )
442
+ assert payload["endpoint_evidence_complete"] is True
443
+ assert payload["selection"]["generation"]["endpoint_complete"] is True
444
+ assert payload["selection"]["generation"]["chunk_stop_reasons"] == [
445
+ "stop_threshold"
446
+ ]
447
+
448
+
449
+ @pytest.mark.parametrize(
450
+ ("field", "value"),
451
+ [
452
+ ("chunk_stop_reasons", ("unknown",)),
453
+ ("chunk_endpoint_energy_ratios", (math.nan,)),
454
+ ("chunk_generated_steps", (True,)),
455
+ ("chunk_generated_steps", (6,)),
456
+ ],
457
+ )
458
+ def test_canonical_log_rejects_invalid_endpoint_rows(field, value):
459
+ chunk = ("完整內容",)
460
+
461
+ def evidence(candidate_index, seed, chunk_indices, candidate_chunks):
462
+ return CandidateGenerationEvidence(
463
+ chunk_indices=chunk_indices,
464
+ chunk_text_units=(4,),
465
+ scheduled_cfg=3.0,
466
+ effective_cfgs=(3.0,),
467
+ floor_reasons=((),),
468
+ chunk_stop_reasons=("stop_threshold",),
469
+ chunk_endpoint_energy_ratios=(0.10,),
470
+ chunk_generated_steps=(4,),
471
+ chunk_hard_stop_steps=(5,),
472
+ )
473
+
474
+ result = run_coverage_adaptive_cascade(
475
+ chunk,
476
+ 10,
477
+ lambda chunks, seed: (f"audio-{seed}",),
478
+ lambda trajectory, chunks, seed: _squim_verification(
479
+ chunks,
480
+ stoi=0.73,
481
+ pesq=1.21,
482
+ speaker_similarity=0.30,
483
+ ),
484
+ lambda trajectory, chunks, seed: _squim_verification(
485
+ chunks,
486
+ stoi=0.73,
487
+ pesq=1.21,
488
+ speaker_similarity=0.30,
489
+ ),
490
+ sequence_final_verifier=lambda result, chunks: _exact_final(chunks),
491
+ generation_evidence_factory=evidence,
492
+ max_generated_chunks=5,
493
+ max_generated_text_units=100,
494
+ preferred_min_speaker_similarity=0.25,
495
+ preferred_max_boundary_speaker_drop=0.05,
496
+ preferred_min_squim_stoi=0.72,
497
+ preferred_min_squim_pesq=1.20,
498
+ require_endpoint_evidence=True,
499
+ )
500
+
501
+ invalid_attempt = replace(
502
+ result.diagnostics.attempts[0],
503
+ **{field: value},
504
+ )
505
+ invalid_diagnostics = replace(
506
+ result.diagnostics,
507
+ attempts=(invalid_attempt,),
508
+ )
509
+ with pytest.raises(ValueError, match="canonical endpoint evidence is invalid"):
510
+ format_cascade_evidence_log(
511
+ invalid_diagnostics,
512
+ outcome="returned",
513
+ generated_chunk_limit=5,
514
+ generated_text_unit_limit=100,
515
+ selection=result,
516
+ )
517
+
518
+
519
+ @pytest.mark.parametrize(
520
+ ("natural_stoi", "natural_pesq", "natural_speaker", "natural_steps"),
521
+ [
522
+ (0.69, 1.19, 0.30, 4),
523
+ (0.71, 1.16, 0.30, 4),
524
+ (0.71, 1.19, 0.24, 4),
525
+ (0.71, 1.19, 0.30, 5),
526
+ ],
527
+ )
528
+ def test_natural_endpoint_waiver_cannot_bypass_bounded_preferred_tier(
529
+ natural_stoi,
530
+ natural_pesq,
531
+ natural_speaker,
532
+ natural_steps,
533
+ ):
534
+ chunk = ("完整內容",)
535
+ profiles = {
536
+ 10: (0.65, 1.15, 0.30),
537
+ 11: (natural_stoi, natural_pesq, natural_speaker),
538
+ 12: (0.73, 1.21, 0.30),
539
+ }
540
+
541
+ def verifier(trajectory, chunks, seed):
542
+ stoi, pesq, speaker = profiles[seed]
543
+ return _squim_verification(
544
+ chunks,
545
+ stoi=stoi,
546
+ pesq=pesq,
547
+ speaker_similarity=speaker,
548
+ )
549
+
550
+ def generation_evidence(candidate_index, seed, chunk_indices, candidate_chunks):
551
+ natural = candidate_index == 1
552
+ scheduled = generation_cfg_for_candidate_offset(candidate_index)
553
+ return CandidateGenerationEvidence(
554
+ chunk_indices=chunk_indices,
555
+ chunk_text_units=(4,),
556
+ scheduled_cfg=scheduled,
557
+ effective_cfgs=(scheduled,),
558
+ floor_reasons=((),),
559
+ chunk_stop_reasons=(
560
+ ("stop_threshold",) if natural else ("hard_stop",)
561
+ ),
562
+ chunk_endpoint_energy_ratios=((0.10,) if natural else (0.90,)),
563
+ chunk_generated_steps=((natural_steps,) if natural else (5,)),
564
+ chunk_hard_stop_steps=(5,),
565
+ )
566
+
567
+ result = run_coverage_adaptive_cascade(
568
+ chunk,
569
+ 10,
570
+ lambda chunks, seed: (f"audio-{seed}",),
571
+ verifier,
572
+ verifier,
573
+ sequence_final_verifier=lambda result, chunks: _exact_final(chunks),
574
+ generation_evidence_factory=generation_evidence,
575
+ max_generated_chunks=5,
576
+ max_generated_text_units=100,
577
+ preferred_min_speaker_similarity=0.25,
578
+ preferred_max_boundary_speaker_drop=0.05,
579
+ preferred_min_squim_stoi=0.72,
580
+ preferred_min_squim_pesq=1.20,
581
+ require_endpoint_evidence=True,
582
+ )
583
+
584
+ assert result.candidate_index == 2
585
+ assert result.seed == 12
586
+
587
+
588
  def test_single_chunk_final_cap_selects_lowest_bounded_soft_quality_cost():
589
  chunk = ("完整內容",)
590
  profiles = {
 
784
  selection=result,
785
  )
786
  payload = json.loads(line.removeprefix(CASCADE_EVIDENCE_LOG_PREFIX))
787
+ assert payload["schema_version"] == 6
788
  assert payload["generation_evidence_complete"] is True
789
  assert payload["request_chunk_count"] == 2
790
  assert payload["generated_chunk_count"] == 3
 
807
  "chunk_policies": ["safe_duration", "base"],
808
  "network_conditioned": [False, False],
809
  "chunk_text_variants": ["base", "base"],
810
+ "endpoint_complete": False,
811
+ "chunk_stop_reasons": [None, None],
812
+ "chunk_endpoint_energy_ratios": [None, None],
813
+ "chunk_generated_steps": [None, None],
814
+ "chunk_hard_stop_steps": [None, None],
815
  }
816
 
817
 
tests/test_inference_cleanup.py CHANGED
@@ -73,6 +73,8 @@ def test_closed_loop_pace_rerenders_once_from_untouched_model_waveform():
73
  "target_pace_speed": lambda *args, **kwargs: 0.90,
74
  "active_voiced_duration_seconds": active_duration,
75
  "active_pace_correction_speed": active_correction,
 
 
76
  "_apply_speed": apply_speed,
77
  "_NATIVE_STOP_POLICY": False,
78
  "_GENERATE_PARAMETERS": set(),
@@ -113,7 +115,14 @@ def test_closed_loop_pace_rerenders_once_from_untouched_model_waveform():
113
  assert apply_calls[0][1] == pytest.approx(0.90)
114
  assert apply_calls[1][1] == pytest.approx(0.90 * 0.95)
115
  assert all(call[2] is True for call in apply_calls)
116
- assert np.array_equal(output, np.ones(16, dtype=np.float32) * np.float32(0.855))
 
 
 
 
 
 
 
117
  assert len(active_calls) == 2
118
  assert np.array_equal(active_calls[0][0], np.ones(16, dtype=np.float32))
119
  assert np.array_equal(active_calls[1][0], np.ones(16, dtype=np.float32) * 0.90)
@@ -124,6 +133,84 @@ def test_closed_loop_pace_rerenders_once_from_untouched_model_waveform():
124
  }
125
 
126
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  def test_lazy_transition_f0_measures_only_dp_eligible_rows():
128
  observations = (
129
  CandidateObservation("第一段完整", "第一段完整", 2.0),
 
73
  "target_pace_speed": lambda *args, **kwargs: 0.90,
74
  "active_voiced_duration_seconds": active_duration,
75
  "active_pace_correction_speed": active_correction,
76
+ "endpoint_tail_energy_ratio": lambda audio, sample_rate: 0.5,
77
+ "_ChunkGenerationOutcome": SimpleNamespace,
78
  "_apply_speed": apply_speed,
79
  "_NATIVE_STOP_POLICY": False,
80
  "_GENERATE_PARAMETERS": set(),
 
115
  assert apply_calls[0][1] == pytest.approx(0.90)
116
  assert apply_calls[1][1] == pytest.approx(0.90 * 0.95)
117
  assert all(call[2] is True for call in apply_calls)
118
+ assert np.array_equal(
119
+ output.audio,
120
+ np.ones(16, dtype=np.float32) * np.float32(0.855),
121
+ )
122
+ assert output.stop_reason == "native_stop"
123
+ assert output.endpoint_energy_ratio == 0.5
124
+ assert output.generated_steps == 12
125
+ assert output.hard_stop_steps == 12
126
  assert len(active_calls) == 2
127
  assert np.array_equal(active_calls[0][0], np.ones(16, dtype=np.float32))
128
  assert np.array_equal(active_calls[1][0], np.ones(16, dtype=np.float32) * 0.90)
 
133
  }
134
 
135
 
136
+ def test_sparse_completion_policy_adds_only_bounded_one_two_unit_headroom():
137
+ def run(units, policy):
138
+ generation_calls = []
139
+ namespace = {
140
+ "np": np,
141
+ "torch": torch,
142
+ "model": SimpleNamespace(
143
+ generate=lambda **kwargs: (
144
+ generation_calls.append(kwargs) or torch.ones(64)
145
+ )
146
+ ),
147
+ "select_generation_cps": lambda *args, **kwargs: 5.0,
148
+ "count_network_endpoint_duration_units": lambda text: units,
149
+ "count_speech_units": lambda text: units,
150
+ "endpoint_generation_plan": (
151
+ lambda *args, **kwargs: ("短句。", 3, 4)
152
+ ),
153
+ "effective_generation_cfg": lambda text, cfg, **kwargs: cfg,
154
+ "set_generation_seed": lambda seed: None,
155
+ "target_pace_speed": lambda *args, **kwargs: 1.0,
156
+ "active_voiced_duration_seconds": (
157
+ lambda *args, **kwargs: (_ for _ in ()).throw(ValueError())
158
+ ),
159
+ "active_pace_correction_speed": lambda *args, **kwargs: 1.0,
160
+ "endpoint_tail_energy_ratio": lambda audio, sample_rate: 0.25,
161
+ "_apply_speed": lambda audio, speed, **kwargs: np.asarray(audio),
162
+ "_ChunkGenerationOutcome": SimpleNamespace,
163
+ "_NATIVE_STOP_POLICY": False,
164
+ "_GENERATE_PARAMETERS": set(),
165
+ "_STOP_CONTROLLER": None,
166
+ "SR": 48_000,
167
+ "STEP_SECONDS": 0.16,
168
+ "MIN_ENDPOINT_CUE_UNITS": 6,
169
+ "SHORT_TEXT_CFG_UNITS": 6,
170
+ "SHORT_TEXT_CFG_MIN": 3.0,
171
+ "TARGET_CPS": 4.0,
172
+ "ACTIVE_PACE_TARGET_CPS": 4.0,
173
+ "CLOSED_LOOP_ACTIVE_PACE_TARGET_CPS": 3.95,
174
+ "MIN_PACE_SPEED": 0.80,
175
+ "STOP_THRESHOLD": 0.50,
176
+ "STOP_CONSECUTIVE": 1,
177
+ }
178
+ generate = _isolated_app_function("_generate_chunk", namespace)
179
+ outcome = generate(
180
+ "短句",
181
+ torch.ones(4),
182
+ cfg=3.0,
183
+ steps=10,
184
+ request_seed=123,
185
+ policy=policy,
186
+ network_conditioned=True,
187
+ )
188
+ return generation_calls[0]["max_len"], outcome
189
+
190
+ base = SimpleNamespace(
191
+ name="base",
192
+ cjk_cps=5.2,
193
+ ascii_cps=4.6,
194
+ hard_stop_margin_steps=1,
195
+ short_headroom_max_units=0,
196
+ short_hard_stop_floor_steps=0,
197
+ )
198
+ completion = SimpleNamespace(
199
+ name="completion_headroom",
200
+ cjk_cps=4.2,
201
+ ascii_cps=3.6,
202
+ hard_stop_margin_steps=1,
203
+ short_headroom_max_units=2,
204
+ short_hard_stop_floor_steps=5,
205
+ )
206
+
207
+ assert run(2, base)[0] == 4
208
+ headroom_cap, headroom = run(2, completion)
209
+ assert headroom_cap == 5
210
+ assert headroom.hard_stop_steps == 5
211
+ assert run(3, completion)[0] == 4
212
+
213
+
214
  def test_lazy_transition_f0_measures_only_dp_eligible_rows():
215
  observations = (
216
  CandidateObservation("第一段完整", "第一段完整", 2.0),
tests/test_production.py CHANGED
@@ -20,7 +20,9 @@ from production import (
20
  count_network_endpoint_duration_units,
21
  count_speech_units,
22
  duration_hard_stop_steps,
 
23
  email_domain_mail_generation_variant,
 
24
  effective_generation_cfg,
25
  endpoint_generation_plan,
26
  ensure_terminal_punctuation,
@@ -39,6 +41,7 @@ from production import (
39
  normalize_tts_text,
40
  plan_generation_chunks,
41
  pcm16_audio_output,
 
42
  select_candidate_sequence,
43
  select_generation_cps,
44
  split_leading_clause,
@@ -834,6 +837,24 @@ def test_stop_controller_can_stop_on_first_confident_hit():
834
  assert decisions == [0, 0, 1]
835
 
836
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
837
  def test_stop_controller_relaxes_near_endpoint_and_enforces_hard_stop():
838
  relaxed = StopHysteresisController(
839
  _SequenceStopHead([0.6] * 10),
@@ -3234,12 +3255,25 @@ def test_pcm16_output_preserves_production_level_without_peak_normalizing():
3234
 
3235
  assert sample_rate == 48_000
3236
  assert pcm.dtype == np.int16
3237
- assert float(np.max(np.abs(pcm.astype(np.float64))) / 32767.0) == pytest.approx(
3238
  0.62,
3239
- abs=1.0 / 32767.0,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3240
  )
3241
- restored = pcm.astype(np.float64) / 32767.0
3242
- np.testing.assert_allclose(restored, waveform, atol=1.0 / 32767.0)
3243
 
3244
 
3245
  @pytest.mark.parametrize(
 
20
  count_network_endpoint_duration_units,
21
  count_speech_units,
22
  duration_hard_stop_steps,
23
+ decode_pcm16,
24
  email_domain_mail_generation_variant,
25
+ encode_pcm16,
26
  effective_generation_cfg,
27
  endpoint_generation_plan,
28
  ensure_terminal_punctuation,
 
41
  normalize_tts_text,
42
  plan_generation_chunks,
43
  pcm16_audio_output,
44
+ pcm16_verification_waveform,
45
  select_candidate_sequence,
46
  select_generation_cps,
47
  split_leading_clause,
 
837
  assert decisions == [0, 0, 1]
838
 
839
 
840
+ def test_stop_controller_preserves_threshold_reason_at_the_hard_cap():
841
+ controller = StopHysteresisController(
842
+ _SequenceStopHead([0.01, 0.01, 0.01, 0.9]),
843
+ threshold=0.50,
844
+ late_threshold=0.05,
845
+ consecutive=1,
846
+ )
847
+ controller.begin(min_len=2, expected_steps=3, hard_stop_steps=4)
848
+
849
+ decisions = [
850
+ controller(torch.zeros(1, 2)).argmax(dim=-1).item()
851
+ for _ in range(4)
852
+ ]
853
+
854
+ assert decisions == [0, 0, 0, 1]
855
+ assert controller.last_stop_reason == "stop_threshold"
856
+
857
+
858
  def test_stop_controller_relaxes_near_endpoint_and_enforces_hard_stop():
859
  relaxed = StopHysteresisController(
860
  _SequenceStopHead([0.6] * 10),
 
3255
 
3256
  assert sample_rate == 48_000
3257
  assert pcm.dtype == np.int16
3258
+ assert float(np.max(np.abs(pcm.astype(np.float64))) / 32768.0) == pytest.approx(
3259
  0.62,
3260
+ abs=1.0 / 32768.0,
3261
+ )
3262
+ restored = decode_pcm16(pcm)
3263
+ np.testing.assert_allclose(restored, waveform, atol=1.0 / 32768.0)
3264
+
3265
+
3266
+ def test_pcm16_verification_roundtrip_is_exhaustively_idempotent():
3267
+ codes = np.arange(-32768, 32768, dtype=np.int32).astype(np.int16)
3268
+
3269
+ decoded = decode_pcm16(codes)
3270
+ reencoded = encode_pcm16(decoded)
3271
+
3272
+ np.testing.assert_array_equal(reencoded, codes)
3273
+ np.testing.assert_array_equal(
3274
+ encode_pcm16(pcm16_verification_waveform(decoded)),
3275
+ codes,
3276
  )
 
 
3277
 
3278
 
3279
  @pytest.mark.parametrize(
tests/test_quality_runtime.py CHANGED
@@ -19,6 +19,10 @@ from quality_runtime import (
19
  COMPLETION_HEADROOM_GENERATION_POLICY,
20
  CASCADE_EVIDENCE_LOG_PREFIX,
21
  CASCADE_EVIDENCE_SCHEMA_VERSION,
 
 
 
 
22
  SAFE_DURATION_GENERATION_POLICY,
23
  SQUIM_OBJECTIVE_ASSET_PATH,
24
  SQUIM_OBJECTIVE_SAMPLE_RATE,
@@ -51,9 +55,11 @@ from quality_runtime import (
51
  active_voiced_duration_seconds,
52
  candidate_gate_evidence,
53
  candidate_chunk_transition_score,
 
54
  candidate_limit_for_chunk_budget,
55
  cosine_similarity,
56
  exact_waveform_sha256,
 
57
  format_cascade_evidence_log,
58
  generation_cfg_for_candidate_offset,
59
  generation_policy_for_candidate_offset,
@@ -295,11 +301,20 @@ def test_candidate_generation_policy_mapping_uses_sparse_completion_headroom():
295
  assert ADAPTIVE_CASCADE_STAGE_LIMITS == (1, 5, 10, 15, 20, 24, 28, 32)
296
  base = generation_policy_for_candidate_offset(0)
297
  assert base is BASE_GENERATION_POLICY
298
- assert (base.name, base.cjk_cps, base.ascii_cps, base.hard_stop_margin_steps) == (
 
 
 
 
 
 
 
299
  "base",
300
  5.2,
301
  4.6,
302
  1,
 
 
303
  )
304
 
305
  for offset in (1, 2, 5, 9):
@@ -310,9 +325,11 @@ def test_candidate_generation_policy_mapping_uses_sparse_completion_headroom():
310
  safe.cjk_cps,
311
  safe.ascii_cps,
312
  safe.hard_stop_margin_steps,
313
- ) == ("safe_duration", 4.6, 4.0, 1)
 
 
314
 
315
- for offset in (4, 8, 12, 16):
316
  headroom = generation_policy_for_candidate_offset(offset)
317
  assert headroom is COMPLETION_HEADROOM_GENERATION_POLICY
318
  assert (
@@ -320,7 +337,54 @@ def test_candidate_generation_policy_mapping_uses_sparse_completion_headroom():
320
  headroom.cjk_cps,
321
  headroom.ascii_cps,
322
  headroom.hard_stop_margin_steps,
323
- ) == ("completion_headroom", 4.2, 3.6, 1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324
 
325
 
326
  @pytest.mark.parametrize("offset", [-1, 0.5, 1.0, True, None, "one"])
@@ -1675,7 +1739,7 @@ def test_canonical_attempt_evidence_distinguishes_local_v3_pass_and_not_run():
1675
  )
1676
  attempt = payload["attempts"][0]
1677
 
1678
- assert payload["schema_version"] == 5
1679
  assert attempt["independent_local_evidence_complete"] is True
1680
  assert attempt["independent_local_results"] == [
1681
  {
 
19
  COMPLETION_HEADROOM_GENERATION_POLICY,
20
  CASCADE_EVIDENCE_LOG_PREFIX,
21
  CASCADE_EVIDENCE_SCHEMA_VERSION,
22
+ ENDPOINT_ENERGY_WEIGHT,
23
+ ENDPOINT_HARD_STOP_PENALTY,
24
+ ENDPOINT_PREFERRED_SQUIM_PESQ_SLACK,
25
+ ENDPOINT_PREFERRED_SQUIM_STOI_SLACK,
26
  SAFE_DURATION_GENERATION_POLICY,
27
  SQUIM_OBJECTIVE_ASSET_PATH,
28
  SQUIM_OBJECTIVE_SAMPLE_RATE,
 
55
  active_voiced_duration_seconds,
56
  candidate_gate_evidence,
57
  candidate_chunk_transition_score,
58
+ candidate_endpoint_selection_cost,
59
  candidate_limit_for_chunk_budget,
60
  cosine_similarity,
61
  exact_waveform_sha256,
62
+ endpoint_tail_energy_ratio,
63
  format_cascade_evidence_log,
64
  generation_cfg_for_candidate_offset,
65
  generation_policy_for_candidate_offset,
 
301
  assert ADAPTIVE_CASCADE_STAGE_LIMITS == (1, 5, 10, 15, 20, 24, 28, 32)
302
  base = generation_policy_for_candidate_offset(0)
303
  assert base is BASE_GENERATION_POLICY
304
+ assert (
305
+ base.name,
306
+ base.cjk_cps,
307
+ base.ascii_cps,
308
+ base.hard_stop_margin_steps,
309
+ base.short_headroom_max_units,
310
+ base.short_hard_stop_floor_steps,
311
+ ) == (
312
  "base",
313
  5.2,
314
  4.6,
315
  1,
316
+ 0,
317
+ 0,
318
  )
319
 
320
  for offset in (1, 2, 5, 9):
 
325
  safe.cjk_cps,
326
  safe.ascii_cps,
327
  safe.hard_stop_margin_steps,
328
+ safe.short_headroom_max_units,
329
+ safe.short_hard_stop_floor_steps,
330
+ ) == ("safe_duration", 4.6, 4.0, 1, 0, 0)
331
 
332
+ for offset in (4, 8, 12, 16, 20, 24, 28):
333
  headroom = generation_policy_for_candidate_offset(offset)
334
  assert headroom is COMPLETION_HEADROOM_GENERATION_POLICY
335
  assert (
 
337
  headroom.cjk_cps,
338
  headroom.ascii_cps,
339
  headroom.hard_stop_margin_steps,
340
+ headroom.short_headroom_max_units,
341
+ headroom.short_hard_stop_floor_steps,
342
+ ) == ("completion_headroom", 4.2, 3.6, 1, 2, 5)
343
+
344
+
345
+ def test_endpoint_tail_energy_and_selection_cost_prefer_natural_quiet_endings():
346
+ waveform = np.concatenate(
347
+ (
348
+ np.ones(950, dtype=np.float32),
349
+ np.full(50, 0.25, dtype=np.float32),
350
+ )
351
+ )
352
+ energy = endpoint_tail_energy_ratio(
353
+ waveform,
354
+ 10_000,
355
+ window_ms=5.0,
356
+ )
357
+ threshold = ChunkCandidateArtifact(
358
+ stop_reason="stop_threshold",
359
+ endpoint_energy_ratio=energy,
360
+ generated_steps=4,
361
+ hard_stop_steps=5,
362
+ )
363
+ threshold_at_cap = ChunkCandidateArtifact(
364
+ stop_reason="stop_threshold",
365
+ endpoint_energy_ratio=energy,
366
+ generated_steps=5,
367
+ hard_stop_steps=5,
368
+ )
369
+ forced = ChunkCandidateArtifact(
370
+ stop_reason="hard_stop",
371
+ endpoint_energy_ratio=energy,
372
+ generated_steps=5,
373
+ hard_stop_steps=5,
374
+ )
375
+
376
+ assert energy == pytest.approx(0.25)
377
+ assert candidate_endpoint_selection_cost(threshold) == pytest.approx(
378
+ ENDPOINT_ENERGY_WEIGHT * 0.25
379
+ )
380
+ assert candidate_endpoint_selection_cost(threshold_at_cap) == pytest.approx(
381
+ ENDPOINT_HARD_STOP_PENALTY + ENDPOINT_ENERGY_WEIGHT * 0.25
382
+ )
383
+ assert candidate_endpoint_selection_cost(forced) == pytest.approx(
384
+ ENDPOINT_HARD_STOP_PENALTY + ENDPOINT_ENERGY_WEIGHT * 0.25
385
+ )
386
+ assert ENDPOINT_PREFERRED_SQUIM_STOI_SLACK == pytest.approx(0.02)
387
+ assert ENDPOINT_PREFERRED_SQUIM_PESQ_SLACK == pytest.approx(0.03)
388
 
389
 
390
  @pytest.mark.parametrize("offset", [-1, 0.5, 1.0, True, None, "one"])
 
1739
  )
1740
  attempt = payload["attempts"][0]
1741
 
1742
+ assert payload["schema_version"] == 6
1743
  assert attempt["independent_local_evidence_complete"] is True
1744
  assert attempt["independent_local_results"] == [
1745
  {
tests/test_release_pins.py CHANGED
@@ -12,6 +12,7 @@ from production import (
12
  join_audio_chunks_variable,
13
  match_chunk_rms,
14
  normalize_spoken_forms,
 
15
  plan_generation_chunks,
16
  punctuation_pause_seconds,
17
  )
@@ -103,6 +104,7 @@ def _isolated_assemble_trajectory_audio():
103
  "NETWORK_INTERNAL_FADE_MS": constants["NETWORK_INTERNAL_FADE_MS"],
104
  "CHUNK_EDGE_FADE_MS": constants["CHUNK_EDGE_FADE_MS"],
105
  "CROSSFADE_MS": constants["CROSSFADE_MS"],
 
106
  "match_chunk_rms": match_chunk_rms,
107
  "punctuation_pause_seconds": punctuation_pause_seconds,
108
  "fade_variable_internal_edges": fade_variable_internal_edges,
@@ -111,6 +113,7 @@ def _isolated_assemble_trajectory_audio():
111
  "_apply_speed": lambda waveform, _speed: waveform,
112
  "count_speech_units": count_speech_units,
113
  "finish_audio": lambda waveform, _sample_rate, **_kwargs: waveform,
 
114
  }
115
  exec(compile(module, str(app_path), "exec"), namespace)
116
  return namespace["_assemble_trajectory_audio"]
@@ -363,6 +366,18 @@ def test_app_wires_row_local_candidate_ordinal_to_generation_policy_and_logs_it(
363
  assert "effective_cfg={effective_cfg:.2f}" in source
364
  assert "network_floor_applied={network_floor_applied}" in source
365
  assert "short_floor_applied={short_floor_applied}" in source
 
 
 
 
 
 
 
 
 
 
 
 
366
 
367
 
368
  def test_app_rejects_ambiguous_iri_before_frontend_normalization():
@@ -646,7 +661,7 @@ def test_network_local_dual_asr_capability_is_range_bound_for_initial_and_refill
646
  assert "chunk_artifacts=primary_verification.chunk_artifacts" in (
647
  intersection_source
648
  )
649
- assert "CASCADE_EVIDENCE_SCHEMA_VERSION = 5" in quality_source
650
  assert '"chunk_text_variants"' in quality_source
651
  assert "local_candidate_has_coverage_eligibility(" in helper_source
652
  assert "independent_local_results=" in initial_source
@@ -861,15 +876,14 @@ def test_app_reverifies_the_post_join_speed_adjusted_whole_waveform():
861
  speed_index = assemble_source.index(
862
  "waveform = _apply_speed(waveform, playback_speed)"
863
  )
864
- finish_index = assemble_source.index(
865
- "return finish_audio(waveform, SR, fade_ms=finish_fade_ms)"
866
- )
867
- assert speed_index < finish_index
868
- assert (
869
- 'finish_fade_ms = 0.0 if count_speech_units("".join(chunks)) <= 6 else 5.0'
870
- in assemble_source
871
  )
872
- assert "else 60.0" not in assemble_source
 
 
 
873
  production_source = (ROOT / "production.py").read_text(encoding="utf-8")
874
  assert "trailing_silence_ms: float = 180.0" in production_source
875
  assemble_index = synthesize_source.index(
@@ -951,7 +965,7 @@ def test_chunk_generation_closed_loop_rerenders_final_audio_from_raw_once():
951
  assert "fallback_speed = final_speed * fallback_residual" in generate_source
952
  assert "_apply_speed(\n corrected" not in generate_source
953
  assert "_apply_speed(\n audio,\n final_speed" in generate_source
954
- assert "_apply_speed(\n audio,\n fallback_speed" in generate_source
955
  assert "PACE_STRETCH_N_FFT = 1536" in source
956
  assert "PACE_STRETCH_HOP_LENGTH = 384" in source
957
  assert "NETWORK_PACE_STRETCH_N_FFT = 2048" in source
@@ -962,7 +976,7 @@ def test_chunk_generation_closed_loop_rerenders_final_audio_from_raw_once():
962
  assert "hop_length=hop_length" in apply_speed_source
963
 
964
 
965
- def test_public_tts_wrappers_serialize_pcm16_after_float_verification():
966
  source = (ROOT / "app.py").read_text(encoding="utf-8")
967
  tree = ast.parse(source)
968
  functions = {
@@ -971,8 +985,14 @@ def test_public_tts_wrappers_serialize_pcm16_after_float_verification():
971
  if isinstance(node, ast.FunctionDef)
972
  }
973
  synthesize_source = ast.get_source_segment(source, functions["_synthesize"])
 
 
 
 
974
 
975
  assert synthesize_source is not None
 
 
976
  assert "pcm16_audio_output" not in synthesize_source
977
  assert "return SR, waveform" in synthesize_source
978
  for wrapper_name in ("tts_speaker", "tts_reference", "tts_longform"):
 
12
  join_audio_chunks_variable,
13
  match_chunk_rms,
14
  normalize_spoken_forms,
15
+ pcm16_verification_waveform,
16
  plan_generation_chunks,
17
  punctuation_pause_seconds,
18
  )
 
104
  "NETWORK_INTERNAL_FADE_MS": constants["NETWORK_INTERNAL_FADE_MS"],
105
  "CHUNK_EDGE_FADE_MS": constants["CHUNK_EDGE_FADE_MS"],
106
  "CROSSFADE_MS": constants["CROSSFADE_MS"],
107
+ "FINAL_ENDPOINT_FADE_MS": constants["FINAL_ENDPOINT_FADE_MS"],
108
  "match_chunk_rms": match_chunk_rms,
109
  "punctuation_pause_seconds": punctuation_pause_seconds,
110
  "fade_variable_internal_edges": fade_variable_internal_edges,
 
113
  "_apply_speed": lambda waveform, _speed: waveform,
114
  "count_speech_units": count_speech_units,
115
  "finish_audio": lambda waveform, _sample_rate, **_kwargs: waveform,
116
+ "pcm16_verification_waveform": pcm16_verification_waveform,
117
  }
118
  exec(compile(module, str(app_path), "exec"), namespace)
119
  return namespace["_assemble_trajectory_audio"]
 
366
  assert "effective_cfg={effective_cfg:.2f}" in source
367
  assert "network_floor_applied={network_floor_applied}" in source
368
  assert "short_floor_applied={short_floor_applied}" in source
369
+ assert "short_headroom_floor_applied={short_headroom_floor_applied}" in source
370
+ assert "generation_endpoint_evidence_by_seed" in source
371
+ assert "chunk_stop_reasons=tuple(" in source
372
+ assert "chunk_endpoint_energy_ratios=tuple(" in source
373
+ assert "require_endpoint_evidence=True" in source
374
+ quality_source = (ROOT / "quality_runtime.py").read_text(encoding="utf-8")
375
+ assert "short_headroom_max_units=2" in quality_source
376
+ assert "short_hard_stop_floor_steps=5" in quality_source
377
+ assert "ENDPOINT_HARD_STOP_PENALTY = 0.05" in quality_source
378
+ assert "ENDPOINT_ENERGY_WEIGHT = 0.02" in quality_source
379
+ assert "ENDPOINT_PREFERRED_SQUIM_STOI_SLACK = 0.02" in quality_source
380
+ assert "ENDPOINT_PREFERRED_SQUIM_PESQ_SLACK = 0.03" in quality_source
381
 
382
 
383
  def test_app_rejects_ambiguous_iri_before_frontend_normalization():
 
661
  assert "chunk_artifacts=primary_verification.chunk_artifacts" in (
662
  intersection_source
663
  )
664
+ assert "CASCADE_EVIDENCE_SCHEMA_VERSION = 6" in quality_source
665
  assert '"chunk_text_variants"' in quality_source
666
  assert "local_candidate_has_coverage_eligibility(" in helper_source
667
  assert "independent_local_results=" in initial_source
 
876
  speed_index = assemble_source.index(
877
  "waveform = _apply_speed(waveform, playback_speed)"
878
  )
879
+ finish_index = assemble_source.index("waveform = finish_audio(")
880
+ pcm_index = assemble_source.index(
881
+ "return pcm16_verification_waveform(waveform)"
 
 
 
 
882
  )
883
+ assert speed_index < finish_index < pcm_index
884
+ assert "fade_ms=FINAL_ENDPOINT_FADE_MS" in assemble_source
885
+ assert "FINAL_ENDPOINT_FADE_MS = 5.0" in source
886
+ assert "finish_fade_ms" not in assemble_source
887
  production_source = (ROOT / "production.py").read_text(encoding="utf-8")
888
  assert "trailing_silence_ms: float = 180.0" in production_source
889
  assemble_index = synthesize_source.index(
 
965
  assert "fallback_speed = final_speed * fallback_residual" in generate_source
966
  assert "_apply_speed(\n corrected" not in generate_source
967
  assert "_apply_speed(\n audio,\n final_speed" in generate_source
968
+ assert "audio,\n fallback_speed" in generate_source
969
  assert "PACE_STRETCH_N_FFT = 1536" in source
970
  assert "PACE_STRETCH_HOP_LENGTH = 384" in source
971
  assert "NETWORK_PACE_STRETCH_N_FFT = 2048" in source
 
976
  assert "hop_length=hop_length" in apply_speed_source
977
 
978
 
979
+ def test_public_tts_wrappers_serialize_the_same_pcm16_grid_used_for_verification():
980
  source = (ROOT / "app.py").read_text(encoding="utf-8")
981
  tree = ast.parse(source)
982
  functions = {
 
985
  if isinstance(node, ast.FunctionDef)
986
  }
987
  synthesize_source = ast.get_source_segment(source, functions["_synthesize"])
988
+ assemble_source = ast.get_source_segment(
989
+ source,
990
+ functions["_assemble_trajectory_audio"],
991
+ )
992
 
993
  assert synthesize_source is not None
994
+ assert assemble_source is not None
995
+ assert "return pcm16_verification_waveform(waveform)" in assemble_source
996
  assert "pcm16_audio_output" not in synthesize_source
997
  assert "return SR, waveform" in synthesize_source
998
  for wrapper_name in ("tts_speaker", "tts_reference", "tts_longform"):