docs: record the millisecond floor as located and closed, and split what stayed open
The retired custom-bounds premise is corrected wherever it was encoded: the tail bit is the time selection's, not custom bounds'.
This commit is contained in:
+63
-49
@@ -710,66 +710,80 @@ refusal reuses `CaptureStatus::BoundsMismatch` rather than minting its own statu
|
||||
earlier note here preferred a distinct status, and that preference is unresolved, not
|
||||
withdrawn.
|
||||
|
||||
## An offline capture can be refused for a short render — the millisecond floor
|
||||
## `renderHonoredBounds`'s one-frame tolerance is empirical, not proven
|
||||
|
||||
**Measured cause (live, 2026-08-02).** Two captures at 48 kHz, `TailMode::None`, matched
|
||||
their landed frame count to the frame with their window's END floored to the millisecond:
|
||||
`[0s, 1.6551724137931001s)` printed 79440 of 79448 (the console's own `%.17g` read-back),
|
||||
and `[0s, ~4.067797s)` — the double nearest the six-decimal value the original refusal
|
||||
actually printed, `4.0677966101694913`, not itself a captured console value — printed
|
||||
195216 of 195254. A three-checkpoint read-back on `RENDER_STARTPOS`/`RENDER_ENDPOS` was
|
||||
silent at store time and immediately before the render, so REAPER writes the floored end
|
||||
back as a side effect of rendering, not before it. Mechanism, why two
|
||||
`RENDER_BOUNDSFLAG` channels exist, and the live experiment this observation opened:
|
||||
`src/core/capture/render_settings.h`'s `RenderBoundsChannel` — the one narrative home;
|
||||
this entry stays the record of what was actually measured.
|
||||
**Context.** The millisecond-floor defect that motivated this gate is closed
|
||||
(`docs/COMPLETED.md`), but the gate itself — `render_window.h`'s
|
||||
`renderHonoredBounds` — carries a one-frame tolerance that carried through the fix
|
||||
unchanged and was never itself proven.
|
||||
|
||||
**Disproven by that observation.** The two hypotheses this entry previously carried — that
|
||||
the render bounds itself to the media it can see, and that a trailing-silence trim fires
|
||||
despite `RENDER_NORMALIZE = &(4<<16)` — both predict a shortfall tracking CONTENT. This
|
||||
one tracks the WINDOW: it is the exact ms-floored count, whatever the material does.
|
||||
Neither is the cause. Do not reinstate either without a fresh observation.
|
||||
**The wart.** A renderer that resolves the window's two edges by DIFFERENT
|
||||
conventions can sit two frames from `frameCountFor`'s answer on a
|
||||
correctly-honored render. That cannot account for the 8- and 38-frame shortfalls
|
||||
the floor produced (`docs/COMPLETED.md`), so it was not the cause of those
|
||||
refusals — but it means a future one- or two-frame refusal may be the gate's own
|
||||
edge convention rather than a real defect.
|
||||
|
||||
**Still open — the START edge.** Every observation to date started at `0s`. Floor, ceil
|
||||
and round all leave `0s` alone (it is exactly representable in binary), so nothing is
|
||||
known about whether the start floors too, and it is the case that matters most: an end
|
||||
floor refuses loudly, a start floor would shift content and break the null test silently.
|
||||
**Intended fix.** Not proposed. Widening the tolerance is a precision-invariant
|
||||
decision, not a bug fix, and was deliberately not taken on speculation.
|
||||
|
||||
**A premise NOT to build on — an on-grid value is not uniformly safe from a bare floor.**
|
||||
That claim holds for `0s` only because `0` is exact in binary; it is FALSE in general for
|
||||
a decimal millisecond grid point: `1.007 * 1000 == 1006.9999999999999` (floors to 1006,
|
||||
not 1007), and `4.068 * 1000 == 4067.9999999999995` (floors to 4067, not 4068). If a
|
||||
future fix compensates for a discovered START floor by grid-aligning the extraction — e.g.
|
||||
slicing a buffer from `floor(start_ms)` — and builds that arithmetic on the false premise,
|
||||
a `1.007`-class start would resolve a whole millisecond early: frame count right, content
|
||||
shifted, exactly the silent null-test misalignment this effort exists to catch. Neither
|
||||
live observation above can detect this hazard (both are off-grid sub-millisecond
|
||||
remainders, not grid points) — a `1.007`-class grid point must be measured in the DAW
|
||||
before any extraction logic is built on this premise. `render_window`'s own
|
||||
`isOnMillisecondGrid`/`floorToMilliseconds` already handle this correctly, but only on OUR
|
||||
side of the boundary; that tolerance cannot influence how REAPER itself resolves a value we
|
||||
hand it, which is the open question here, not a closed one.
|
||||
**Priority / risk.** Low. Nothing to date implicates the tolerance itself;
|
||||
recorded so a future narrow refusal is investigated rather than assumed to be
|
||||
the same floor.
|
||||
|
||||
**Still open — where the floor lives.** Custom time bounds is one of eight
|
||||
`RENDER_BOUNDSFLAG` modes. Whether the floor sits in that field's own render-time
|
||||
resolution or downstream in the render engine (where no mode escapes it) cannot be
|
||||
answered from the SDK header. `RenderBoundsChannel`
|
||||
(`src/core/capture/render_settings.h`) is the experiment; `docs/VERIFICATION.md`
|
||||
§Capture range and bounds is the one smoke run that settles it.
|
||||
**Done looks like.** Either the tolerance is confirmed correct by a DAW
|
||||
observation that isolates edge-convention behavior from bounds-floor behavior,
|
||||
or it is widened with the reasoning recorded.
|
||||
|
||||
**Not excluded — the gate itself.** `renderHonoredBounds`' one-frame tolerance is
|
||||
empirical, not proven (`src/core/capture/render_window.h`): a renderer that resolves the
|
||||
window's two edges by DIFFERENT conventions can sit two frames from `frameCountFor`'s
|
||||
answer on a correctly-honored render. That cannot account for 38 frames, so it is not
|
||||
these refusals — but it means a future one- or two-frame refusal may be ours, which is why
|
||||
the tolerance was not widened on speculation. Widening it is a precision-invariant
|
||||
decision, not a bug fix.
|
||||
## `TailMode::Auto` and `Manual` have no automatic bounds observation
|
||||
|
||||
**Context.** `render_bounds_gate.cpp`'s `checkRenderedBounds` returns early for
|
||||
anything but `TailMode::None`, so the millisecond-floor fix (`docs/COMPLETED.md`)
|
||||
was measured only against `TailMode::None` — Auto and Manual were never
|
||||
observed, before the fix or after it.
|
||||
|
||||
**The wart.** The inference that Auto/Manual are fixed too is sound — same
|
||||
bounds path, same floor, same fix — but it is an inference, not a measurement.
|
||||
`checkRenderedFileNotEmpty` runs on every tail mode and still catches a 0-byte
|
||||
render, but that is the ONLY automatic bounds signal Auto/Manual get; a
|
||||
floored or otherwise short-but-nonzero render under either mode would land as
|
||||
`Ok` with nothing to catch it.
|
||||
|
||||
**Intended fix.** Not a code change — a DAW observation. `docs/VERIFICATION.md`'s
|
||||
"Capture range and bounds" section already carries the manual check: repeat an
|
||||
off-grid-start capture at Manual over a source loud to the window's end and
|
||||
check the landed frame count against window + `tailMs`; Auto can't be checked
|
||||
by count (it trims trailing silence) and needs the null test by ear/inversion
|
||||
instead.
|
||||
|
||||
**Priority / risk.** Low. Both modes share the same bounds path as the
|
||||
now-fixed `TailMode::None`, so nothing suggests they still floor — but nothing
|
||||
confirms it either.
|
||||
|
||||
**Done looks like.** A DAW-observed Auto and Manual capture, each landing the
|
||||
window as requested, closes the inference into fact — or surfaces a
|
||||
mode-specific divergence this entry does not currently know about.
|
||||
|
||||
## Floor, ceil and round are not the identity on a millisecond grid point in binary double (caution, not an open question)
|
||||
|
||||
A discarded compensation design for the millisecond-floor defect
|
||||
(`docs/COMPLETED.md`) rested on the premise that a grid-aligned value survives a
|
||||
bare floor/ceil/round unchanged. That is false in binary double: `1.007 * 1000
|
||||
== 1006.9999999999999` (floors to 1006, not 1007), and `4.068 * 1000 ==
|
||||
4067.9999999999995` (floors to 4067, not 4068). The compensation this premise
|
||||
would have supported is no longer needed — the fix moved the render to a bounds
|
||||
mode that does not floor at all — so this is not a live open question. Recorded
|
||||
because it would bite any future millisecond-grid arithmetic that assumes an
|
||||
on-grid value is safe from a bare floor: `render_window.h`'s own
|
||||
`isOnMillisecondGrid`/`msFlooredEndFrameCount` already carry the nanosecond
|
||||
tolerance that handles it correctly on this codebase's side of the boundary; the
|
||||
trap is for whoever writes the next piece of grid arithmetic without that guard.
|
||||
|
||||
## `capture.cpp` is over the ~600-line ceiling — the seam is identified, taking it is blocked
|
||||
|
||||
**Context.** Removing the settled bounds experiment's instrumentation (the console
|
||||
verdict and the three-checkpoint `RENDER_STARTPOS`/`ENDPOS` read-back) brought the file
|
||||
from 697 to **622 measured lines**, against root `CLAUDE.md`'s ~600-line ceiling. The
|
||||
from 697 to **620 measured lines**, against root `CLAUDE.md`'s ~600-line ceiling. The
|
||||
seam that entry originally named is gone with the instrumentation; nothing left in the
|
||||
file is bisectable without cutting load-bearing why.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user