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
{{ message }}
Repository navigation
normalize_audio (target_lufs), grade, loop_audio log nothing about what they applied — a save:false step's effect is unobservable #392
expected: each value-applying step logs what it did, the way mix_audio does ("mix_audio: 2 tracks, gains [1.0, 0.5]", with structured gains). For normalize_audio with target_lufs, that means: the measured input loudness and peak, the gain applied in dB, and which constraint set it (the LUFS target or the peak ceiling). For grade, it means the parameters applied. For loop_audio, it means the loop count and the output length.
actual: the job succeeded and the result is correct. The norm wav measures integrated_lufs −23.00 and peak −8.18, so the LUFS target set the gain and the ceiling didn't. But in get_job_events, bed, norm and graded emit only phase/memory/writing/wrote events. Nothing in the events says what gain normalize_audio applied, or whether LUFS or the ceiling decided it. The shortfall warning exists only for the ceiling case, so a silent run could mean either "the target was met" or "target_lufs was ignored". Nothing records whether grade changed anything either. The frame at 2 s looks slightly warmer than asset:qa-cast/ep37-episode.mp4 at the same time, but that's judged by eye, and media carries no colour statistics.
why it matters: I had to work around this. The only way to confirm a level-setting step took effect is a separate get_gallery_metadata call on each intermediate output, and that works only if the step saves. With save: false, which is the usual case mid-chain, the step's effect can't be observed at all. This is the same class as the resample_audio note on #295 (it logs nothing either). A one-line log per step would settle it.
Also confirmed on this run: #293's mixed-rate mix_audio (32 kHz + 16 kHz) now resamples to 32 kHz with a sample_rate_mismatch warning, and pair_audio fit:"video" → 248 f / 10.334 s / 32 kHz stereo, −23.04 LUFS after the mux.
Fixed in commit d9d1143, merged to develop at 1f6d8ab, deployed to lem at 2026-09-23 04:10:35 UTC (server confirmed healthy).
All three commands now use emit_log (not just logger.debug), so their output reaches get_job_events over MCP even when the step is save:false:
normalize_audio: logs measured peak (dBFS) and, when target_lufs was given, the measured integrated LUFS; the gain applied in dB; and a constraint field naming what set the gain - "target_lufs" (LUFS target held), "peak_ceiling" (LUFS target existed but the peak ceiling capped it - including the unmeasurable-loudness fallback case), or "peak_dbfs" (no target_lufs given at all, so the ceiling was the only constraint in play). The existing target_lufs_unmeasurable/target_lufs_capped warnings were left untouched.
loop_audio: logs the lap/loop count and the resulting output length (samples and seconds).
grade: logs the non-identity parameters actually applied (comparing each of exposure/contrast/saturation/temperature/tint against its identity default), or an explicit "no adjustment" message when every parameter was left at default.
Tests added in tests/test_audio_utils.py (TestNormalizeAudio, TestLoopAudio) and tests/test_grade.py (TestAppliedParametersAreLogged), all driving the real code path through RunContext/activate_context and asserting on the captured "log" events - not mocks of emit_log itself. Full suite (5838 passed, 14 skipped) and ruff pass.
resample_audio, named in the issue as "the same class as #295", already had a correct emit_log call in the current codebase - no change was needed there.
Verified against lem develop @ 732cd21, workspace qa-ep38.
Repro (job 20ec7e7c350f): I ran the issue's 5-step chain (bed loop_audio → mix → norm normalize_audio peak_dbfs=-3/target_lufs=-23 → graded grade temp 0.3/sat 0.8/contrast 1.1 → episode pair_audio fit:video). Every intermediate step had no result, so none of them saved a file (manifest files: []). get_job_events now shows:
bed: loop_audio: 79360 samples at 16000Hz looped 3x to 165333 samples (10.33 s) with laps: 3, output_samples, output_seconds
norm: normalize_audio: measured -0.6 dBFS peak, -15.4 LUFS -> gain -7.6 dB, set by target_lufs with structured measured_peak_dbfs, measured_lufs, gain_db, constraint: "target_lufs"
graded: grade: applied {'contrast': 1.1, 'saturation': 0.8, 'temperature': 0.3} with each parameter as a field
Adjacent cases (job 9c0180ef41ab):
normalize_audio with no target_lufs (peak_dbfs=-3): gain -2.4 dB, set by peak_dbfs, measured_lufs: null, constraint: "peak_dbfs"
target the ceiling caps (peak_dbfs=-20, target_lufs=-10): the target_lufs_capped warning still fires (24.8 LU short), and the log line reads gain -19.4 dB, set by peak_ceiling, constraint: "peak_ceiling"
grade with every parameter left at default: grade: no adjustment (all identity)
This matches expected:. I deleted both runs' outputs.
Activity
Merge branch 'fix/392-audio-grade-observability' into develop (#392)
dkackman commentedon Sep 24, 2026
Fixed in commit d9d1143, merged to develop at 1f6d8ab, deployed to lem at 2026-09-23 04:10:35 UTC (server confirmed healthy).
All three commands now use
emit_log(not justlogger.debug), so their output reachesget_job_eventsover MCP even when the step issave:false:normalize_audio: logs measured peak (dBFS) and, whentarget_lufswas given, the measured integrated LUFS; the gain applied in dB; and aconstraintfield naming what set the gain -"target_lufs"(LUFS target held),"peak_ceiling"(LUFS target existed but the peak ceiling capped it - including the unmeasurable-loudness fallback case), or"peak_dbfs"(notarget_lufsgiven at all, so the ceiling was the only constraint in play). The existingtarget_lufs_unmeasurable/target_lufs_cappedwarnings were left untouched.loop_audio: logs the lap/loop count and the resulting output length (samples and seconds).grade: logs the non-identity parameters actually applied (comparing each of exposure/contrast/saturation/temperature/tint against its identity default), or an explicit "no adjustment" message when every parameter was left at default.Tests added in
tests/test_audio_utils.py(TestNormalizeAudio,TestLoopAudio) andtests/test_grade.py(TestAppliedParametersAreLogged), all driving the real code path throughRunContext/activate_contextand asserting on the captured"log"events - not mocks ofemit_logitself. Full suite (5838 passed, 14 skipped) and ruff pass.resample_audio, named in the issue as "the same class as #295", already had a correctemit_logcall in the current codebase - no change was needed there.Worked as claude-sonnet-5 via Anthropic.
dkackman commentedon Sep 24, 2026
Verified against lem
develop @ 732cd21, workspaceqa-ep38.Repro (job
20ec7e7c350f): I ran the issue's 5-step chain (bedloop_audio →mix→normnormalize_audio peak_dbfs=-3/target_lufs=-23 →gradedgrade temp 0.3/sat 0.8/contrast 1.1 →episodepair_audio fit:video). Every intermediate step had noresult, so none of them saved a file (manifestfiles: []).get_job_eventsnow shows:bed:loop_audio: 79360 samples at 16000Hz looped 3x to 165333 samples (10.33 s)withlaps: 3,output_samples,output_secondsnorm:normalize_audio: measured -0.6 dBFS peak, -15.4 LUFS -> gain -7.6 dB, set by target_lufswith structuredmeasured_peak_dbfs,measured_lufs,gain_db,constraint: "target_lufs"graded:grade: applied {'contrast': 1.1, 'saturation': 0.8, 'temperature': 0.3}with each parameter as a fieldAdjacent cases (job
9c0180ef41ab):gain -2.4 dB, set by peak_dbfs,measured_lufs: null,constraint: "peak_dbfs"target_lufs_cappedwarning still fires (24.8 LU short), and the log line readsgain -19.4 dB, set by peak_ceiling,constraint: "peak_ceiling"grade: no adjustment (all identity)This matches
expected:. I deleted both runs' outputs.— tester, claude-opus-5-5 via anthropic