fix(turn): log reorder + deathSave (BUG-7)
reorderParticipants returned log:null → handler skipped logAction → drag
invisible in combat log, no undo payload. Now returns
log:{ message, undo:{ participants, turnOrderIds, currentTurnParticipantId }}.
App.js handleDrop calls logAction on logged reorders.
Found second gap: deathSave also returned null log (both branches).
Fixed — message + undo (participants snapshot).
Added logging contract test (turn.logging.test.js):
- all mutating ops logged (start/next/pause/add/remove/toggle/hp/deathsave/
condition/reorder/end)
- no-ops return null log (same-id, cross-init, cross-pointer blocks)
- undo payloads valid + restore prior state
- documents addParticipants + updateParticipant gaps (null log, intentional)
235 tests green.
This commit is contained in:
+25
-3
@@ -477,6 +477,8 @@ function deathSave(encounter, participantId, saveNumber) {
|
||||
if (!participant) throw new Error('Participant not found.');
|
||||
const currentSaves = participant.deathSaves || 0;
|
||||
const newSaves = currentSaves === saveNumber ? saveNumber - 1 : saveNumber;
|
||||
const name = participant.name;
|
||||
const undo = { participants: encounter.participants || [] };
|
||||
|
||||
if (newSaves === 3) {
|
||||
// Mark dying — caller waits for animation, then calls removeParticipant.
|
||||
@@ -485,7 +487,10 @@ function deathSave(encounter, participantId, saveNumber) {
|
||||
);
|
||||
return {
|
||||
patch: { participants: updatedParticipants },
|
||||
log: null,
|
||||
log: {
|
||||
message: `${name} failed 3 death saves — dying`,
|
||||
undo,
|
||||
},
|
||||
isDying: true,
|
||||
};
|
||||
}
|
||||
@@ -493,7 +498,14 @@ function deathSave(encounter, participantId, saveNumber) {
|
||||
const updatedParticipants = (encounter.participants || []).map(p =>
|
||||
p.id === participantId ? { ...p, deathSaves: newSaves } : p
|
||||
);
|
||||
return { patch: { participants: updatedParticipants }, log: null, isDying: false };
|
||||
return {
|
||||
patch: { participants: updatedParticipants },
|
||||
log: {
|
||||
message: `${name} death save: ${newSaves}/3`,
|
||||
undo,
|
||||
},
|
||||
isDying: false,
|
||||
};
|
||||
}
|
||||
|
||||
// TOGGLE_CONDITION — verbatim from ParticipantManager.toggleCondition
|
||||
@@ -553,7 +565,17 @@ function reorderParticipants(encounter, draggedId, targetId) {
|
||||
const newTargetIndex = participants.findIndex(p => p.id === targetId);
|
||||
participants.splice(newTargetIndex, 0, removedItem);
|
||||
const turnUpdates = syncTurnOrder(participants); // 1-list: always mirror
|
||||
return { patch: { participants, ...turnUpdates }, log: null };
|
||||
return {
|
||||
patch: { participants, ...turnUpdates },
|
||||
log: {
|
||||
message: `${removedItem.name} reordered before ${(participants.find(p => p.id === targetId) || {}).name || targetId}`,
|
||||
undo: {
|
||||
participants: encounter.participants || [],
|
||||
turnOrderIds: encounter.turnOrderIds || [],
|
||||
currentTurnParticipantId: encounter.currentTurnParticipantId ?? null,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// END_ENCOUNTER — verbatim from InitiativeControls.confirmEndEncounter
|
||||
|
||||
Reference in New Issue
Block a user