Ψ-W1-T2 review remediation: solo restore drops on visible-in-target, not parked; N-mode segments read dead when unroutable

Fixes a hidden-parent solo replay that could silence the mix. Also closes the N-mode segment silent no-op, amends the invariant comment, trims view.cpp under 600 lines, hedges two SDK inferences, drops a dead null-check.
This commit is contained in:
2026-08-01 20:13:10 -04:00
parent 9c234c2e6b
commit f2cdf676f3
17 changed files with 137 additions and 73 deletions
+1 -1
View File
@@ -92,7 +92,7 @@ settled 2026-07-23):
## Modules
- `view_mode_model` — Design View mode system: mode registry, GUID-keyed membership, folder-tree-aware visibility derivation, snapshot-based park/restore planner, the per-mode `SoloCache` it owns, JSON round-trip.
- `solo_cache` — the per-mode solo surface: `SoloCache` (mode id → GUID → raw `I_SOLO`), the soloed-subset filter, and `planSoloRestore`, whose two drop rules (dead GUID, track parked in the incoming mode) and their reasoning live in its header.
- `solo_cache` — the per-mode solo surface: `SoloCache` (mode id → GUID → raw `I_SOLO`), the soloed-subset filter, and `planSoloRestore`, whose two drop rules (dead GUID, not visible in the incoming mode) and their reasoning live in its header.
- `view_tree` — pure `I_FOLDERDEPTH`→FolderTree helper for the Design View shell.
- `mode_switch` — REAPER-free segment layout + hit-test for the bank_panel's Design View mode switch.
- `guid_diff` — the pure, REAPER-free core of the D2 Wave-2 new-content detection: `newGuids(previous, current)` computes the GUIDs present in `current` but absent from `previous` (empty GUIDs ignored); `GuidBaseline` tracks the live GUID set across polls for one project, implementing the first-poll-after-open guard (the first `observe()` after construction/`reset()` records a baseline and reports nothing new, so pre-existing content is never mass-tagged) and re-arms via `reset()` on a detected project switch so detection never diffs across two unrelated projects.
+2 -2
View File
@@ -53,11 +53,11 @@ std::size_t SoloCache::reconcile(const std::set<std::string>& liveGuids) {
std::vector<SoloOp> planSoloRestore(const std::map<std::string, int>& cached,
const std::set<std::string>& liveGuids,
const std::set<std::string>& parkedGuids) {
const std::set<std::string>& visibleGuids) {
std::vector<SoloOp> ops;
for (const auto& [guid, value] : cached) {
if (liveGuids.count(guid) == 0) continue;
if (parkedGuids.count(guid) != 0) continue;
if (visibleGuids.count(guid) == 0) continue;
ops.push_back(SoloOp{guid, value});
}
return ops;
+9 -5
View File
@@ -73,14 +73,18 @@ private:
// The incoming mode's restore writes, in GUID order. Two kinds of entry are dropped
// rather than written:
// * a GUID absent from `liveGuids` — the track is gone (same prune rule as above);
// * a GUID parked in the incoming mode — a parked track is hidden and carries
// B_MAINSEND=0, so soloing it would silence the whole mix while contributing
// nothing audible, and the user would have no visible control to undo it.
// * a GUID absent from `visibleGuids` — not visible in the incoming mode, whether
// because the leaf is parked or because it is a folder parent that is itself
// derived-invisible there. Either way the track is hidden and (for a parked
// leaf) carries B_MAINSEND=0, so soloing it would silence the whole mix while
// contributing nothing audible, and the user would have no visible control to
// undo it. A show-both leaf is a member of every mode's visible set, so it is
// never dropped by this rule.
// The caller consumes the whole mode entry regardless (clear-on-restore), so a
// dropped entry does not linger as zombie state waiting on a track that may never
// come back unparked.
// become visible again.
std::vector<SoloOp> planSoloRestore(const std::map<std::string, int>& cached,
const std::set<std::string>& liveGuids,
const std::set<std::string>& parkedGuids);
const std::set<std::string>& visibleGuids);
} // namespace reasampler::view