tracking: one ledger, one authority — prune protection and replace-vs-add answered from the same records, fail-safe on unreadable state

This commit is contained in:
2026-07-30 19:44:11 -04:00
parent 7bd911d58b
commit 7f70d94228
40 changed files with 1546 additions and 633 deletions
+43
View File
@@ -0,0 +1,43 @@
#include "core/tracking/tracking_authority.h"
namespace reasampler::tracking {
ProtectionAnswer pruneProtection(const TrackingState& state) {
ProtectionAnswer answer;
// heldPaths is taken unconditionally: on an abort the usage fold returns its
// protect-all set, which is the widest (safest) answer available.
answer.heldPaths = state.usage.heldPaths;
if (state.usage.abortPrune) {
answer.blocked = true;
answer.unreadableUsageKeys = state.usage.offendingKeys;
}
if (state.ledgerStatus == LedgerStatus::Unreadable) {
answer.blocked = true;
answer.ledgerUnreadable = true;
return answer; // ownedPaths left empty -> (owned ∩ present) is empty
}
answer.ownedPaths = state.ledger.ownedPaths();
return answer;
}
Answer tiedUsageExists(const TrackingState& state, const std::string& capturePath,
const std::string& ownUsageKey) {
if (capturePath.empty()) return Answer::Indeterminate;
if (state.ledgerStatus == LedgerStatus::Unreadable) return Answer::Indeterminate;
if (state.usage.abortPrune) return Answer::Indeterminate;
for (const wire::CountedUsage& counted : state.usage.counted) {
const bool isOwn = !ownUsageKey.empty() && counted.key == ownUsageKey &&
!counted.record.unioned;
if (isOwn) continue;
for (const wire::UsageHold& hold : counted.record.holds)
if (hold.relativePath == capturePath) return Answer::Yes;
}
return Answer::No;
}
} // namespace reasampler::tracking