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
+12 -20
View File
@@ -104,11 +104,8 @@ std::string fxGuidString(MediaTrack* tr, int fx) {
return std::string(buf);
}
// ANY offline FX, not every one: a park offlines the whole chain, but a partial
// undo or a half-finished hand recovery leaves some back online, and there is no
// read that tells a park's leftover offline from one the user set. So the test
// refuses in the direction that commits nothing false — the cost is a chain
// carrying a hand-offlined plugin that the tool then declines to park.
// ANY offline FX, not every — see the snapshot-source invariant (view_fx_park.h,
// src/shell/view/CLAUDE.md) for why.
bool anyFxOffline(MediaTrack* tr) {
const int fxCount = TrackFX_GetCount(tr);
for (int fx = 0; fx < fxCount; ++fx)
@@ -116,11 +113,12 @@ bool anyFxOffline(MediaTrack* tr) {
return false;
}
// "Track N" for an unnamed track, matching REAPER's own convention (GetTrackName,
// not P_NAME, for the same reason capture::trackName picks it). The buffer is
// read bounded — the SDK documents no NUL within bufOut_sz. A track the report
// cannot name still has to appear in it, so the read failing yields a placeholder
// rather than dropping the entry.
} // namespace
// GetTrackName, not P_NAME, matching capture::trackName's reason for the same
// choice. The buffer is read bounded — the SDK documents no NUL within
// bufOut_sz. A track the report cannot name still has to appear in it, so the
// read failing yields a placeholder rather than dropping the entry.
std::string trackDisplayName(MediaTrack* tr) {
std::vector<char> buf(1024, '\0');
if (!GetTrackName || !GetTrackName(tr, buf.data(), static_cast<int>(buf.size())))
@@ -128,8 +126,6 @@ std::string trackDisplayName(MediaTrack* tr) {
return std::string(buf.data(), strnlen(buf.data(), buf.size()));
}
} // namespace
ParkAction decideParkForTrack(MediaTrack* tr, bool haveSnapshot,
const std::vector<TrackFlagOp>& parkFlags) {
if (haveSnapshot) return decidePark(true, false); // second term unread — skip the reads
@@ -139,18 +135,14 @@ ParkAction decideParkForTrack(MediaTrack* tr, bool haveSnapshot,
return decidePark(false, chainReadsParked(flagsRead, anyFxOffline(tr)));
}
void reportRefusedParks(ReaProject* proj, const std::vector<MediaTrack*>& refused) {
void reportRefusedParks(ReaProject* proj, const std::vector<std::string>& refusedNames) {
ReaProject* const owner = proj ? proj : currentProject();
std::vector<std::string> names;
names.reserve(refused.size());
for (MediaTrack* tr : refused) names.push_back(trackDisplayName(tr));
if (owner == g_reportedOwner && names == g_reportedRefusals) return;
if (!shouldReport(owner == g_reportedOwner, g_reportedRefusals, refusedNames)) return;
g_reportedOwner = owner;
g_reportedRefusals = names;
g_reportedRefusals = refusedNames;
const std::string msg = describeRefusedParks(names);
const std::string msg = describeRefusedParks(refusedNames);
// "!SHOW:" so an unattended project-load reapply cannot force the console open
// (reaper_plugin_functions.h:6536), same as the drain's drop report.
if (!msg.empty()) ShowConsoleMsg(("!SHOW:" + msg).c_str());