Name refused tracks before Undo_EndBlock2, not after; tighten the route-list doc; pin the refusal memo's gate

Fixes D (handle lifetime), C (ASCII dashes), G (comment compression), I (shouldReport extracted + tested); CLAUDE.md route list corrected per A/B/H. E pushed back -- cross-module GUID plumbing is architectural, not a targeted fix.
This commit is contained in:
2026-08-05 17:34:49 -04:00
parent 5376ab085c
commit 4b306dd436
5 changed files with 100 additions and 54 deletions
+35 -8
View File
@@ -236,11 +236,8 @@ static void testRestorePlanOpsRebuildTheSlotKeyedSnapshotVerbatim() {
// -- may this chain be snapshotted? -------------------------------------------
//
// The pre-park snapshot is restore's only source of truth, so one taken from an
// already-parked chain makes every later restore write hidden/out-of-mix/
// FX-disabled back, permanently. The park site cannot infer a clean chain from
// an absent snapshot — discardDeferredFxParks drops intents whose flag writes
// already landed — so the chain itself has to be asked.
// Rationale: the snapshot-source invariant (view_fx_park.h, this directory's
// CLAUDE.md).
// The live values the fold reads, keyed by Flag — so an assertion names the flag
// it varies rather than a position in makeParkPlan's op order.
@@ -283,9 +280,7 @@ static void testAnEmptyPlanProvesNothing() {
}
static void testEitherHalfOfTheChainReadingParkedIsEnoughToRefuse() {
// The disjunction, pinned: a snapshot has a flag half and an FX half, and each
// is the only source of truth for its own. An AND here would re-open the
// defect one layer down — flags clean, FX still offline, snapshotted as truth.
// Disjunction pinned; rationale at chainReadsParked (view_fx_park.h).
CHECK(!chainReadsParked(/*parkFlagsRead=*/false, /*anyFxOffline=*/false));
CHECK(chainReadsParked(/*parkFlagsRead=*/true, /*anyFxOffline=*/false));
CHECK(chainReadsParked(/*parkFlagsRead=*/false, /*anyFxOffline=*/true));
@@ -337,6 +332,33 @@ static void testRefusalRecoveryNamesThePerFxHalfAndAssertsNoCause() {
CHECK(msg.find("lost") == std::string::npos);
}
// -- the refusal memo's print-suppression gate --------------------------------
//
// reportRefusedParks' own memo (owner + last-reported names, both REAPER-side
// statics) can't be driven from here, but the pure gate behind it can: prints
// (i.e. updates the memo) on any change, stays silent on an exact repeat, and
// treats a fresh empty set as a change too, so a later real refusal is never
// mistaken for a repeat of one that already healed.
static void testUnchangedOwnerAndSetStaysSilent() {
CHECK(!shouldReport(/*sameOwnerAsLast=*/true, {"Bass"}, {"Bass"}));
}
static void testADifferentNamedSetReports() {
CHECK(shouldReport(/*sameOwnerAsLast=*/true, {"Bass"}, {"Bass", "Drum bus"}));
}
static void testADifferentOwnerReportsEvenWithTheSameNames() {
// Two alternating project tabs must not suppress each other's first refusal.
CHECK(shouldReport(/*sameOwnerAsLast=*/false, {"Bass"}, {"Bass"}));
}
static void testAFreshEmptySetReportsAndResetsTheMemo() {
CHECK(shouldReport(/*sameOwnerAsLast=*/true, {"Bass"}, {}));
// Already empty, same owner: nothing changed, stays silent.
CHECK(!shouldReport(/*sameOwnerAsLast=*/true, {}, {}));
}
// -- re-entrancy -------------------------------------------------------------
static void testTakeDetachesEverythingAndLeavesTheQueueEmpty() {
@@ -411,6 +433,11 @@ int main() {
testRefusalNamesEveryRefusedTrackAndSaysNothingWhenNoneWere();
testRefusalRecoveryNamesThePerFxHalfAndAssertsNoCause();
testUnchangedOwnerAndSetStaysSilent();
testADifferentNamedSetReports();
testADifferentOwnerReportsEvenWithTheSameNames();
testAFreshEmptySetReportsAndResetsTheMemo();
testTakeDetachesEverythingAndLeavesTheQueueEmpty();
testIntentsArrivingDuringADrainSurviveIt();
testAReEntrantParkCancelsOnlyWhatIsStillPending();