Commit Graph

10 Commits

Author SHA1 Message Date
david raistrick c90fc6ffb0 tests: M4 dead-participant skip RED (4 tests, turn.dead-skip.test.js)
Desired behavior locked:
- dead PC not removed from turnOrderIds
- dead PC turn still comes up (nextTurn visits them)
- dead PC on their turn can deathSave
- dead PC not auto-set isActive=false by applyHpChange

All 4 RED on current code. Root cause: nextTurn filters isActive,
applyHpChange sets isActive=false on death, computeTurnOrderAfterRemoval
drops dead from turnOrderIds.

TODO BUG-3/M4 updated with test refs.
2026-06-30 13:57:55 -04:00
david raistrick be481767f0 tests: undo roundtrip (10 green) + reorderParticipants BUG-7 candidate
turn.undo.test.js: every op with log.undo roundtrips to prior state.
startEncounter, nextTurn, togglePause, applyHpChange, toggleCondition,
toggleParticipantActive, addParticipant, removeParticipant, endEncounter.

Found: reorderParticipants returns log:null. Cannot undo. Documents as
BUG-7 candidate (test green now, asserts current behavior).
2026-06-30 13:50:48 -04:00
david raistrick bac94d85ff tests: reorderParticipants characterization + BUG-6 RED
turn.reorder.test.js: 4 green (swaps, throws-diff-init, throws-missing-id,
documents current no-turnOrderIds-touch) + 1 RED (BUG-6: should update
turnOrderIds to reflect new order).

Found: reorderParticipants changes participants[] array but not turnOrderIds.
nextTurn rotates via turnOrderIds only → mid-combat drag-drop = no effect.
replay-combat.js calls with wrong signature (swallowed by try/catch), so
real path never exercised either.

TODO: BUG-6 added.
2026-06-30 13:49:38 -04:00
david raistrick 08c6146cf7 tests: turn.combat.test.js (deterministic RED for BUG-5), deprecate audits
REAL test audit should have been. jest, seeded RNG, mirrors replay-combat.js
op sequence exactly. Asserts per-round invariants: rotation-dupe, turnOrder
dup-id, currentTurn valid+active, HP bounds.

Result: 13 rotation-dupes / 100 rounds. First at round 4 (Cleric twice).
Deterministic, reproducible every run. BUG-5 locked.

Deprecate tests/audit/*.js: random sim gave false 0-violations while
this exact test reproduces bug. Commented early-return. Kept for reference,
delete later when log analyzer + unit tests cover ground.

TODO: BUG-5 added (mid-round addParticipant/revive corrupts rotation).

Root cause hypothesis: computeTurnOrderAfterAddition appends id to
turnOrderIds end. Round wrap re-sorts by initiative. currentTurn pointer
stale after sort → drifts → nextTurn revisits.

Test RED by design (documents live bug). Pre-push will block on push.
2026-06-30 12:33:56 -04:00
david raistrick d35a730e12 fix(turn): BUG-2 addParticipant rejects duplicate id
Root cause: addParticipant appended participant to participants[] without
checking id uniqueness. Two participants with same id in array. On
togglePause resume, turnOrderIds rebuilt via sort → dup id appears twice.
nextTurn then stuck repeating that id (rotation breaks).

This was the enabling step for BUG-1's full corruption (audit chain):
  pause blocks advance → totalTurns frozen → addParticipant re-adds
  same r${totalTurns} id → resume dup → nextTurn stuck.

Fix: throw on duplicate id in addParticipant. Caller must use fresh id
(crypto.randomUUID in App, replay already does).

Evidence:
- Test: 'addParticipant rejects duplicate id' (was test.skip, now live).
- Pre-fix: 1 RED (Received function did not throw).
- Post-fix: 50 green (shared), 23 green (server), 62 green (FE).
- Reachability in normal app: low (App uses crypto.randomUUID) but no
  guard existed before. Defensive + unblocks BUG-1 isolation.

No other behavior changed.
2026-06-29 16:25:39 -04:00
david raistrick 2756b7b3eb tests: skip dup-id test (BUG-2, see TODO), enable clean push
test.skip preserves the test + its comment documenting BUG-2. Re-enable
(remove .skip) when fix lands.
2026-06-29 16:03:03 -04:00
david raistrick f81308a0df tests: consolidate into tests/ dirs, fix import paths
Move all test files out of source dirs into per-workspace tests/:
- shared/tests/   (3 unit test files)
- server/tests/   (1 integration test)
- src/tests/      (8 characterization + scenario tests + testHelpers)

Fix all relative import paths (App, storage, __mocks__, testHelpers).
Fix jest.config testMatch globs in shared/ and server/ (rootDir +
<rootDir>/tests pattern).

Delete scripts/repro-pause-bug.js (debug scratch, superseded by
turn.pause-add.test.js).

Keep scripts/replay-combat.js + scripts/audit-rotation.js as manual
demo/exploratory tools (NOT unit tests, not deterministic).

No logic changes. All green: shared 49 + 1 validated RED, server 23,
FE 62. Scenario test unchanged (240s timeout, pre-existing slow).
2026-06-29 16:02:22 -04:00
david raistrick 33e0e52789 tests: pause-add rotation corruption + dup-id, log bugs to TODO
- turn.pause-add.test.js: 3 tests isolating addParticipant+pause/resume
  interaction. Clean minimal repro passes (bug needs more state than
  single add+pause). Audit authoritative repro.
- turn.characterization.test.js: RED 'addParticipant rejects duplicate id'.
  Validates current allow-dup behavior.
- TODO.md: BUG-1 (add+pause rotation corruption, 32/100 audit violations),
  BUG-2 (dup id allow). Both confirmed real, NOT fixed.

Audit bisect: dmg+heal+cond+toggle+remove+add+pause = 32 violations.
add+pause alone = 0. Combo needs full state.

No feature code changed.
2026-06-29 15:52:17 -04:00
david raistrick 13490fe3de tests: round-rotation audit, dup-id fail, replay rewrite
- turn.round-rotation.test.js: 7 tests, full round visits each active
  participant once (pure nextTurn clean). Green.
- turn.characterization.test.js: RED 'addParticipant rejects duplicate id'.
  Validates current behavior allows dup ids (self-inflicted in audit via
  loop spin-while-paused re-adding same id; unreachable in app via
  crypto.randomUUID, but documents gap).
- audit-rotation.js: pure turn.js simulation of replay op sequence.
  Detects rotation violations (skip/dupe per round). Pause disabled = 0
  violations across 100 rounds. Pause enabled = 56-77 violations starting
  round 20. Pinpoints addParticipant+pause interaction.
- repro-pause-bug.js: minimal repro scripts.
- replay-combat.js: rewritten for real rounds (full initiative cycles),
  visible damage each turn, all conditions, toggleActive, remove,
  reinforce, edit, pause/resume, reorder, endEncounter. HP bumped for
  100-round sustain + revive dead each round.

No feature code changed.
2026-06-29 15:49:39 -04:00
david raistrick e06adaa081 M1: shared turn logic + characterization tests (39 green)
- npm workspaces: shared/, server/
- shared/turn.js: port turn logic verbatim from App.js (bugs preserved)
- 39 characterization tests lock current behavior
- gitignore: sqlite data, logs
2026-06-28 16:57:43 -04:00