Take the read-back back out of the persist; a write verdict belongs only where evidence crosses the plugin boundary
Its false gated six undo points, so an unverified byte-equality assumption could have silently removed Ctrl-Z for a bank mutation that landed.
This commit is contained in:
@@ -767,3 +767,83 @@ above.
|
||||
function under a `<module>_tests` target with no REAPER, no VST3 SDK, and no
|
||||
filesystem includes; `shell/capture/render_bounds_gate` shrinks to the file-move and
|
||||
the two callers' plumbing.
|
||||
|
||||
## The capture path ignores `saveToActiveProject`'s return at four sites
|
||||
|
||||
**Context.** `saveToActiveProject()` returns false for exactly two reasons — no active
|
||||
project, or an unsaved one — and in both cases NOTHING was written. Four capture sites
|
||||
discard that return outright: `capture_orchestrator.cpp:343`, `capture_batch.cpp:266` and
|
||||
`:333`, and `realtime_lifecycle.cpp:39`.
|
||||
|
||||
**The wart.** A capture on an unsaved project renders the file into the bank folder, adds
|
||||
the `Sample` to the in-memory book, records a birth record in memory — and loses all three
|
||||
on reload. The bytes stay on disk with no index entry and no persisted ledger record, so
|
||||
they are a foreign file prune will never reclaim (an unrecorded file is untouchable by
|
||||
design — `core/tracking/CLAUDE.md`). Nothing is printed. The bank-op family already reads
|
||||
this return and discards its undo point on a false; the capture family does not read it at
|
||||
all.
|
||||
|
||||
**Why filed, not fixed.** Pre-existing, and the right answer is a product decision this
|
||||
dispatch had no mandate for: refuse the capture up front, keep it and warn, or prompt for
|
||||
a Save-As (the bank ops chose "quiet persist by design, deliberately no Save-As prompt" —
|
||||
whether capture should follow is a separate call).
|
||||
|
||||
**Done looks like.** A capture attempted with no saved project either does not write bytes
|
||||
at all, or writes them and says so in a sentence naming what will not survive a reload —
|
||||
and the choice between those two is recorded rather than implicit.
|
||||
|
||||
## `panel_input`'s wheel handler persists the whole book per wheel message
|
||||
|
||||
**Context.** `panel_input.cpp:450` — `handleWheel` calls `markTailDirty()` on every wheel
|
||||
message that actually moves `manualMs`, while the pointer is over the footer in Manual
|
||||
mode. (It coalesces sub-notch deltas within ONE message and no-ops at a bound, so the
|
||||
count is wheel messages that changed the value, not raw notches.)
|
||||
|
||||
**The wart.** `markTailDirty` is `saveToActiveProject()` — a full `BankBook` serialize plus
|
||||
six ext-state value writes on the UI thread — for a setting that is one number. A flick
|
||||
over the footer is a dozen of them in a few hundred milliseconds. Disproportionate rather
|
||||
than incorrect: no guardrail is violated (this is nowhere near the two named hot paths),
|
||||
and the writes are idempotent.
|
||||
|
||||
**Intended fix.** Coalesce: mark dirty and let one timer tick flush, the same shape the
|
||||
panel already uses elsewhere for repaint batching.
|
||||
|
||||
**Done looks like.** A continuous wheel gesture over the footer produces one persist, and
|
||||
the value that lands is the gesture's final one.
|
||||
|
||||
## `RunCaptureItemAssign`'s undo point does not follow the pattern its comment claims
|
||||
|
||||
**Context.** `capture_orchestrator.cpp:364-365` states that the action follows the bank-op
|
||||
family's discard-on-unsaved pattern.
|
||||
|
||||
**The wart.** It does not: `:382-383` records the undo point unconditionally whenever
|
||||
`sampleId` is non-empty, and never consults the persist's return at all. So on an unsaved
|
||||
project it records an undo point for ext-state that was never written — the empty
|
||||
no-effect entry `persistBankOp`'s guardrail exists to avoid. The comment describes the
|
||||
intended behavior, not the code.
|
||||
|
||||
**Why filed, not fixed.** It is one instance of the capture-family gap filed above, and
|
||||
fixing it alone would leave the other four sites divergent. Fix them together, or explain
|
||||
in one place why capture differs from bank ops.
|
||||
|
||||
**Done looks like.** The comment and the code agree, and the whole capture family answers
|
||||
the unsaved-project case one way.
|
||||
|
||||
## `core/tracking/CLAUDE.md`'s untracked-file enumeration says "reaches the `.rpp`" too loosely
|
||||
|
||||
**Context.** `src/core/tracking/CLAUDE.md:24-31` enumerates how a created file can stay
|
||||
untracked, and describes the ledger as reaching the `.rpp` at the following
|
||||
`saveToActiveProject()`.
|
||||
|
||||
**The wart.** `saveToActiveProject()` writes REAPER's IN-MEMORY project state and marks the
|
||||
project dirty; REAPER writes the `.rpp` on the project's own save, which may be much later
|
||||
or never. The sentence was already loose before this branch and is not made wrong by it —
|
||||
but it is the same over-claim ("a write reached the file on disk") the bake's reporting
|
||||
pass spent several rounds removing from its own sentences, so it should read the same way.
|
||||
|
||||
**Why filed, not fixed.** Editing another layer's own CLAUDE.md from a persist-and-report
|
||||
dispatch is exactly the boundary crossing the per-directory docs exist to prevent. It is a
|
||||
doc-keeper edit.
|
||||
|
||||
**Done looks like.** The enumeration distinguishes "in the project's state" from "on disk
|
||||
in the `.rpp`", and does not gain a second home for the distinction.
|
||||
|
||||
Reference in New Issue
Block a user