dont stop assignments for help rovers, just allow people to leave them.

This commit is contained in:
legop3
2026-09-12 18:58:32 -04:00
parent 6a914faffb
commit ba5c1c5d25
2 changed files with 46 additions and 0 deletions
@@ -184,6 +184,11 @@ function createRoverLifecycle(deps) {
const currentRecord = rovers.get(currentId);
if (!currentRecord) return { ok: true, currentId };
if (hasOtherDrivers(currentRecord, socket.id)) return { ok: true, currentId };
// HELP means the normal dock-before-leaving requirement has failed to
// resolve the rover's situation and a person may need to take a different
// rover instead. This exception changes departure only; request eligibility
// and automatic assignment ranking remain owned by their existing paths.
if (currentRecord.needsHelp) return { ok: true, currentId };
if (isDockedAndCharging(currentRecord)) return { ok: true, currentId };
return { ok: false, currentId, message: 'Dock and charge your current rover before switching.' };
}
@@ -57,3 +57,44 @@ test('removing a rover clears driver sets, reverse membership, rooms, and turns'
{ socketId, roverId, action: 'remove' },
]);
});
test('the last driver may leave an undocked HELP rover but not an ordinary undocked rover', () => {
const roverId = 'rover-help';
const socketId = 'driver-help';
const socket = { id: socketId };
const record = {
id: roverId,
drivers: new Set([socketId]),
needsHelp: false,
// A present but explicitly non-charging frame exercises the real policy
// boundary instead of accidentally passing through missing rover state.
lastSensor: {
decoded: {
chargingSources: { homeBase: false },
chargingState: { code: 0 },
},
},
};
const lifecycle = createRoverLifecycle({
io: { sockets: { sockets: new Map() } },
rovers: new Map([[roverId, record]]),
socketToRovers: new Map([[socketId, new Set([roverId])]]),
managerEvents: new EventEmitter(),
turnService: {},
isAdmin: () => false,
sendAlert: () => {},
ALERT_COLOR: '#000000',
getMode: () => 'public',
getControlDenialReason: () => null,
});
const ordinaryResult = lifecycle.canLeaveCurrentRover(socket);
assert.equal(ordinaryResult.ok, false);
assert.equal(ordinaryResult.message, 'Dock and charge your current rover before switching.');
// Mutating only the server-owned HELP flag proves that no docking, driver,
// role, or assignment condition is being weakened as part of the exception.
record.needsHelp = true;
const helpResult = lifecycle.canLeaveCurrentRover(socket);
assert.deepEqual(helpResult, { ok: true, currentId: roverId });
});