⏱️ Prerequisite for boundary-fit selection (companion issue): when the Orchestrator plans upcoming items, the next break's patter has no known duration — the LLM copy isn't written and the TTS isn't rendered at pick time. Measured duration exists only post-render (TtsSegmentSource stamps DurationMs from the cue analyzer, F66.1 — measured, never fabricated).
Build an estimation seam (e.g. IPatterDurationEstimator) the planner can consult, with honest tiers:
- Already-rendered (render-ahead cache hit): use the real measured
DurationMs — exact.
- Historical average: the Booth log holds 14 days of aired patter with durations — a per-persona × per-SegmentKind rolling average is cheap and self-improving.
- Cold fallback: chars-per-second heuristic per voice (
Llm:MaxCopyChars bounds the worst case).
The estimate's confidence tier should ride along so the consumer can widen its tolerance accordingly. No behavior change by itself — this only exposes numbers.
⏱️ Prerequisite for boundary-fit selection (companion issue): when the Orchestrator plans upcoming items, the next break's patter has no known duration — the LLM copy isn't written and the TTS isn't rendered at pick time. Measured duration exists only post-render (
TtsSegmentSourcestampsDurationMsfrom the cue analyzer, F66.1 — measured, never fabricated).Build an estimation seam (e.g.
IPatterDurationEstimator) the planner can consult, with honest tiers:DurationMs— exact.Llm:MaxCopyCharsbounds the worst case).The estimate's confidence tier should ride along so the consumer can widen its tolerance accordingly. No behavior change by itself — this only exposes numbers.