You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Update the TTS eval bench (skills/tts-eval/bench.py) for what #201 changed in the renderer: its direction probe should exercise per-line direction over a clone (a lines scene whose one line carries instruct), not only the episode-level voice_instruct path, and its events probe should report that an engine without events never received the markers (they are stripped before the render) instead of a bare markers heard: none that reads as "performed".
Context
#201 made render.py consume the events and direction capabilities: on an engine without events the renderer strips (laugh) / (sigh) from every take before the model sees it, and a scene line may carry instruct, rendered through Breeze's clone-plus-instruct form and folded into the take's cache key. The bench renders only through render.validate_manifest / render.render_segments (the invariant in CLAUDE.md), so two of its probes now measure something different from what they were written for:
The events probe on the control (qwen3) measures a marker-stripped take: WER 0, markers_heard: []. tests/test_tts_eval.py::test_bench_renders_candidate_and_control_and_writes_both_artifacts already asserts that per engine, but the ledger row and the HTML report present it the same way as a candidate that performed the markers. A reader comparing engines cannot tell "performed" from "never handed them".
The direction probe goes through voice_instruct (design mode on a plain segment), which skills/tts-eval/SKILL.md line 28 explicitly says is a stand-in until Gate vocal events and per-line voice direction on the engine's capabilities #201 lands. The identity drift that motivates st_write.MAX_DIRECTED_LINES_PER_SCENE = 1 (Ethan 93 → 183 Hz, similarity 0.96 → 0.88 in the 2026-09-04 eval) needs to be measured on the form a show actually uses: a cast clone with instruct, compared against the same clip undirected.
Pointers
skills/tts-eval/bench.py — TAKE_KINDS, strip_events, the events/direction entries in the corpus expansion (~line 195-235), markers_heard in the per-take rows (~line 674-723) and the report (~line 951, ~line 1005).
skills/tts-eval/corpus.json — the events and direction entries (append-only; a changed line makes earlier ledger entries incomparable).
skills/tts-eval/SKILL.md — the probe table and the metrics table, both pinned to bench.METRICS / the corpus by tests/test_tts_eval.py drift tests.
skills/daily-podcast/render.py — EVENT_MARKERS, strip_event_markers, _validate_engine_capabilities (the per-line instruct refusal), _generate_breeze (the clone-plus-instruct form), _segment_cache_key(instruct=).
skills/surface-tension/st_write.py — DIRECTIONS (word → instruct phrase) and lines_for_engine; the probe should direct with a phrase from that table so the bench measures what the show would ship.
The bench keeps rendering through the registry only (test_bench_never_calls_mlx_audio_directly stays green).
The corpus stays append-only and under every finite max_take_chars in render.ENGINES; adding a directed variant of an existing line is fine, changing a line is not.
On an engine without direction the per-line probe is skipped and the report says so (the existing posture for an engine without design).
Ledger entries written before this change must still parse; a new field is added, never renamed.
Acceptance criteria
The events probe row and report cell distinguish "performed" (engine has events, markers absent from the transcript) from "stripped before the render" (engine lacks events), and the daily-skill metric name for it is pinned by the existing drift test.
The direction probe renders a clone line with instruct (a DIRECTIONS phrase) through render.render_segments and reports its pitch/similarity against the same line undirected.
Task
Update the TTS eval bench (
skills/tts-eval/bench.py) for what #201 changed in the renderer: its direction probe should exercise per-line direction over a clone (alinesscene whose one line carriesinstruct), not only the episode-levelvoice_instructpath, and its events probe should report that an engine withouteventsnever received the markers (they are stripped before the render) instead of a baremarkers heard: nonethat reads as "performed".Context
#201 made
render.pyconsume theeventsanddirectioncapabilities: on an engine withouteventsthe renderer strips(laugh)/(sigh)from every take before the model sees it, and a scene line may carryinstruct, rendered through Breeze's clone-plus-instruct form and folded into the take's cache key. The bench renders only throughrender.validate_manifest/render.render_segments(the invariant in CLAUDE.md), so two of its probes now measure something different from what they were written for:qwen3) measures a marker-stripped take: WER 0,markers_heard: [].tests/test_tts_eval.py::test_bench_renders_candidate_and_control_and_writes_both_artifactsalready asserts that per engine, but the ledger row and the HTML report present it the same way as a candidate that performed the markers. A reader comparing engines cannot tell "performed" from "never handed them".voice_instruct(design mode on a plain segment), whichskills/tts-eval/SKILL.mdline 28 explicitly says is a stand-in until Gate vocal events and per-line voice direction on the engine's capabilities #201 lands. The identity drift that motivatesst_write.MAX_DIRECTED_LINES_PER_SCENE = 1(Ethan 93 → 183 Hz, similarity 0.96 → 0.88 in the 2026-09-04 eval) needs to be measured on the form a show actually uses: a cast clone withinstruct, compared against the same clip undirected.Pointers
skills/tts-eval/bench.py—TAKE_KINDS,strip_events, the events/direction entries in the corpus expansion (~line 195-235),markers_heardin the per-take rows (~line 674-723) and the report (~line 951, ~line 1005).skills/tts-eval/corpus.json— theeventsanddirectionentries (append-only; a changed line makes earlier ledger entries incomparable).skills/tts-eval/SKILL.md— the probe table and the metrics table, both pinned tobench.METRICS/ the corpus bytests/test_tts_eval.pydrift tests.skills/daily-podcast/render.py—EVENT_MARKERS,strip_event_markers,_validate_engine_capabilities(the per-lineinstructrefusal),_generate_breeze(the clone-plus-instruct form),_segment_cache_key(instruct=).skills/surface-tension/st_write.py—DIRECTIONS(word → instruct phrase) andlines_for_engine; the probe should direct with a phrase from that table so the bench measures what the show would ship.tests/test_tts_eval.py— the per-engine events assertion added in Gate vocal events and per-line voice direction on the engine's capabilities #201's PR, and the fake engine/analyzers the bench tests run on.Constraints
test_bench_never_calls_mlx_audio_directlystays green).max_take_charsinrender.ENGINES; adding a directed variant of an existing line is fine, changing a line is not.directionthe per-line probe is skipped and the report says so (the existing posture for an engine withoutdesign).Acceptance criteria
events, markers absent from the transcript) from "stripped before the render" (engine lacksevents), and the daily-skill metric name for it is pinned by the existing drift test.instruct(aDIRECTIONSphrase) throughrender.render_segmentsand reports its pitch/similarity against the same line undirected.skills/tts-eval/SKILL.mdno longer says the direction probe waits on Gate vocal events and per-line voice direction on the engine's capabilities #201.pytestand both ruff gates pass.Out of scope
render.pystrips or refuses; that contract is Gate vocal events and per-line voice direction on the engine's capabilities #201's.Cross-references
Generated by Claude Code.