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
The first phase where a model runs. qwen-1.7b goes first because it has the most recorded
evidence, the cheapest runs, and no native anything, so it forces every derived path — five of
the seven roles, and the two exit codes only run can return.
Scope
transport.py, orchestrator.py, the decode, silero, diarizer, qwen and aligner
adapters with their stage scripts, and audio transcribe run for qwen-1.7b and qwen-0.6b.
Transport
One fresh subprocess per stage, chosen per environment, request JSON in and result JSON out, exit
code as the signal, progress on stderr. ENVIRONMENTS.md settles this, and the
recorded end-to-end measurement is what it describes
(model_tests/benchmark/run_interview_pipeline.py:175, "strictly sequential fresh subprocesses").
Environment
How a stage runs
core
in-process SileroOnnxVad. A declared exception: a 2.3 MB hash-pinned ONNX file in the tool's own environment, already normalized to SpeechRegion, with no model object to leak. Normalization here is by code, not by construction.
Stage scripts ship in the wheel, are passed by absolute path, and import no audio_cli —
installing it into a provisioned environment would drag onnxruntime and a conflicting numpy into
each one.
Adapters run in core, over the stage's raw JSON. The stage emits the backend's own JSON-safe
shape minus anything unbounded (FluidAudio's 256-float per-segment embeddings are dropped at the
boundary); normalization happens in the tool. That is what lets every adapter test run against the
recorded artifacts with no provisioned environment. The floor is still structural: no
model-specific object can cross a process boundary.
Decode
One canonical render per run — ffmpeg -ac 1 -ar 16000 -c:a pcm_s16le to a temp file every later
stage reads. The source is never modified.
ASR
_generate_chunks_batched for both the diarized and the fixed-chunk case: one declared api_path, and it is the only path that reports per-unit completion, without which failure_recovery: per_unit and exit 4 are not implementable. The public generate() chunks
internally and reports nothing per unit. The two paths agree on every word and differ by two
Chinese commas, so the choice is declared rather than hidden.
max_tokens is declared configuration, not a constant nobody notices: it is the exit-4
trigger. The 60-minute stress run consumed 10,169 of 16,384 tokens, so at that rate the budget
exhausts near 1.6 hours of comparable audio.
The language English<asr_text> scaffold is stripped unconditionally via extract_language
(qwen3_asr.py:899). It is only reachable with no language hint: the batched path leaks it at language=None (run_qwen_verbatim_probe.py:545,553-558) and does not leak it in 0 of 195
segments with a hint (mlx_qwen3_asr_1.7b_8bit_fluidaudio_turns_spice30m_mix_batch1_clearcache.json),
so a test written against the hinted configuration passes vacuously.
Aligner
Per segment: clip, text, and a language that selects a tokenizer, with bounds re-offset onto the
source timeline. --languagedoes not reach it. qwen3_forced_aligner.py:256-266 branches on japanese, korean, chinese, and everything else to tokenize_space_lang, while its checkpoint
declares Cantonese as supported — so passing Cantonese through would space-split CJK into one
"word" per segment and silently degenerate word_timestamps, on the exact configuration every
recorded Cantonese figure used. roles.aligner.config.language_rule declares the recorded CJK rule
verbatim (run_mlx_forced_aligner_probe.py:55,94), which is what produced the 246 token-identical
alignments.
Diarizer
fluidaudiocli process --mode offline with the five values the measured runs passed, plus batch_size, and --overlapping-segmentsonly when overlapped_speech is requested. No --num-speakers: the offline options are "all optional" and the diarizer estimates. Both cited
figures came from the opposite settings, which the catalog notes now say (phase 0).
The turn reconciliation is deterministic glue, not a role: an exact partition of the timeline, with
the three thresholds from run_turn_attributed_mlx_asr.py:78-84 and the abstention ledger they
produce.
Partial results and resume
Exit 4 writes a conforming document with complete: false and a coverage ledger. --range resumes
against the original input and re-decodes and re-diarizes the whole file, then transcribes only
units intersecting the range. That is not belt-and-braces: three separate runs of the 30-minute
fixture, two weeks apart, produced identical normalized_output_sha256 (3b6639…, 589 segments),
while the same 30 minutes in two positions of a 60-minute concat produced 588 against 549
intervals. Whole-file reproduces the partition and the anonymous labels exactly, so the two results
merge; range-only would not.
Out of scope
firered, vibevoice, export.
Acceptance
A real run's provenance key set equals its plan's sample_output key set, parametrized
over the derivation table, compared against the real embedded plan and not the elided print.
Exit 3 before pull, with the missing payload and the pull line as its fix.
Exit 4 on a budget forced low enough to truncate, writing a document that satisfies every
floor, whose covered_intervals and missing_intervals partition the source exactly.
A resumed run's turn bounds equal the first run's for the units they share, and its speaker
labels agree.
The scaffold strip is asserted on the no-hint configuration, and the assertion fails when
the strip is removed.
peak_rss_bytes is the maximum of the per-stage peaks; the sum never appears.
No "N/A", no 0.0 synthesized bound, no key for an unrequested capability, in real output.
A stage double can represent a truncated run and an exhausted budget — a double that cannot
reach the state under test makes the test pass without the code running, which has happened here
twice.
uv run --extra dev pytest green, and the deterministic render-from-original enhance flow
is not regressed.
Depends on
#20 — run executes a plan, so the planner comes first.
#11 — nothing here runs end to end without audio packages pull.
Context
Decomposes #12, phase C of
TRANSCRIBE_IMPLEMENTATION_PLAN.md.
The first phase where a model runs.
qwen-1.7bgoes first because it has the most recordedevidence, the cheapest runs, and no native anything, so it forces every derived path — five of
the seven roles, and the two exit codes only
runcan return.Scope
transport.py,orchestrator.py, thedecode,silero,diarizer,qwenandaligneradapters with their stage scripts, and
audio transcribe runforqwen-1.7bandqwen-0.6b.Transport
One fresh subprocess per stage, chosen per environment, request JSON in and result JSON out, exit
code as the signal, progress on stderr. ENVIRONMENTS.md settles this, and the
recorded end-to-end measurement is what it describes
(
model_tests/benchmark/run_interview_pipeline.py:175, "strictly sequential fresh subprocesses").coreSileroOnnxVad. A declared exception: a 2.3 MB hash-pinned ONNX file in the tool's own environment, already normalized toSpeechRegion, with no model object to leak. Normalization here is by code, not by construction.mlx<root>/envs/mlx/bin/python <stage script> <request> <result>swiftStage scripts ship in the wheel, are passed by absolute path, and import no
audio_cli—installing it into a provisioned environment would drag onnxruntime and a conflicting numpy into
each one.
Adapters run in
core, over the stage's raw JSON. The stage emits the backend's own JSON-safeshape minus anything unbounded (FluidAudio's 256-float per-segment embeddings are dropped at the
boundary); normalization happens in the tool. That is what lets every adapter test run against the
recorded artifacts with no provisioned environment. The floor is still structural: no
model-specific object can cross a process boundary.
Decode
One canonical render per run —
ffmpeg -ac 1 -ar 16000 -c:a pcm_s16leto a temp file every laterstage reads. The source is never modified.
ASR
_generate_chunks_batchedfor both the diarized and the fixed-chunk case: one declaredapi_path, and it is the only path that reports per-unit completion, without whichfailure_recovery: per_unitand exit 4 are not implementable. The publicgenerate()chunksinternally and reports nothing per unit. The two paths agree on every word and differ by two
Chinese commas, so the choice is declared rather than hidden.
max_tokensis declared configuration, not a constant nobody notices: it is the exit-4trigger. The 60-minute stress run consumed 10,169 of 16,384 tokens, so at that rate the budget
exhausts near 1.6 hours of comparable audio.
The
language English<asr_text>scaffold is stripped unconditionally viaextract_language(
qwen3_asr.py:899). It is only reachable with no language hint: the batched path leaks it atlanguage=None(run_qwen_verbatim_probe.py:545,553-558) and does not leak it in 0 of 195segments with a hint (
mlx_qwen3_asr_1.7b_8bit_fluidaudio_turns_spice30m_mix_batch1_clearcache.json),so a test written against the hinted configuration passes vacuously.
Aligner
Per segment: clip, text, and a language that selects a tokenizer, with bounds re-offset onto the
source timeline.
--languagedoes not reach it.qwen3_forced_aligner.py:256-266branches onjapanese,korean,chinese, and everything else totokenize_space_lang, while its checkpointdeclares
Cantoneseas supported — so passingCantonesethrough would space-split CJK into one"word" per segment and silently degenerate
word_timestamps, on the exact configuration everyrecorded Cantonese figure used.
roles.aligner.config.language_ruledeclares the recorded CJK ruleverbatim (
run_mlx_forced_aligner_probe.py:55,94), which is what produced the 246 token-identicalalignments.
Diarizer
fluidaudiocli process --mode offlinewith the five values the measured runs passed, plusbatch_size, and--overlapping-segmentsonly whenoverlapped_speechis requested. No--num-speakers: the offline options are "all optional" and the diarizer estimates. Both citedfigures came from the opposite settings, which the catalog notes now say (phase 0).
The turn reconciliation is deterministic glue, not a role: an exact partition of the timeline, with
the three thresholds from
run_turn_attributed_mlx_asr.py:78-84and the abstention ledger theyproduce.
Partial results and resume
Exit 4 writes a conforming document with
complete: falseand a coverage ledger.--rangeresumesagainst the original input and re-decodes and re-diarizes the whole file, then transcribes only
units intersecting the range. That is not belt-and-braces: three separate runs of the 30-minute
fixture, two weeks apart, produced identical
normalized_output_sha256(3b6639…, 589 segments),while the same 30 minutes in two positions of a 60-minute concat produced 588 against 549
intervals. Whole-file reproduces the partition and the anonymous labels exactly, so the two results
merge; range-only would not.
Out of scope
firered,vibevoice,export.Acceptance
provenancekey set equals its plan'ssample_outputkey set, parametrizedover the derivation table, compared against the real embedded plan and not the elided print.
pull, with themissingpayload and thepullline as itsfix.floor, whose
covered_intervalsandmissing_intervalspartition the source exactly.labels agree.
the strip is removed.
peak_rss_bytesis the maximum of the per-stage peaks; the sum never appears."N/A", no0.0synthesized bound, no key for an unrequested capability, in real output.reach the state under test makes the test pass without the code running, which has happened here
twice.
uv run --extra dev pytestgreen, and the deterministic render-from-originalenhanceflowis not regressed.
Depends on
runexecutes a plan, so the planner comes first.audio packages pull.