fix(matrix): no baseGrid leak in evolve one-shot
CI build oscope-of / build-check (push) Has been cancelled

When the evolve toggle is OFF, ~matRelanceEvolve now snapshots
~matBaseGrid, mutates once, then restores it to nil. When ON it
keeps the persistent base and re-mutates from it. Fixes stale-
snapshot corruption across preset loads. Case I added to harness.
This commit is contained in:
L'électron rare
2026-06-30 12:19:14 +02:00
parent 8ed0365309
commit cadbced958
2 changed files with 20 additions and 2 deletions
+7 -2
View File
@@ -407,10 +407,15 @@ File.exists(~matDir).not.if({ ("mkdir -p " ++ ~matDir.quote).systemCmd });
});
};
// one mutation from a base snapshot + re-source (the evolve one-shot)
// one mutation + re-source (the evolve one-shot). When the evolve toggle is
// OFF, snapshot/mutate/discard so ~matBaseGrid (owned by the toggle: non-nil
// iff evolve active) is never leaked across a preset load. When ON, keep the
// persistent base and just re-mutate from it.
~matRelanceEvolve = {
~matBaseGrid.isNil.if({ ~matBaseGrid = ~lp[\matrix].collect({ |row| row.copy }) });
var hadBase = ~matBaseGrid.notNil;
hadBase.not.if({ ~matBaseGrid = ~lp[\matrix].collect({ |row| row.copy }) });
~matEvolveStep.();
hadBase.not.if({ ~matBaseGrid = nil });
~matVoices.size.do { |i| ~matLastColor[i] = -1 };
(~lp[\matPlaying] == true).if({ ~matApplyBar.(~lp[\matBar] ? 0) });
};
@@ -67,6 +67,19 @@ feat.load;
(~matGlobalActions == [\evolve, \breakdown, \fill, \drop]).not.if({ pass = false; "FAIL: globalActions not round-tripped".postln });
("rm -f '" ++ (~matDir +/+ "zz_gact_test.matrix") ++ "'").systemCmd;
// -- I: evolve one-shot must not leak ~matBaseGrid when the toggle is off,
// and must mutate from the CURRENT grid (not a stale snapshot) --
~matEvolve = false; ~matBaseGrid = nil;
~lp[\matrix] = Array.fill(~matVoices.size, { Array.fill(~matBars, 0) });
~lp[\matrix][0][0] = 3; // gridA: kick bar0 active
~matRelanceEvolve.();
(~matBaseGrid.isNil).not.if({ pass = false; "FAIL: evolve one-shot leaked baseGrid".postln });
~lp[\matrix] = Array.fill(~matVoices.size, { Array.fill(~matBars, 0) });
~lp[\matrix][1][5] = 2; // gridB: hats bar5 active
~matRelanceEvolve.();
(~lp[\matrix][0][0] == 0).not.if({ pass = false; "FAIL: stale gridA cell resurrected by evolve".postln });
(~lp[\matrix][1][5] > 0).not.if({ pass = false; "FAIL: gridB active cell lost by evolve".postln });
pass.if({ "GLOBALACT PASS".postln }, { "GLOBALACT FAIL".postln });
0.exit;
)