Commit Graph
56 Commits
Author SHA1 Message Date
Eric WagonerandClaude Fable 5 b4adb97536 The mid-round democratic monster claws when its turn comes
Every creature is born with attackUsed spent — the right way to say
"cannot attack the turn created" for monsters whose flag refreshes
next turn. But the democratic monster's flag budgets its ROUND, so a
mid-round summon arrived pre-spent and bumped harmlessly until the
round rolled over. Creation-turn pacifism now rides justCreated
alone for the monster (checked at the touch), and its round-claw
starts live — folded into rev 18 with the boundary refresh.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 16:53:28 -04:00
Eric WagonerandClaude Fable 5 3b0aa01867 Rev 18: the democratic monster's claw outlives the first wizard
Its one-attack-per-round refreshed inside beginTurnFor when the turn
index matched the roll-off winner's seat — and only the living begin
turns, so once that wizard fell the claw never refreshed again: one
attack, then a lifetime of harmless bumping. The refresh now lives at
the true round boundary in the turn-advance loop, which passes dead
seats without skipping the count. Earlier ledgers keep their gummed
monster and replay so.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 16:51:44 -04:00
Eric WagonerandClaude Fable 5 d89d995daf The sector ghost slides where the sector actually went
The relocation flourish corrected its coordinates against the view —
but effects are mapped when the events arrive, one message before
the new state, so the correction read the PRE-move board and the
ghost slid between unrelated squares. The sectorRelocated event now
carries its origins in final coordinates, computed after the maze
renormalizes, and the flourish trusts the event alone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 16:48:20 -04:00
Eric WagonerandClaude Fable 5 e57307efbe Rev 17: the wave carries monsters as it carries wizards
Stone to Water's wave (and every waterwall collapse) washed wizards
back and crushed them against the maze — while a skeleton in the
same water stood dry. The wave only knew creatures well enough to
drown fire imps. From rev 17 it carries them all: washed back along
the surge, one point of crush per space the maze refuses, fire imps
still destroyed outright. Earlier ledgers keep their dry monsters
and replay so.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 15:07:34 -04:00
Eric WagonerandClaude Fable 5 aef88d892a Two treasures, one square: the taker names their prize
pickUpTreasure grabbed whichever treasure the list offered first —
with two on a square, no choice and sometimes the wrong one. The
command now takes an optional treasureId (absent in every stored
ledger, so old replays keep their old grab), and when the square
holds more than one, the button asks "whose?" before dispatching.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 15:03:34 -04:00
Eric WagonerandClaude Fable 5 794b809a1b Swapping homes stops announcing a body swap
SWAP HOME BASES traded homes correctly but borrowed the
positionsSwapped event, so the chronicle claimed the wizards
themselves changed places. It now speaks its own event — "swap home
bases — the maze's loyalties shift!" — and both hearths shimmer as
their allegiance changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 15:01:07 -04:00
Eric WagonerandClaude Fable 5 e7c8ddc0b3 Creatures walk open doorways, and the interruption gets its fanfare
Player movement asked the full question of a door — removed, keyed
this turn, or held — while creature movement only saw "door" and
refused, so a skeleton balked at a doorway its master had unlocked
for good. One doorIsOpen() now answers for both, and an open doorway
costs a wraith none of its wall passes.

And the interruption window earns the modal it deserved: "The maze
holds its breath" — the card shown, the instruction plain, dismissed
with "Seize it". No more hunting the rail for a slip while time
stands parted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 13:50:38 -04:00
Eric WagonerandClaude Fable 5 94ec714e35 Rev 16: empathy mirrors the blows that resolve by their own hand
A believed ILLUSIONARY ATTACK, the goat's ram, and the hurled
treasure all deal their damage inside the attack's own resolution
hook — past the pipeline where the empathy mirror lived, so a linked
caster walked away unbloodied. One resolvedBlow helper now carries
the mirror to all three: "any attack done in ANY form" means these
too. Rev-gated: proactive empathy predates this, so stored ledgers
may hold unmirrored blows and replay them as struck.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 13:37:37 -04:00
Eric WagonerandClaude Fable 5 89ba225fe5 Illusions show their face, and empathy answers the call
An automaton's ILLUSIONARY ATTACK arrived as a mystery: the modal
showed only the illusion card, never the spell being faked — though
the stack has always carried it face-up. The defender now sees both
cards side by side, the caption names the fake ("an ILLUSIONARY
Fireball — it bites only if believed"), and the hint bar says which
spell to weigh a counter against.

And EMPATHY — corner: COUNTERACTION — was refused at the door like
INVISIBLE before it, while the automatons' own counter ladder had
been reaching for it and silently failing into the fallback all
along. It now raises mid-stack: the blow lands on both wizards, the
link lingers for its NUMBER card's turns, and ANTI-ANTI severs it
cleanly (empathy is no escape). The number-riding-a-counter idiom is
one shared helper now. Permissive both ways: no stored ledger
contains either play, so no rev gate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 13:33:24 -04:00
Eric WagonerandClaude Fable 5 adf463effa Rev 15: the held doorway carries sight — the whole point of holding it
The table holds doors open to cast back through them at pursuers;
our held door opened for feet but not for eyes. From rev 15 a held
door is an open doorway to sight — casting at players, creatures,
and squares sees through it, the client's dimming aid and the
automatons alike (they share sightedCellsFor). REMOVE LOCK's "still
considered to block L.O.S." stands: that speaks of a CLOSED door,
and an unheld unlocked door still blocks. Rev-gated because rev-14
ledgers may already contain holds and must replay blind.

Pinned three ways: the holder blasts a pursuer through the held
doorway; an unheld unlocked door still blocks; rev 14 stays blind.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 13:20:45 -04:00
Eric WagonerandClaude Fable 5 a0c65413ef The door can be held open, as both key cards always promised
MASTER KEY and PICK LOCK each read: "You may 'hold the door open' for
others, if you wish" — and the engine always slammed it at end of
turn. Now the cast takes a hold param: the door stays unlocked past
the turn, for anyone, as long as its holder stands adjacent and
alive. A step away, a shove, a teleport, or a killing blow lets it
swing shut — swept after every command, since anything can move a
wizard. New state, new param: no old ledger contains either, so no
rev gate is needed.

The client offers a "hold the door open" checkbox when either card is
selected; a held door shows pale with a green jamb ("held open by a
standing wizard"), and the chronicle records the holding and the
shutting. Pinned: a held door outlives the turn and admits the other
wizard; walking away releases it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 13:15:57 -04:00
Eric WagonerandClaude Fable 5 d2b40ec6f8 Credibility pass: the seams get sanded
Scoped to everything since the last pass (3308850). Three blind
reviews, every finding verified before touching anything.

Confirmed and fixed: two identical comment-splitting insertions left
doc comments orphaned from their fields (net and local alike); a
51-line CSS fossil of the pre-extraction inline effects survived in
Board.svelte; the rev-13 miss-roll test asserted tautologies while
its comment claimed a check the code never made — it now proves the
die was consumed, and the skeleton is no longer returned as trollId;
the sprite registry's `as never` silently disabled the completeness
its annotation advertised (now a mapped type, one cast at the
dispatch seam); a dead ternary guarded a union that doesn't exist;
Bolt carried a duplicate .fork rule from a color iteration; fxTtl
contradicted three sprites' real animation lengths; the permanence
sentinel was reinvented as a magic 9000 (the engine now exports
isPermanentDuration); CELL was declared thrice (fx.ts now imports
it); App and Replay ran two divergent fx schedulers (one scheduleFx
now, cancellable — stale flourishes can no longer fire after leaving
a game); TokenArt retried missing files forever; the anti-anti
escape guards merge with the gate asymmetry explained; wall-of-fire's
rev-12 carve-out is marked; overLimit ignored a displayed BRAINSTONE
(bots over-discarded by two); botRemark's header mis-stated its own
branches; deliverGold fired on any drop, not a home-base delivery;
escape and win banter never fired from the steps that carry them.

Rejected: "as a human would" (house voice); FxGallery's dev-harness
framing (trimmed one plea, kept the facts).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 12:12:03 -04:00
Eric WagonerandClaude Fable 5 64709f6c9c Stone to water splashes like it means it
The transmutation fired no flourish: its event carried no coordinates
for the wall case and the mapper knew neither it nor the wave it
raises. The event now carries its edge; the burst splashes both sides
of the vanished wall (or the freed square, for a block), and every
wizard the collapsing wave carries leaves a wash streak — which also
gives the plain WATERWALL's wave its motion for free.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 10:47:42 -04:00
Eric WagonerandClaude Fable 5 d4565006bc Rev 14: elimination sweeps the board by either door
Two ways out of the game, one cleanup. A wizard killed by damage took
their monsters, sustained spells, and armed ambushes with them; a
wizard eliminated by treasure loss left everything standing — a fire
imp scorching for a dead master, a Medusa still gazing at a corpse.
Both paths now share one sweep, gated at rev 14 so stored games keep
their orphans acting as recorded.

Also: Lifesaver lasts until used, carried as a near-billion-turn
sentinel — which the scoresheet printed. Durations that mean forever
no longer show a number.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 22:27:14 -04:00
Eric WagonerandClaude Fable 5 e0da97627b Rev 13: monsters roll to hit the hidden — the invented exception dies
"The creature shares your square — there is nowhere to hide" appeared
on no card and in no rulebook. Neither did the convention beneath it:
the engine skipped INVISIBLE and SHRINK miss rolls for creature blows
on the theory that a monster in your square has nothing to aim. The
cards say otherwise — SHRINK reduces the chance to hit "in any
attack", and INVISIBLE's D4 carves out no exception for monsters.

From rev 13, creature blows roll the same dice as every other attack
(1 finds the unseen; 1-2 find the tiny), INVISIBLE may be counter-
cast against a creature's blow, and the automatons will do so. The
rolls consume RNG, so earlier games keep their certainty and replay
without them — the refusal survives only there, reworded to blame the
revision instead of inventing a rule.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 21:11:30 -04:00
Eric WagonerandClaude Fable 5 4d8584ae44 Rev 12: vanishing and water answer the call to arms
INVISIBLE's corner reads NEUTRAL/COUNTERACTION, and ANTI-ANTI's own
face names it an escape — yet the engine refused it at the door. Now
it counters: the vanishing goes up mid-stack (duration from a NUMBER
card riding the counteract command), the attacker's 1-in-4 hit roll
happens at resolution, the spell lingers after the exchange, and
ANTI-ANTI cannot pin it. WATERWALL — "Acts as counteraction to
FIREBALL" — now mirrors WALL OF FIRE's waterbolt-stopping role and
counts as a total stop. WALL OF FIRE itself joins the total-stop set
at rev 12 only: stored rev-10/11 games bounced after it and replay so.

While responding, tapping a number card holds it to ride the next
counter (unless a displayed Shieldstone makes the number itself the
counteraction, as before). The automatons learn the trick too: vanish
when the blow is heavy and the shields are spent, and never waste
ANTI-ANTI against an escape.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 21:07:47 -04:00
Eric WagonerandClaude Fable 5 fb2266b401 Mega-Monster offers its choice
"Doubles the existing life-points OR movement rate" — the engine
always took the OR's left side because the client never asked. With
Mega-Monster selected, the hint bar now offers the choice (hit points
lit by default), and the pick rides the cast as params.boost — its
own field, freeing params.cardId for the name-a-card spells it
belongs to. Both halves of the OR are pinned in the creature suite.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 20:56:49 -04:00
Eric WagonerandClaude Fable 5 3308850bb6 Credibility pass: sweep the workshop floor
Scoped to everything since the last pass (695307d). The residue of
fast iteration, removed: a reduced-motion media query that had
swallowed a full copy of the .faq-seal rules; doc comments orphaned
from their functions by inserted methods; the FAQ scrape's seams
(section headings run into ruling bodies under the wrong topics, a
next-page heading shipped as a ruling, an amputated "h", and rulings
filed under alphabetically-nearest strangers — Large Rock/Dagger now
lives on those cards; Book of Spells and Torquemada describe no card
in this set and are gone); the write-only aisle flag left behind by
the reverted rev 7; a linter-silenced dead destructure; a duplicated
median lookup; dead casts; and the fallback path that ignored the
apprentice's one-card draw.

Tests now typecheck (tsconfig includes test/), which surfaced the
missing type imports and a drifted creature literal hiding under an
as-cast. Also: a no-op self-assignment, mid-file imports hoisted, a
dynamic-import habit made static, a hedge comment replaced with a
loud setup failure, the fallback-retries-itself dead rung removed
from both bot drivers, and the twin peek scrims merged.

Deliberately kept: the TIERS lookup guard (ledger JSON is untrusted),
the wand-cost stanzas (they differ on the power-attack trade — a
rules question, not a dedup), and rollDie's coexistence with rollD4
(migrating changes visible logs; future work).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 20:20:37 -04:00
Eric WagonerandClaude Fable 5 73150a89b5 Rev 11: the maze has no wall at zero, and moving sectors carry everything
Relocate Sector could never land a sector west or north of the origin
— placements the physical game allows by simply sliding the whole map
across the table. The coordinate grid still cannot go negative, but
now it does not need to: a sector may land at negative coordinates
and the whole maze renormalizes, zero-anchoring on both axes (which
also pulls the maze snug when the origin corner is vacated, instead
of leaving a blank band). The client offers the new landings as ghost
slots on every side, verified slot-for-slot against engine truth.

The move also closes a real gap: remapState never carried creatures,
boobytrap tokens, glue, open safes, or dimensional warp tokens when a
sector relocated or rotated — they were left hovering at their old
coordinates. Sectors now carry everything standing on them. Both
changes ride rules rev 11; older ledgers replay their flaws intact,
as replay determinism demands.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 20:07:01 -04:00
Eric WagonerandClaude Fable 5 18d3142f95 Rev 10: a total stop ends the exchange, and the modal stops goading
Slow Death, countered with Force Field — and the battle modal popped
right back up as if nothing had happened, goading a second counter
out of a hand that had already won the exchange. The engine was
bouncing every attacker's pass back to the defender so counters could
stack; correct for partial stops (Blunt, Absorb, Reflection numbers),
senseless past a total one. Under rules rev 10, when a Full Shield,
Force Field, Teleport escape, Full Reflection, or Reverse stands
unnullified, the attacker's declined answer resolves the stack on the
spot. Older ledgers keep the bounce and replay unchanged.

And when the exchange legitimately returns — a partial counter
standing, or a shield broken by Anti-Anti — the modal now says so:
"Your Blunt stands — only what slips past it will land," or "Your
Full Shield was nullified — the attack comes on unchecked," instead
of replaying the fanfare of a fresh, unanswered attack.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 19:53:38 -04:00
Eric WagonerandClaude Fable 5 2c3e622ce5 Rev 9: REDIRECTION connects the exits you choose
Playtesting read the card right and the engine had it wrong. "Placing
the A tokens on one set of exits & the B tokens on the other" means
the two exits you mark BECOME a pair — and their former partners pair
with each other — not that the two exits trade destinations. Under
rev 9, click the exit and then the exit you want it to connect TO
(the hint now says so); already-connected exits are refused. Earlier
games keep the swap their logs were validated against. Test pins the
full four-way rewiring.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 16:40:35 -04:00
Eric WagonerandClaude Fable 5 5802e1df05 Table talk keeps its place in the chronicle
Live chat interleaved correctly, but a reload sank every past message
to the bottom: the rejoin sent the whole game history first and the
chat history after. Talk is now a tableTalk event in the room's event
stream at the moment it was said — the room file already preserved
the interleaving, since chat lines append between command lines — so
rejoining players read the banter between the battle lines where it
happened. The separate chatHistory message retires; unread counting
rides the event stream instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 16:00:51 -04:00
Eric WagonerandClaude Fable 5 ef661c79ad The die rolls in the open
Every player-facing D4 roll now lands in the chronicle as pips with
its purpose: "🎲 alice rolls a 3 — aiming at the unseen — only a 1
finds them." A shared rollD4 helper threads the generic dieRolled
event through blind staggers and swings, pit leaps, ooze and pit
struggles, and the invisible/shrink miss rolls — the table sees the
die land, exactly as it would in person. Rolls whose numbers already
showed (the troll's swing, the misdirection direction, the opening
roll-off) keep their lines.

And the physical die's other job — "any 50-50 call" — gets its
button: 🎲 beside the say-box in online games (server-rolled,
published through the chat ledger so it persists, replays, and counts
toward unread badges) and under the chronicle in hotseat, rolled on
the device. Chronicle only; no game state touched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 15:57:28 -04:00
Eric WagonerandClaude Fable 5 d6d34887e3 The whole punch list: rev 8, general FAQ, and four promoted UX items
Rules rev 8 closes the last two fidelity threads. A SPEED bonus turn
burns a turn of duration spells on the hastened wizard — recipient-
counted, per the FAQ's most obscure ruling — with self-cast durations
already burning through the normal turn-start sweep (expiry extracted
into expireEffect so both paths share the cleanup). And nothing can
be created on a DIMENSIONAL WARP token, as the card face always said.

The general-topic FAQ sections (Combat, Line of Sight, Monsters,
Treasures, and five more) join the rules tab verbatim under a double-
ruled divider, completing the FAQ's absorption: card rulings on the
cards, general rulings in the rules.

The four promoted UX items: cell-target spells now dim ineligible
squares (creations mirror emptySquareTarget from the viewer's
knowledge, summons want clear sighted squares, teleport BFSes its
four spaces exactly as the engine does, stone-to-water lights only
stone, dispel lights only creations); hotseat games get the full
replay reel, each step seen from its actor's own seat; a "stop
announcing attacks on this device" link in the fanfare modal (undo
lives beside the notification toggle in the lobby); the corner
inspector now serves only the selected casting card, with every
examine-a-card peek unified on the centered treatment; and the dev
socket URL keys on vite's port instead of hijacking every localhost.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 15:45:59 -04:00
Eric WagonerandClaude Fable 5 4833a229e1 The table's reading prevails: open sides carry sight
An hour of rules archaeology, summarized: DIMENSIONAL WARP denies
LOS explicitly (its tokens stay sightless); the AUTO WARP describes
how to trace sight across a join; and on the lettered wraparounds
the texts are silent — no grant, no denial. The FAQ's Permawarp
rulings even have area effects counting distance through warps. Where
the texts are silent, the edition's own table breaks the tie, and the
table says the open sides see. Board openings carry sight in every
revision (a permissive change: every stored game's log replays
clean); the brief rev-7 restriction and its legacy flag are gone,
along with the sophistry that justified them. The adjacency geometry
stands. The friend's sticky-wand shot through the C opening was legal
after all.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 15:29:09 -04:00
Eric WagonerandClaude Fable 5 493f3bc567 Rev 7: sight passes only through the aisle warps
The cards settle what the morning's feature got wrong. DIMENSIONAL
WARP: "There is no L.O.S. through the warp." The AUTO WARP: "for all
purposes, treat the connected board edges as though they are
adjacent" — an explicit grant, for edges that physically meet at a
corner. The lettered wraparounds get no grant at all: their rule is
about walking. So the pattern is that warps carry movement, not
sight, unless the text says otherwise — and only the aisle corners
say otherwise.

Warps now carry an aisle flag (the 3-player AUTO WARP and the
5-player corner arcs); hasWarpLineOfSight honors only those, with
the adjacency geometry — diagonals through the corner mouth —
unchanged from this morning where it rightfully applies. Games begun
before rev 7 keep the wider sight their logged commands were
validated against, via a legacy flag boardView stamps from the
game's rules revision. Tests pin all three states: lettered mouths
see nothing, aisle mouths see the corner fan, legacy games see
everything they used to.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 15:25:00 -04:00
Eric WagonerandClaude Fable 5 de446c2ad5 Counteraction answers follow the FAQ: absorb reflections, not shields
"It's not letting me cast Absorb Spell on your Full Shield" — and
Jolly's FAQ says exactly why: "ABSORB SPELL will work on FULL
REFLECTION or REFLECTION, but not FULL SHIELD, as that is not used
against you, but cast upon the player using it." The refusal stands,
now with that reason in the error — and the neighboring case the
engine wrongly refused is fixed: an attacker may answer a reflection
with ABSORB SPELL, nullifying it and taking the reflection card into
their hand, with the original spell then landing unturned.

And the card face corrects my own hours-old work: ANTI-ANTI "does not
work against escape, such as SHRINK, TELEPORT, or INVISIBLE" — so
under rules rev 6 it can no longer pin a teleport escape. Earlier
games keep their stored chains.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 14:51:14 -04:00
Eric WagonerandClaude Fable 5 ed9585aa59 Five fidelity gaps closed: teleport escapes, slime traps, the Big Man
moves like a giant, and the boards are diagram-verified

TELEPORT as a counteraction (official FAQ: "the attack has no chance
of hitting you"): the defender names an escape square within four
spaces, the escape resolves before anything lands, and an ANTI-ANTI
pins their boots to the floor. Additive — no revision gate needed.

FILL SQUARE WITH SLIME holds spells now: an attack cast at the slime
sticks in the gel (leaving the discard pile), springs once at whoever
is inside or next enters, and counteractions against the trapped
blast cannot touch its caster — reflections vanish into the ooze. A
five-point waterbolt washes the slime and its cargo away, and the
waterwall waves clear slime from their path.

BIG MAN, under rules rev 5, finally moves like the card says: he
pushes players and monsters down the corridor ahead of him (stuck or
unpushable occupants block his advance), steps over a pit, tacks, or
killer ooze for two movement points without ever entering the square
(click two cells beyond the hazard), and monsters may not enter his
square. All gated so stored games replay under their own rules.

The boards were never wrong — the rulebook's Set-Up Diagram photo
confirms every pairing the code already had: 2p crossed, 3p stair
with the Aisle Warp arc, 4p/6p straight-across, 5p plus with all four
corner arcs. The stale TODOs are gone, replaced by tests pinning each
letter pair, and relocation's "only opposite board edges connect"
(which discards the aisle warp) is pinned too. Wall of Fire vs
Waterbolt turned out to be implemented and tested all along — its
TODO comment was the only thing wrong.

Also: hotseat saves now request durable storage (iOS evicts
unprotected origins under pressure).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 14:17:37 -04:00
Eric WagonerandClaude Fable 5 f00ef75fbd The chronicle names creatures, not their ids
"The creature-1 takes 2 damage" — the creature events carried only
internal ids, so the log printed them. creatureAttacked, Touched, and
Damaged now carry the creature's kind, and the lines read like a
table: "The Wraith strikes!", "The Troll swings (rolled 3)!", "The
Skeleton takes 2 damage."

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 13:30:02 -04:00
Eric WagonerandClaude Fable 5 d1eace9530 Rules rev 4: a creature's blow can be counteracted
The WRAITH card assumes the window exists — "REFLECTIONs used on the
wraith's touch will damage the wraith" — but creature damage applied
instantly, so BLUNT had nothing to catch, as playtesting found. Under
revision 4 every creature blow against a wizard opens the same
counteraction stack a spell does: the wraith's entry touch, the
democratic monster's claw, and commanded troll/skeleton/shadow
attacks. The blow's damage rides the stack; BLUNT halves it (round
up); reflections work by name against creatures — half back for
REFLECTION, the whole blow for FULL REFLECTION — landing on the
creature, not its controller; FULL SHIELD correctly does nothing
("does not stop any physical attack"); the wraith's card theft is a
secondary effect that lands only if damage does. No aim-miss rolls
against invisible or shrunk defenders — the creature is already in
the square. The attack fanfare shows the creature's own card.

Earlier revisions keep the instant touch so every stored game — and
the live one that found this — replays unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 13:25:45 -04:00
Eric WagonerandClaude Fable 5 b210cffa76 Zero-damage attacks stop lying about being stopped
DROP OBJECT resolved correctly — the treasure fell — but the
chronicle announced "The attack is completely stopped," because the
attackResolved event branded any attack that dealt zero damage as
stopped. Utility attacks deal zero by design; only an attack that was
TRYING to wound counts as stopped when nothing lands. Tests pin both
sides: uncountered DROP OBJECT reports unstopped and drops the
treasure; FULL SHIELD reports stopped and the treasure stays carried.

Not deployed — a live game is in progress.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 12:58:16 -04:00
Eric WagonerandClaude Fable 5 7e3e00bf97 Rules rev 3: Ward is a choice, Chaos honors the shield
WARD's text says "you may play at that time" — under rules revision 3
the choice is made by setting the trap: an armWard command toggles it
on your own turn (your secret; a private wardSet event and a rail
note), and the spring fires only while set, consuming the card and
the arming together. Async games keep their agency without an
interrupt window, exactly as the ambush system solved this before.

CHAOS gains its printed interactions: "FULL SHIELD removes a player
from participation" — a defender's shield sits them out instead of
stopping the spell, and after the counter chain every bystander gets
a shield window in seat order (chaosPending; queue head owes a
response in lobby summaries, the rail says whose hand hangs in the
balance) before the pile forms among the unshielded. "REFLECTIONS
have no effect" — both reflections are refused as counters. ABSORB
SPELL still eats the whole thing through the existing absorb path.

Both changes are frozen behind deckRev 3 so every stored game — and
the live one — replays byte-for-byte under its own rules. Five new
tests cover armed/unarmed wards, shielded defenders and bystanders,
the reflection refusal, and the legacy auto-ward.

Not deployed — a live game is in progress.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 12:55:58 -04:00
Eric WagonerandClaude Fable 5 41c384274d Walls and doors fall to sustained assault
"It is possible, though time-consuming, to punch a wall down. A wall
takes 20 points of damage to destroy; a door takes 15. Any attack
against an inanimate object counts as your one attack for the turn."
Damage accumulates per edge in wallDamage (remapped through sector
rotations, public in the view), fed two ways: a punchWall command for
the bare-fisted (1 point, from a square touching the edge) and attack
spells cast at an edge target — LOS to the wall for L.O.S. cards,
touching it for same-square cards, amplify and power-attack honored,
wand charges spent, no counteractions since stonework plays none.
Thrown daggers and rocks clatter to the floor at the foot of the
wall. At the threshold the edge opens through the same override path
destroy-wall uses.

On the table: damaged walls wear spreading cracks, an attack card's
hint offers "or a wall line to batter it" with the edge layer live,
and a "Punch a wall…" stamp arms a click-the-wall mode. The chronicle
counts the blows: "alice batters the wall with bare fists — 3/20."

Not deployed — a live game is in progress.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 12:48:49 -04:00
Eric WagonerandClaude Fable 5 64454ffc3e Sight travels through the wraparound openings
"If casting a spell, or checking line of sight through the AUTO WARP,
treat it as a straight line, and the two connected boards as though
they were adjacent" — and the lettered openings reconnect edges the
same way. hasWarpLineOfSight models it: the line must run straight
down the corridor, out one mouth, and in through the paired mouth,
with both corridor legs clear and neither mouth filled solid. The new
sightBetween (direct or through-a-warp) is now the game's LOS check
everywhere — spells, ambush triggers, Around The Corner, the
visionstone sweep, and the targeting dim on the client.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 12:43:57 -04:00
Eric WagonerandClaude Fable 5 efec82e88d Two-player decks shed LIFESAVER, as the card itself instructs
"Not applicable in a 2-player game." — the card face. New games deal
from deck revision 2, which removes it when exactly two wizards sit
down; three or more keep it. The revision travels in GameConfig and
the persisted start line, and stored games without one replay against
the original build — changing an existing game's deck composition
would scramble its deterministic replay. Test pins all three cases:
removed at two, present at three, present in legacy two-player games.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 12:07:28 -04:00
Eric WagonerandClaude Fable 5 695307daa8 Credibility pass: one voice, no scars
A three-reviewer sweep for tells of piecemeal machine generation,
every finding verified against the code before touching it. No
behavior changes; the full suite passes unchanged (plus two
strengthened pins).

Engine: removed four void-silenced fossils (a parseEdgeKey call
voided where it stood, stoneEffect's ignored cardId parameter, the
actualTarget remnant in doCast, a voided loop variable in shadow
upkeep); fixed the initialize-then-overwrite narration in
spawnCreature; replaced a filter(() => false) no-op; waterwall now
rides waveFromEdge instead of carrying its own verbatim copy (and the
single-caller washBack wrapper went with it); blind wall-bumps and
LOS blockers each collapsed to one implementation; the wand-id list
and the "permanent" duration sentinel became named constants; the
ambush number local no longer shadows the imported numberValue
function; assorted reviewer-aimed phrasings rewritten as the
constraints they guard.

Server/deploy: the protocol header now documents all eleven message
types; dropped an eslint pragma with no eslint, a test script with no
tests, and an rsync exclude anchored at a path that never existed
(the real data/ dir now excluded); the Caddy vhost has one source of
truth; stale "pending DNS" note removed — the record resolves.

Web: ~90 lines of CSS swallowed verbatim into a mobile media query
deduplicated; the reduced-motion guard on the board now actually
stops the marked-cell pulse; one shared color module replaces two
drifted palettes; an orphaned doc comment rejoined its function.

Tests: the ten-times-pasted helper block became test/helpers.ts;
wave-numbered files renamed for the behaviors they pin; deliberation
comments and void-ed corpses of unwritten assertions deleted; silent
seed-dependent early-returns now fail loudly; one assertion that
compared a value to itself now pins the home-translation it meant to;
the stored-log single-number command form gained the explicit
compatibility test it deserved.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 11:56:55 -04:00
Eric WagonerandClaude Fable 5 da4ab03135 The reveal remembers the hand a wizard fell holding
Elimination destroys the evidence: a killed wizard's cards pass to
the killer, a treasure-lost wizard's go to the discard — so the
post-game reveal showed "empty-handed" for exactly the player whose
hand everyone wants to see. Both elimination paths now snapshot the
hand at the moment of death (finalHand), the finished view serves it,
and the gallery marks those rows "as they fell" in script. Because
rooms replay from the command log, already-finished games show their
fallen hands too. Test kills a wizard holding a Fireball and a 6 and
finds them in the reveal.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 11:20:10 -04:00
Eric WagonerandClaude Fable 5 13aeeea0ef Victory gets its moment: a gold-ringed proclamation
Winning showed only as a small slip in the rail — anticlimactic, as
playtesting put it. The engine now records HOW the game was won
(winReason: treasures carried home, or last wizard standing) alongside
the winner, the view carries it, and the finish opens a gold-ringed
modal: trophy, the winner's name in tall caps, and the manner of
victory in a handwritten line. "Behold the final board" dismisses it
to the finished table. In hotseat the one screen proclaims to the
whole table at once; in async games each player is greeted by it when
they next open the game.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 11:11:24 -04:00
Eric WagonerandClaude Fable 5 4f3083c490 Targeting dims out-of-reach squares; Speedstone pays out immediately
Selecting an L.O.S. card now drops every square you cannot see into
shadow, leaving eligible targets lit — computed by the engine's own
hasLineOfSight over the player's VIEW, so illusion walls you still
believe in block your aim, stone and bushes and the Big Man block
everyone's, and Around The Corner widens the light one bend when
attached. ADJACENT cards light just your square and its four
neighbors. The shade paints over tokens and wizards alike, and
switches off while arming an ambush, since ambushes aim at the
future. A new sightedCellsFor lives in the engine view module so the
client can never disagree with the rules.

Speedstone, meanwhile, only took effect at next turn's allowance
recompute — displaying it mid-turn granted nothing, as playtesting
found. It now bumps the current allowance by one on display (a delta,
so number-card movement already played survives), unless SLOW or a
zeroed allowance says otherwise. Test covers the immediate grant and
the persistence into later turns.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 10:33:02 -04:00
Eric WagonerandClaude Fable 5 789d927122 Daggers, rocks, blades, and wands can be set down too
The rulebook's movable-object list is wider than the stones: "magic
stones, treasure chests, the dagger, the large rock, and the
wizardblade" — and the expansion expects wands to change hands, since
"its remaining charges go with it." A new isMovableObject helper in
the engine names that full set, doDropObject honors it, and the hint
bar's "Drop it here" button follows suit. Charges are keyed by card
instance, so a dropped wand carries them to whoever picks it up —
covered by new tests, along with the refusal to drop spell cards.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 09:59:09 -04:00
Eric WagonerandClaude Fable 5 45666bca16 Ambushes: the async-native form of Interrupt and Opportunity Fire
Eric's diagnosis: "in the moment" interruption cards are worthless in
correspondence play — there is no moment. The answer was already in
the game: WARD is a contingency card, and ambushes generalize it. On
your turn, playing Interrupt or Opportunity Fire now arms an ambush:
commit it with an attack from your hand (plus an optional number
card) and a trigger — an opponent entering your line of sight, coming
beside you, or grabbing a treasure — and it springs automatically
when the condition occurs, whether you are watching or asleep. The
sprung attack opens the normal counteraction stack, so the victim
gets their defense (asynchronously, like any attack). Committed cards
leave your hand until the trap springs or you disarm it; ambushes are
invisible to everyone but their owner (view-level redaction), die
with their owner, stay armed if the shot is momentarily illegal, and
honor the no-combat first round. Live play in the moment still works
too — and the client now actually offers it (the old UI never let
you click those cards out of turn). The rail shows your armed traps
with a disarm control; the chronicle announces AMBUSH! when one
springs. 124 tests passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 01:36:53 -04:00
Eric WagonerandClaude Fable 5 77ae65b263 Pick your standee: hotseat wizards choose their color while naming
The naming round now shows the six real wizard standees; each player
taps theirs before typing their name, claimed standees gray out, and
the next player defaults to the first free one. The choice travels as
an optional colors array in the engine config, the view exposes each
player's colorIndex, and the board, score sheet, treasure chests, and
wizard art all follow the chosen color instead of seat order —
persisting through hotseat saves. Verified: Alice claimed the yellow
standee and marched onto the board as the yellow wizard with yellow
treasure chests. (Online rooms still assign by seat order; a lobby
color picker can reuse the same config field later.)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 01:15:07 -04:00
Eric WagonerandClaude Fable 5 89961bbb59 ADD joins two number cards on movement, as printed
"You may add two NUMBER cards together for any single action" —
movement included. The engine accepts a second movement number when an
ADD accompanies it (once per turn); the client spends your Add
automatically and says so on the button. 120 tests passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 23:41:37 -04:00
Eric WagonerandClaude Fable 5 c9524a37db Thumb Of God lands: the 6th edition is 100% implemented
Eric chose the "divine meteor" redesign for the one card that cannot
be digitized faithfully (the physical version has you flick the die at
the board from six inches). Digital form: aim at a square in sight;
the die drifts 0-2 squares in a random direction, then every token in
and around the landing square — ground objects, treasures, creatures,
and wizards alike — is flung to a random nearby square. Walls mean
nothing to falling cardboard; tokens knocked off the board settle at
the nearest edge, per the original card; there is no counteraction.

With this, all 128 unique cards of the 6th edition game (69 basic +
59 Expansion Set #1) are implemented, tested, and playable online.
The "unimplemented card" guard test now points at an Expansion #2
shelf card, which is the only kind left. 119 tests passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 23:05:47 -04:00
Eric WagonerandClaude Fable 5 21dcd532a3 Add Swap Home Bases — the audit's one escapee
Neutral, LOS to the other player, legal only when both home bases hold
an equal number of treasures. With this, every card in the 6th edition
game is implemented except Thumb Of God, which awaits its digital
redesign. 118 tests passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 23:02:43 -04:00
Eric WagonerandClaude Fable 5 06eea72ded Expansion wave 4: 27 combat, curse, and utility cards
Fortune: GIFT FROM ABOVE (+3, no ceiling), GIFT FROM BELOW (a trap in
the deck — 3 damage on the draw, harmless in the opening deal).
Modifiers: POWER ATTACK burns life into any damage spell. Curses:
WEAKNESS (drop your treasure, take double, carry nothing), STRENGTH
(double physical dealt; the two cancel), WALKING DEAD (half a point
per space walked, forever), DISEASE (the victim becomes a carrier who
infects everyone in squares they enter), IDIOT (the victim shambles
toward their nearest own treasure, able only to counteract, until
they stand on it and ask "What am I doing here?"). Defense: EMPATHY
(attacks bite their caster too), FORCE FIELD (spell-stopping
counteraction). Mischief: MENTAL SWAP (trade whole hands), MENTAL
FORCE (march someone three spaces), BUTT-HEAD (become a goat, ram for
the distance charged), HEAVE-HO (throw your carried treasure as a
weapon), THIEF and SWAP-MEET (item larceny), CHAOS (all hands in a
pile, shuffled, redealt), ILLUSIONARY ATTACK (a fake spell that hurts
if believed), WARD (a trapped treasure bites its thief), REMOVE CURSE
(strip any duration spell, rolling to hit the shrunken or invisible),
SWARTHMORE'S ENCHANTMENT (+1 on an enchanted object). Space-time:
DIMENSIONAL WARP (paired step-through tokens), REDIRECTION (swap two
outer exits' wraparounds), BIG MAN (fills the corridor: no entry, no
punches, no casting past him), FEAR (nobody approaches within 3),
and the out-of-turn pair — INTERRUPT and OPPORTUNITY FIRE — which
open a one-action window in another player's turn. Only THUMB OF GOD
remains, awaiting its digital redesign. 117 tests passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 23:01:42 -04:00
Eric WagonerandClaude Fable 5 3a35922a40 Expansion wave 3: twelve terrain cards
KILLER OOZE (1 damage on entry, slip on 1-2: drop treasure, 2 more,
flat on your face until you roll to stand), CREATE PIT (jumps roll a
D4 — clear it on 2-4, fall in on a 1 and climb out on later rolls),
ROSEBUSH (3-point passage, blocks sight), DUST CLOUD (a permanent
zone of blindness: direction rolls inside, no LOS through, defeats
Visionstone), FILL SQUARE WITH SLIME (entering ends your actions,
blocks sight), HANDFUL OF TACKS (adjacent-only scatter, 3 points to
cross), CREATE DOOR (a new locked door in any wall or corridor),
BOOBYTRAP (four face-down tokens, one secretly real — 4 points under
anyone but the caster; the caster's view alone marks the true token),
GLUE (objects pinned for twice the number card), SAFE (items locked
away from everyone but the creator), TRADER (swap two floor items in
sight; glue and safes hold fast), and STONE TO WATER (walls melt into
range-2 waves, stone blocks into range-4 bursts). LOS blocking is now
per-terrain-kind. The board renders all of it, boobytrap placement is
a four-click ritual, and Trader is two. 108 tests passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 22:52:34 -04:00
Eric WagonerandClaude Fable 5 28949bdb7d Expansion wave 2: the magic wand system, plus Deja-Vu
Wands charge on first use from the number card(s) played (Amplify and
Add both work when setting charges), spend one charge per use with a
hard once-per-turn limit, stay displayed while charged, and crumble
to the discard when the last charge goes. They are isolated from
their wielder — usable under NO SPELL — and Absorb Spell cannot eat
them. BLASTER WAND fires 3-point bolts through the normal
counteraction stack; STICKY WAND webs its victim (movement -3 for a
turn, +2 to any fire damage, including hotter firewall crossings);
SHIFT WAND shoves a wizard one space in any direction straight
through stone walls; WARP WAND opens a wall section that snaps back
at the end of the turn. DEJA-VU retrieves any discard except a wand.
The wands' 5e-era "stick" subtype is renamed "wand" per Eric (the 6e
faces say Wand; Exp2 shelf cards keep their period names). Client:
charge badges, shove targeting, retrieve-by-name. 101 tests passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 22:45:51 -04:00
Eric WagonerandClaude Fable 5 df0675c735 Expansion wave 1: the creature system and first eight monster cards
Creatures are first-class citizens: TROLL (D4 punches, 6 damage to
kill, regenerates at its creator's turn end), SKELETON (2-point
punches), WRAITH (walks through one wall a turn; its touch deals 2
and steals a random card), FIRE IMP (a stationary turret scorching
anyone in sight once per turn — including its creator — killed only
by Waterbolt or a Waterwall wave), DEMOCRATIC MONSTER (moved three
spaces by EVERY player on their turn, one claw per round), SHADOW (a
second body costing a life point per turn, destroyed by any damage),
and ALTER EGO (a stationary double). Monsters obey their creators,
move on the controller's turn, attack once per turn but never on
their creation turn (summoning IS your attack), refuse to strike
their creators, and vanish when their creator dies. Attacks can
target creatures directly (no counteraction window — monsters don't
counter); Dispel Creation un-creates them. Plus MEGA-MONSTER (double
a monster's toughness or speed), ADRENALINE (two attacks a turn),
MAD DASH, and LIFESAVER. Expansion Set #2 confirmed by Eric as a
5e-era product — marked historical-only in the data; the 6e game is
exactly base + Expansion #1 (200 cards, all verified). Lobby gains an
"include Expansion Set #1" toggle; the client renders creatures as
diamond tokens with select-move-attack interaction. 95 tests passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 22:41:54 -04:00
Eric WagonerandClaude Fable 5 5a0003f4ce Correct 15 cards against photos of the actual 6e card faces
Eric spotted mismatches between the 5e-database-derived card data and
his physical 6e cards (photos IMG_4688-4690). All 15 texts are now
verbatim from the faces. Four were mechanical, now fixed in the
engine: BLIND's 6e text adds "engage in combat" — blinded punches
flail on a die roll; PICK LOCK's face states "This is not a spell" —
the lock cards and thrown weapons are physical actions NO SPELL cannot
silence; MIST-BODY passes doors and drifts through thornbushes but
does NOT pass the maze's stone walls (was backwards); WALL OF FIRE's
counteraction mode stops a Waterbolt (previously deferred). Metadata:
UGLY is L.O.S.-marked, MASTER KEY is NEUTRAL/ADJACENT, WIZARDBLADE
and PICK LOCK carry ADJACENT markings (new `adjacent` field), LARGE
ROCK is rethrowable by any player (already engine behavior),
BRAINSTONE's face has no corner type. 84 tests passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 21:58:17 -04:00