Prove every ext-state write by reading the key back, so no guard is constant-true

SetProjExtState's return describes the whole extname. The persist and the instrument's publish now re-read their key; both refusals can finally fire.
This commit is contained in:
2026-08-02 13:14:49 -04:00
parent 0afb885987
commit 25390d5253
14 changed files with 231 additions and 112 deletions
+18 -1
View File
@@ -182,7 +182,24 @@ bool ReaSamplerSession::saveToActiveProject() {
instrument::map::formatBankGeneration(bankGeneration_).c_str());
MarkProjectDirty(static_cast<ReaProject*>(proj));
return true;
// Prove the ONE key a caller's answer hinges on. Each SetProjExtState above returns the
// size of the whole extname's state, which the six writes here keep non-zero between
// them, so no single one of those returns can speak for `banks`
// (wire::extStateWriteLanded owns the reasoning). The sibling keys stay unobserved and
// no caller claims otherwise; `banks` is the one whose absence would make a landed
// capture vanish on reload.
const wire::GrowingExtStateRead back = wire::readProjExtStateGrowing(
[&](char* buf, int cap) {
return GetProjExtState(static_cast<ReaProject*>(proj), projExtNamespace(),
kProjExtBanksKey, buf, cap);
});
if (back.status == wire::GrowingExtStateRead::Status::Overflow)
return false; // could not check -> do not claim; never folded in as an absence
return wire::extStateWriteLanded(
banksJson, back.status == wire::GrowingExtStateRead::Status::Complete
? std::optional<std::string>(back.value)
: std::nullopt);
}
bool ReaSamplerSession::writeAssignmentRequest(const std::string& wire) {