@@ -311,6 +311,45 @@ access(all) fun test_supervisor_executed() {
311311 Test .assertEqual (2 , evts .length )
312312}
313313
314+ /// Regression test for FLO-27: if a paid rebalancer is deleted without removing its UUID from
315+ /// the Supervisor's set, the next Supervisor tick must NOT panic. Before the fix,
316+ /// fixReschedule(uuid:) force-unwrapped borrowRebalancer(uuid)! which panicked on a stale UUID,
317+ /// reverting the whole executeTransaction and blocking recovery for all other rebalancers.
318+ access (all ) fun test_supervisor_stale_uuid_does_not_panic () {
319+ // Get the UUID of the paid rebalancer created during setup.
320+ let createdEvts = Test .eventsOfType (Type <FlowALPRebalancerv1 .CreatedRebalancer >())
321+ Test .assertEqual (1 , createdEvts .length )
322+ let created = createdEvts [0 ] as ! FlowALPRebalancerv1 .CreatedRebalancer
323+
324+ // Register the UUID with the Supervisor so it will call fixReschedule on it each tick.
325+ addPaidRebalancerToSupervisor (signer : userAccount , positionID : created .positionID , supervisorStoragePath : supervisorStoragePath )
326+
327+ // Delete the paid rebalancer WITHOUT removing its UUID from the Supervisor — this leaves a
328+ // stale UUID in the Supervisor's paidRebalancers set, simulating the FLO-27 bug scenario.
329+ deletePaidRebalancer (signer : userAccount , paidRebalancerStoragePath : paidRebalancerStoragePath )
330+
331+ // Advance time to trigger the Supervisor's scheduled tick.
332+ Test .moveTime (by : 60.0 * 60.0 )
333+ Test .commitBlock ()
334+
335+ // The Supervisor must have executed without panicking. If fixReschedule force-unwrapped
336+ // the missing rebalancer the entire transaction would revert and Executed would not be emitted.
337+ let executedEvts = Test .eventsOfType (Type <FlowALPSupervisorv1 .Executed >())
338+ Test .assert (executedEvts .length > = 1 , message : " Supervisor should have executed at least 1 time" )
339+
340+ // The stale UUID must have been pruned from the Supervisor's set.
341+ let removedEvts = Test .eventsOfType (Type <FlowALPSupervisorv1 .RemovedPaidRebalancer >())
342+ Test .assertEqual (1 , removedEvts .length )
343+ let removed = removedEvts [0 ] as ! FlowALPSupervisorv1 .RemovedPaidRebalancer
344+ Test .assertEqual (created .positionID , removed .positionID )
345+
346+ // A second tick should not emit another RemovedPaidRebalancer — the UUID was already cleaned up.
347+ Test .moveTime (by : 60.0 * 60.0 )
348+ Test .commitBlock ()
349+ let removedEvts2 = Test .eventsOfType (Type <FlowALPSupervisorv1 .RemovedPaidRebalancer >())
350+ Test .assertEqual (1 , removedEvts2 .length )
351+ }
352+
314353access (all ) fun test_supervisor () {
315354 Test .moveTime (by : 100.0 )
316355 Test .commitBlock ()
0 commit comments