tracking: read the ledger's version, not just write it; clear owned on any block; channel-correct prune recovery

This commit is contained in:
2026-07-30 20:11:05 -04:00
parent 7f70d94228
commit 45b87dc2ff
27 changed files with 432 additions and 168 deletions
-2
View File
@@ -273,8 +273,6 @@ ImportResult importFileIntoActiveBank(const std::string& absoluteSourcePath) {
s.createdTimestamp = nowSec;
const AddResult r = book.activeIndex().add(s);
// Record the birth regardless of outcome — the tool WROTE the file, so prune must
// attribute it even in the narrow Collapsed race below.
g_session->recordCreated(s, tracking::OriginKind::Ingest);
switch (r) {
+18 -3
View File
@@ -6,6 +6,7 @@
#include <string>
#include <vector>
#include "core/version/app_version.h" // extStateNamespace — the printed recovery line must be channel-correct
#include "shell/persist/session.h" // ReaSamplerSession — pruneDryRun / pruneOrphanSet / pruneReclaim
#define REAPERAPI_MINIMAL
@@ -27,22 +28,36 @@ void doBankPruneFolder(ReaSamplerSession& session) {
// set unknowable, so the prune HALTS outright rather than proceed with degraded
// protection. Both blockers can fire at once; report each one that did.
if (report.blockedByTracking) {
// Every printed recovery line names THIS build's ext-state namespace: a beta
// user handed the stable spelling would clear the stable channel's key in
// their project and still be blocked.
const std::string& ns = version::extStateNamespace();
std::string msg =
"ReaSampler prune: ABORTED -- the file-tracking state could not be read. "
"Nothing was deleted.\n";
if (report.ledgerUnreadable) {
msg += "The stored file-tracking ledger is malformed. It has been left "
"intact rather than overwritten, so it can be repaired or cleared:\n"
" reaper.SetProjExtState(0, \"reasampler\", \"owned_files\", \"\")\n"
" reaper.SetProjExtState(0, \"" + ns + "\", \"owned_files\", \"\")\n"
"Clearing it makes every existing bank file un-reclaimable (they stop "
"being attributable to ReaSampler); no file is lost.\n";
"being attributable to ReaSampler); no file is lost. Reopen the "
"project afterwards -- the block is held for the rest of this "
"session, and until then no new capture is persisted to the ledger "
"either.\n";
}
if (report.ledgerFutureVersion) {
msg += "The stored file-tracking ledger was written by a NEWER version of "
"ReaSampler than this one, so its records cannot be read safely. It "
"has been left intact and will NOT be overwritten. Reopen the project "
"with that newer version -- do NOT clear this key from here, that "
"would discard tracking records this build cannot see.\n";
}
if (!report.unreadableUsageKeys.empty()) {
msg += "One or more instance usage records could not be read or decoded. "
"If the owning instance is still loaded it will republish its record "
"on the next poll tick, clearing the abort. If the instance no longer "
"exists (the key is an orphaned corrupt record), clear it manually:\n"
" reaper.SetProjExtState(0, \"reasampler\", \"<key>\", \"\")\n"
" reaper.SetProjExtState(0, \"" + ns + "\", \"<key>\", \"\")\n"
"Offending key(s):\n";
for (const std::string& key : report.unreadableUsageKeys) {
msg += " " + key + "\n";