Ψ-W2-T2 remediation: atomic temp+rename collapse write, honest unknown-channel fallback, [verify — DAW] markers, corrected+filed bake-collapse deferral, observable collapse message, quiet-NaN test

This commit is contained in:
2026-08-01 22:08:39 -04:00
parent 4fa3c1dd15
commit 8b191e3379
12 changed files with 151 additions and 31 deletions
+8
View File
@@ -89,6 +89,14 @@ Detail specific to these pure modules:
which is what the bit-identical-repeats invariant actually asks for. Do not "fix"
this by hashing pre-collapse — that would make two entries with different audio
layouts share one identity.
- **The collapse's minimal rebuild also drops `bext`/iXML/LIST — a source-position
consequence, not only a hashing one.** REAPER's renderer writes a `bext` time
reference, and REAPER's own import paths can position an item at that BWF timestamp,
so a collapsed capture loses it while a declined (non-collapsed) capture from the same
action keeps it — two captures from one action behave differently on re-import.
`shell/capture/insert.cpp` is unaffected (it drives `SetEditCurPos` + `InsertMedia`
rather than reading BWF), so this is not a defect in the shipped insert path.
Accepted, not verified against a DAW re-import: `[verify — DAW]`.
- `tail_control`'s `kDefaultManualTailMs`/`kManualStepMs` and
`render_settings`'s `kMaxTailMs`/`kAutoTrimThresholdDb` are separate constants
in separate files by design (panel-facing default/step vs. runaway-guard cap)
+7 -2
View File
@@ -284,8 +284,13 @@ MonoCollapse collapseToMono(const std::vector<std::uint8_t>& bytes) {
}
}
// float -> double -> float round-trips exactly (double represents every float),
// so channel 0 reaches the rebuilt file unaltered.
// float -> double -> float round-trips exactly for every finite value and for
// +-0/+-infinity (double represents every float bit pattern in those classes), so
// channel 0 reaches the rebuilt file unaltered. The one hole: a signaling NaN is
// quieted by the float->double promotion, so an identical-bit sNaN pair could
// collapse to a different bit pattern than it started with. Not reachable from
// REAPER-rendered audio, but the bit-identical predicate above admits NaN inputs,
// so this rebuild is not exempt from the claim it makes.
std::vector<double> mono(frames);
for (std::size_t f = 0; f < frames; ++f)
mono[f] = static_cast<double>(pcm[f * stride]);
+2 -1
View File
@@ -113,7 +113,8 @@ struct MonoCollapse {
// The rebuild is a canonical minimal WAV, so non-audio chunks (a renderer's `bext`
// timestamp, iXML, LIST) do not survive it. That much hashWavContent already skips —
// but the collapse rewrites the `fmt ` body and the `data` payload too, which moves
// the file's content identity; see this directory's CLAUDE.md for what that costs.
// the file's content identity; see this directory's CLAUDE.md for what that costs,
// including the bext/source-position consequence beyond hashing.
MonoCollapse collapseToMono(const std::vector<std::uint8_t>& bytes);
// --- Content identity (dedup hashes) -----------------------------------------