Commit 36466a40 by PLN (Algolia)

fix(probe): one low FINAL bin is the window closing, not a fade

Third and last calibration of shape_of() against real audio. perfect.tidal's d4
measured |▇▇▆▆▇▇▆▅▆▆▇▆▃| — visibly steady for twelve bins — and was reported
"DECAYING, 13 dB down, never recovering, almost certainly an xfade tail" on the
strength of the thirteenth. The capture window had simply closed inside a gap
between events.

The midpoint-crossing rule added in 708c2aef cannot catch this: a dip in the last bin
crosses the midpoint exactly ONCE, which is the signature of a genuine fade. So ask a
different question — does the verdict survive dropping the final bin? If the inner
trend is flat, the final bin WAS the verdict, and the answer is STEADY with the edge
dip named explicitly rather than hidden.

A real decay is unaffected, including one that only begins in the last three bins
(still DECAYING). Eight synthetic shapes now separate cleanly: steady-with-edge-dip,
monotonic decay, late decay, gated-riser-dipping-at-the-end, spiky-sparse, died,
steady, rising.

Pattern across all three fixes to this function: every false positive came from
answering a question about SHAPE with a pair of summary statistics. Each fix replaced
a statistic with the structural question that actually distinguishes the cases —
does it recur, does it survive without its last sample. The verdict text now says
which, so the reading can be argued with instead of believed.
parent 4836d74f
...@@ -296,6 +296,22 @@ def shape_of(series: list[float], bin_s: float) -> str: ...@@ -296,6 +296,22 @@ def shape_of(series: list[float], bin_s: float) -> str:
f"({min(lvls):+.1f} to {max(lvls):+.1f} dB), so it RECURS rather than " f"({min(lvls):+.1f} to {max(lvls):+.1f} dB), so it RECURS rather than "
f"fades: a masked/gated part (e.g. mask \"<t f!7>\") or a sparse one. " f"fades: a masked/gated part (e.g. mask \"<t f!7>\") or a sparse one. "
f"A decay crosses once, by definition") f"A decay crosses once, by definition")
# One low FINAL bin is a capture-edge artifact, not a fade. The window simply
# closed inside a gap between events. Seen 2026-07-28 on perfect.tidal's d4:
# |▇▇▆▆▇▇▆▅▆▆▇▆▃| — visibly steady for 12 bins, and called "DECAYING, 13 dB
# down, almost certainly an xfade tail" on the strength of the thirteenth. So
# ask whether the verdict survives dropping that last bin; if it does not, the
# last bin WAS the verdict.
if drop > 12 and len(series) >= 6:
inner = [d for d in series[:-1] if d != -math.inf]
if inner:
q2 = max(1, len(series[:-1]) // 4)
inner_tail = [d for d in series[:-1][-q2:] if d != -math.inf]
if inner_tail and head_avg - (sum(inner_tail) / len(inner_tail)) <= 12:
return (f"STEADY — {head_avg:+.1f} dB, with a dip in the FINAL bin only "
f"({series[-1]:+.1f} dB). That is the capture window closing "
f"inside a gap between events, not a fade — the trend without "
f"it is flat")
if drop > 12: if drop > 12:
return (f"DECAYING — {head_avg:+.1f} -> {tail_avg:+.1f} dB ({drop:.0f} dB down), " return (f"DECAYING — {head_avg:+.1f} -> {tail_avg:+.1f} dB ({drop:.0f} dB down), "
f"never recovering. Almost certainly an xfade tail, not a part") f"never recovering. Almost certainly an xfade tail, not a part")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment