B2.3: migrate MGC to LatestWinsGate.fireAndWait

specificClass.js 319 → 311 lines. Removed inline _dispatchInFlight +
_delayedCall + finally block. handleInput is now a 1-line delegate
to DemandDispatcher.fireAndWait({source, demand, ...}).
turnOffAllMachines calls _demandDispatcher.cancelPending().
DemandDispatcher 39 → 53 lines. One integration test rewritten to
use the new sentinel-resolution semantics. 77/77 tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
znetsixe
2026-05-11 17:29:18 +02:00
parent 0e8cab5d3f
commit 31324ae82d
3 changed files with 48 additions and 29 deletions

View File

@@ -116,16 +116,27 @@ test('repeated turnOffAllMachines reaches idle (serializes concurrent shutdowns)
'delayedMove must be cleared after shutdown');
});
test('turnOffAllMachines clears MGC._delayedCall to cancel any deferred dispatch', async () => {
test('turnOffAllMachines cancels any parked demand so it cannot re-engage pumps', async () => {
// PS sends a 1% keep-alive while MGC is mid-dispatch. MGC parks it in
// _delayedCall. PS then crosses stopLevel and calls turnOffAllMachines.
// Without clearing _delayedCall, MGC's finally block fires the parked
// 1% call AFTER the shutdown — re-engaging the pump.
// its demand dispatcher's latest-wins slot. PS then crosses stopLevel
// and calls turnOffAllMachines. Without cancelPending(), the parked
// 1% call would fire AFTER the shutdown — re-engaging the pump.
const { mgc } = buildGroup();
mgc._delayedCall = { source: 'parent', demand: 1, powerCap: Infinity, priorityList: null };
const gate = mgc._demandDispatcher._gate;
// Pin a fake in-flight dispatch then park a pending call behind it.
gate._inFlight = true;
const parked = mgc.handleInput('parent', 1, Infinity, null);
await mgc.turnOffAllMachines();
assert.equal(mgc._delayedCall, null,
'turnOff must cancel any deferred dispatch so it cannot re-engage pumps post-shutdown');
// Re-open the gate: the in-flight pin is artificial. Awaiting the
// parked promise must yield the SUPERSEDED sentinel (i.e. it was
// cancelled, not run).
const res = await parked;
assert.ok(res && res.superseded === true,
'parked demand must resolve as superseded after turnOffAllMachines cancels it');
// Idle now — pending slot must be clear.
assert.equal(gate._pending, null,
'turnOff must cancel any parked demand so it cannot re-engage pumps post-shutdown');
gate._inFlight = false;
});