Replay (scripts/combat/replay.js):
- Merchant now type=npc via asNpc (was stale isNpc)
- Death-save eligibility keyed on type (character|npc), not removed isNpc
- Rotate outcomes success/fail/nat1/nat20 (was success-only)
- Import stabilizeParticipant, reviveParticipant
- Between-round revive: dead -> reviveParticipant, stable -> heal,
inactive -> reactivate (heal was no-op on dead, leaving active-dead monsters)
- Fix deathSave return unwrap: it returns {enc, status}; callStep runner
must extract .enc or state corrupts (round undefined, combat auto-ends)
- describe() fix: death-save arg is outcome, not type
Scenario (src/tests/Combat.scenario.test.js):
- Import stabilizeParticipant, reviveParticipant
- applyDamage accepts options (crit at 0 HP)
- Add stabilizeAction, reviveAction helpers
- addAllCharacters now actually exercises batch add (was no-op)
- New deterministic edge-case test: monster death (dead+inactive),
NPC nat20, NPC nat1+damage+revive+heal, character stable->damage->crit,
massive damage
scripts/
Dev orchestration + manual demo tool. NOT test.
dev-start.sh / dev-stop.sh
Local dev stack: backend (:4001, sqlite) + frontend (:3999, server mode).
One command. Writes env vars for you. Logs to tmp/server.log, tmp/fe.log.
./scripts/dev-start.sh # start (idempotent: leaves running ports as-is)
./scripts/dev-stop.sh # stop both
replay-combat.js
Live backend demo. Drives full combat via server adapter (same contract as App). Player display live-updates. Watch UI react to state changes.
# start backend + frontend first (see docs/DEVELOPMENT.md)
node scripts/replay-combat.js [rounds] [delayMs]
# defaults: 100 rounds, 200ms/step
Coverage per round: damage, heal, all 22 conditions, toggleActive, removeParticipant, addParticipant (reinforcements), updateParticipant, pause/resume, reorderParticipants, endEncounter. Revives dead each round to sustain full round count.
See also
tests/audit/— exploratory bug-finders (manual run, non-deterministic){shared,server,src}/tests/— jest unit/integration/characterizationscratch/— gitignored throwaway