Fix render-bounds EXACT verdict: enumerate floored models instead of trusting grid membership

Grid-ness of an edge was a proxy for "no floor could explain this count," not
the test itself — equal remainders on both edges cancel under a full floor. Now
checks all three floored models directly and corrects the SHORT/LONG
floor-signature docs.
This commit is contained in:
2026-08-02 16:21:46 -04:00
parent 5f971e60cd
commit bcdf97d6c4
6 changed files with 188 additions and 51 deletions
+1 -1
View File
@@ -27,7 +27,7 @@ Checks for Θ, Ξ, and Ψ work that no unit test can close. Build **Release**, i
- [ ] One razor-union case (two disjoint areas, one track) — lands the requested window, no `ReaSampler capture failed:` line (`PLAN.md:2137`)
- [ ] Capture an item whose extent already equals the window — still lands, unchanged (the byte-identity regression floor) (`docs/COMPLETED.md:829`)
- [ ] **The millisecond floor — what to expect.** A custom-bounds render is known to floor its window's END to the millisecond and write the floored value back over `RENDER_ENDPOS`. Mechanism, why two `RENDER_BOUNDSFLAG` channels exist, and the two live observations behind this: `src/core/capture/render_settings.h`'s `RenderBoundsChannel` and `docs/TODO.md` "An offline capture can be refused...". **Both live observations started at `0s`, on the grid, so nothing is known about the START edge**
- [ ] **The one experiment — does another bounds mode escape the floor?** This build renders on the TIME SELECTION channel (`RENDER_BOUNDSFLAG=2`, window handed over via `GetSet_LoopTimeRange`) instead of custom time bounds. Every capture prints one line beginning `ReaSampler capture -- bounds channel:` — including the two paths that answer before any bounds are judged (unsupported format, no output file), which print `NOT JUDGED` rather than staying silent. Read the verdict: a bare **SHORT**/**LONG** (no tag), or one naming "floored to the millisecond", is the floor's signature — it did not escape this channel. **(WITHIN TOLERANCE)** on a SHORT/LONG is the gate's ordinary ±1-frame edge-convention slack (`render_window.h`), not the floor — don't read it as either result. **EXACT on a window whose END is off the millisecond grid** is the fix — the floor did not reach this channel. **EXACT on a window whose END lands on the grid is NOT conclusive**: the line adds "The END edge is UNTESTED here too" — a floored render prints the identical count by coincidence, so re-run with an off-grid end before trusting EXACT. **NOT JUDGED naming a bounds channel** means that capture answered nothing (tail mode was not None, the render was empty, the render never even reached a bounds check) OR the render source itself derives its own bounds and never consulted the channel — selected-items/razor captures always read this way, so pick a window narrower than the selected item(s) to route through the time-bounded source instead
- [ ] **The one experiment — does another bounds mode escape the floor?** This build renders on the TIME SELECTION channel (`RENDER_BOUNDSFLAG=2`, window handed over via `GetSet_LoopTimeRange`) instead of custom time bounds. On every return past the point a bounds channel is chosen (the format/mode/empty-range/no-project refusals answer earlier and print nothing), one line beginning `ReaSampler capture -- bounds channel:` prints — including the two paths that answer before any bounds are judged (unsupported format, no output file), which print `NOT JUDGED` rather than staying silent. Read the verdict: **the floor's signature is ONLY a sentence naming "floored to the millisecond"** — a bare SHORT with no such sentence means the shortfall's cause is unestablished, and LONG can never be the floor's signature (a floor only removes frames, never adds them). **(WITHIN TOLERANCE)** on a SHORT/LONG is the gate's ordinary ±1-frame edge-convention slack (`render_window.h`), not the floor — don't read it as either result, and it can mask a floor: a window whose start and end sit in the same millisecond bucket makes the floored count equal the exact one, so a real one-frame floor there reads as a bare SHORT (WITHIN TOLERANCE) with no floor sentence at all. **EXACT is the fix only when the line carries no further caveat.** The verdict checks the observed count against every millisecond-floored model of the window (start floored alone, end floored alone, both together) and names any that reproduce it — grid membership on either edge is a proxy for that collision, not the test itself, so the caveat can fire even when NEITHER edge sits on the millisecond grid (sub-millisecond remainders on the two edges can cancel under a full floor — a dragged, fixed-length time selection is the reproducible case). Re-run with a window the caveat doesn't name before trusting EXACT. **NOT JUDGED naming a bounds channel** means that capture answered nothing (tail mode was not None, the render was empty, the render never even reached a bounds check, or the window rounds to 0 frames at this rate) OR the render source itself is INFERRED (not SDK-confirmed) to derive its own bounds and never consult the channel — selected-items captures always read this way; razor edits never do today, because no offline capture path assigns `SourceMode::RazorArea` (razor is a range source resolved through track/item scope, not a render source of its own) — so pick a window narrower than the selected item(s) to route through the time-bounded source instead
- [ ] **Same run, the START edge.** The verdict line also says whether the run tested the start. Capture a range whose start is NOT a whole millisecond (set View → time unit to Samples, then nudge the selection start off the grid) so the line reads `The START edge IS tested here`. Report that line verbatim — it is the only evidence available for whether the start floors too, and a start floor is the case that would break the null test silently rather than loudly
- [ ] **Auto and Manual tail.** Repeat the off-grid-start/off-grid-end capture once with the panel tail toggle at **Auto** and once at **Manual**. Neither is judged against a frame count, so the evidence is the `after render` drift lines: report whether either channel's bounds read back changed. `[verify — DAW]` A tail is assumed to render PAST the window end — the SDK header (`:3048`) confirms only that `RENDER_TAILMS` is a length in ms, not that it extends past the end. If that assumption is wrong, an end floor could be costing Auto/Manual real content with no detector (`checkRenderedBounds` returns immediately for `tailMode != None`) — so also report by ear/measurement whether either tail capture comes up short against the source, not only whether the bounds fields drifted
- [ ] Whichever way the experiment lands, the refused render is still kept for diagnosis at `<project folder>/reasampler_refused/` (the refusal line names the path; a failed move leaves it unindexed in the bank folder and says so). Delete the folder when done — nothing in the bank references it