Commit Graph
426 Commits
Author SHA1 Message Date
Eric WagonerandClaude Fable 5 9aac790e71 Four token revisions clear the board's last confusions
The Democratic Monster goes crab-red (two heads, per the card), the
rock warms to brown against the gray stone, and the ooze and slime
split on silhouette — one stands up toothy, the other hangs and drips.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-30 14:52:36 -04:00
Eric WagonerandClaude Fable 5 553754a596 Mid-game invite links and a surprise-report slip
The masthead's room code is now a button: one click copies the /join
link, which seats newcomers in a waiting room and the gallery once the
boards flip. And a 🐞 report opens a two-question slip — what happened,
what was expected — that lands in feedback.jsonl beside the rooms with
the room code, move number, round, and rules rev attached, so any
surprise can be replayed to its exact moment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-30 14:08:39 -04:00
Eric WagonerandClaude Fable 5 a1fdb37c54 Credibility pass: the splice marks sanded from the rev-11 batch
The extracted rebuildRoom loop reflowed to the file's indent and its
doc comments unstacked; liftIdiotIfSatisfied moves below idiotBlocked
so each keeps its own comment; the pickup's duplicated owner lookup
folds to one; the cloned grab-refusal chain hoists to grabRefused; a
one-off #8a7a5c rejoins the #8a7a5e palette; an inert overflow-x line
and a duplicate import go; span 6 and the two cache strategies say why;
the reversed walking-dead test moves beside its biting sibling. Also:
the replay harness now honors lobby kicks, which VVZU (five bots
seated, two kicked) was the first production ledger to exercise.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-30 13:58:02 -04:00
Eric WagonerandClaude Fable 5 e83d70116f Room ids pass a strict alphabet before touching the filesystem
The lazy room wake handed caller-supplied ids to fileFor; an 8-char
traversal like '../../aa' fit through the length trim. Only [A-Z0-9]
codes reach disk now — reads refuse quietly, server-minted writes
fail loud.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-30 13:48:34 -04:00
Eric WagonerandClaude Fable 5 002698085f Ready for a crowd: idle rooms sleep, share cards render once
Memory now carries only live tables — a sweep puts finished rooms to
bed after 30 minutes and anything untouched after a day, and getRoom
wakes a sleeping room from its ledger the moment anyone asks (the
seed plus the log IS the game). The room cap counts ledgers on disk,
not just rooms awake. Share-card PNGs render once per share id and
cache immutable. Rate-limit kicks use terminate() so an abuser cannot
hold the socket open by ignoring the closing handshake.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-30 13:43:23 -04:00
Eric WagonerandClaude Fable 5 9cc0430ee2 The left-hand hand deals into two columns and the map takes the height
Player refinement: no vertical scrolling through a tall single file —
the side hand lays out two cards abreast, and with the bottom strip
holding only buttons the board viewport stretches to the freed room.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-29 23:36:13 -04:00
Eric WagonerandClaude Fable 5 7bcad12449 The ward's bite gets its name, and shrink slips past the giant
Two chronicle truths from tonight's table: the cardless ward stack fell
through to 'punch from <owner>' — stacks now carry a sourceName, and the
bite reads 'warded treasure' as it always did pre-rev-9. And a SHRUNK
wizard walks straight through BIG MAN's square (table ruling: small
enough to slip between the giant's boots) — a widening, shipped ungated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-29 23:36:13 -04:00
Eric WagonerandClaude Fable 5 d334b267a2 The hand may stand at the board's left (preference)
A player asked for cards down the side instead of along the bottom.
With the new pref on (wide screens only), the hand claims a sticky,
scrolling column at the left while the hint strips and action buttons
stay beneath the board — the table-edge dissolves into the grid so its
children place themselves. The strip moves inside the .game grid to
make that possible; the default bottom layout spans the full row as
before, and phones keep their one-column flow.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-29 23:28:00 -04:00
Eric WagonerandClaude Fable 5 b538a0a2ae Reversed, Walking Dead heals half a point per step (rules rev 11)
The same FAQ turn as Slow Death's: a REVERSE riding the cast attaches
the curse backward, and every second space walked gains the point the
bite would have taken. Older ledgers attached it biting and replay so.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-29 23:01:01 -04:00
Eric WagonerandClaude Fable 5 4430a0def1 The board gets a zoom dial, and its size is never left to chance
Players wanted to magnify crowded squares; the board now lives in a
scrolling viewport with +/− controls (1x fit to 4x), zoom centered on
the view. The svg's width is always set explicitly — fit × zoom,
remeasured by a ResizeObserver — which also cures the stale small
board left behind when the first-person pane closed: auto-sizing
against shifting CSS constraints is gone entirely.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-29 22:57:55 -04:00
Eric WagonerandClaude Fable 5 7f82aa47e0 Auto-grab asks before pocketing your own treasure
Walking off a square holding your own chest is the capture clause's
favorite setup, so the end-turn caution now names it before the
auto-grab preference takes it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-29 22:36:04 -04:00
Eric WagonerandClaude Fable 5 7ee3c01e44 Idiot lifts the moment its march turns impossible
The all-carried check ran only on the victim's own step, so a curse
whose last floor treasure was hauled off mid-turn kept its grip until
the idiot happened to move. The lift check now also runs at the pickup
that empties the floor, and at attach for a victim already standing on
their chest.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-29 22:35:00 -04:00
Eric WagonerandClaude Fable 5 dd6ba59220 Reflected permanent curses return to their caster (rules rev 11)
SLOW DEATH, WALKING DEAD, and IDIOT ride no damage or duration pipe, so
a FULL REFLECTION used to evaporate them; per the FAQ reflections act on
the cast, so the returned curse now opens its stack against the caster
like any reflected spell. Marked permanentCurse on the three defs; older
ledgers keep the evaporation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-29 22:23:53 -04:00
Eric WagonerandClaude Fable 5 e885325098 Reversed, Slow Death heals a point per draw (rules rev 11)
Per the FAQ: a REVERSE riding the cast turns the whole curse — the
victim gains a point for every card drawn, as permanently as the bite.
The stack's reversed verdict now reaches onResolved, and the sustained
effect carries it in its data scratch. Older ledgers attached the
biting curse regardless and replay unchanged (pinned at deckRev 10).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-29 22:20:29 -04:00
Eric WagonerandClaude Fable 5 e930d013f8 The invite card knows a finished tale from a live one
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-29 21:58:25 -04:00
Eric WagonerandClaude Fable 5 691f44d858 Room invite links: /join/<CODE> recruits with a card of its own
A living room's link unfurls as an invitation (waiting rooms beckon a
seat, started games a gallery view) via the shared ogPage baker. The
client follows the path: a held seat resumes, a waiting room offers
join-or-watch from the lobby, a started game is watched at once. The
address bar carries the invite link at any table, with a copy button
beside the roster.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-29 21:57:38 -04:00
Eric WagonerandClaude Fable 5 e93bcc15a2 Credibility pass: session residue swept from the rev-10 run
War-story comments become timeless constraints (carrier rule, boobytrap
tell, remove-curse prescription); the rev changelog reunites under
GameConfig.deckRev; three hand-copied cardless stack literals fold into
openCardlessStack; the visionstone one-edge loop is shared via
throughOneEdge with the edge-target hairpin exclusion stated; drain()
moves to test helpers and replaces four inline copies; the butt-head
sweep test loses its dead scaffolding and its expect(refused || true)
tautology and now asserts both branches; a process-named suite is
renamed for the behavior it pins; dead .bezel-spacer CSS and the fx
effect's fossilized cleanup story go. No behavior changes: 304 engine
tests pass, 36/36 ledgers replay, web typecheck clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-29 19:14:03 -04:00
Eric WagonerandClaude Fable 5 f2af1e26f8 Duel skill: game-fourteen scars (soft terrain, grab-time interception, warp-landing traps)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-29 18:59:30 -04:00
Eric WagonerandClaude Fable 5 100f15651d OPSEC's final form: metaphors count
Game fourteen, third leak of the series: "a door my pick answers"
revealed a pick-lock without naming it. Table prose may reference
only public state — the board, never my options, in any costume.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-29 18:50:35 -04:00
Eric WagonerandClaude Fable 5 eaa672236b The boobytrap keeps its secret
The public boobytrapPlaced event and every subsequent view shipped
the four token cells in casting order — with the real trap always
first, a tell readable by any client. Tokens are now stored and
broadcast in canonical cell order while the truth lives only in
realKey (and the caster's private event). Deterministic sort, no rng
touched, replays unaffected; a test casts in reverse order and checks
that position whispers nothing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-29 00:21:02 -04:00
Eric WagonerandClaude Fable 5 8ba0a934cc The goat charges on legs, not wings (rules rev 10)
Eric's table ruling: BUTT-HEAD's ram IS movement — the charge walks
real corridors on the turn's legal legs (three plus numbers played)
and spends them, with the walked distance as the damage. The engine
allowed an unlimited-range homing goat, and game thirteen ended on an
eight-square ram its own caster ruled illegal. At rev 10 the cast
refuses beyond-reach targets up front, a victim who slips away leaves
the goat winded ("outran"), and the legacy test pins the old behavior
at rev 9 for the ledgers that recorded it. The skill also gains the
passivity audit: a turn that only draws is a lost turn.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-29 00:17:32 -04:00
Eric WagonerandClaude Fable 5 cadba96b43 The ward tests wave the rev-9 window through
The bite rides the stack now, so the three tests that expected an
instant sting drain the counteraction window before asserting the
wound. Green across the suite; the earlier commit shipped with these
red, which the pipeline should never have allowed — noted in the
operator's own scar tissue.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-29 00:12:05 -04:00
Eric WagonerandClaude Fable 5 2a8539e59a Rev 9 ships with game thirteen's scars
The WARD's bite now rides the stack per its card text, cardless traps
carry their own damage through resolution, and the duel skill records
the goat: BUTT-HEAD's charge is cross-map physical that no spell-
counter answers, custody of one's own chest is a dial not a state, and
junction terrain outlives every spell cast near it. Ledgers verified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-29 00:10:13 -04:00
Eric WagonerandClaude Fable 5 019deedd85 The imp's fire is a spell; the soulstone floor holds (rules rev 8)
Eric flagged both mid-game, and the second one killed me while he
typed: the scorch carried no damage kind, slipping past SOULSTONE
entirely, and the stone's own clamp guarded only from above — a bearer
already at 3 or less had no protection at all, the exact opposite of
"last three points cannot be taken by spell attack." At rev 8 the
floor holds from below (spell damage at or under the floor is simply
immune), and per the FAQ the scorch is a SPELL: it opens a
counteraction window, burns as magical fire, and FULL SHIELD parts it.
One victim's window at a time; the sweep finds the rest next pass.
Older games — including tonight's, where the flaw was fatal — replay
their recorded flames unchanged; all 34 ledgers verify.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-28 23:36:48 -04:00
Eric WagonerandClaude Fable 5 5dde7b4c21 Salience is Euclidean even when geometry is not
Eric's final layer on the torus lesson: humans see center tiles and
aim there, so the center-perceived seat pays an attention tax — and a
strong player arbitrages the gap between how the board looks and how
it routes. The bots, running true-graph BFS, have neither the bias
nor the ability to exploit it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-28 13:30:17 -04:00
Eric WagonerandClaude Fable 5 b32db9878d Relocate sector is a topology weapon
Eric's framing after the six-player postmortem: on wrap boards one
sector shift breaks every curved warp at once — the card's payload is
the whole table's stale mental maps. The skill now says to hold it for
the moment an enemy plan leans on a wrap, and never to build a plan
whose only road is a warp while an opponent might hold it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-28 13:09:45 -04:00
Eric WagonerandClaude Fable 5 b7c8428ed5 The duel skill learns the board is a torus
Eric, after game eleven: the warping edges mean there is no center
column — sew the right column onto the left and the geography is
identical. Seat-quality and distance judgments made in coordinates
are rendering artifacts; only the edge-and-warp graph is real. The
router always knew; the narrator now does too.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-28 13:06:03 -04:00
Eric WagonerandClaude Fable 5 7585a5e88d Two idle-bot loops cured; visionstone reaches the walls
Game eleven's silent turns, diagnosed from the ledger. Automaton III
proposed DESTROY WALL at a wall its visionstone could see — but the
engine's edge-target casts never honored the stone, despite the
declared policy that it is the bearer's sight wherever sight is asked.
castSightEdge now dissolves one wall for the look, and the three raw
losToEdge gates (create-wall, destroy-wall, attacks on walls) route
through it, gaining visionstone and bent-corner sight alike. Automaton
II cast REMOVE CURSE with no patient and no ailment named; the rung
now writes the full prescription. Refusal-fallback loops read as idle
bots — both replays march again. Ledgers verified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-28 12:58:57 -04:00
Eric WagonerandClaude Fable 5 b99c22f14a Disease makes its caster the carrier (rules rev 7)
The card says it plainly — "You're the carrier! Disease caused by
spell does not affect you, only others" — but the engine cast it AT an
adjacent victim, making them the plague rat. At rev 7 it is a
self-cast on fear's pattern: no target, no counteraction window
("REFLECTIONs have no effect against this"), duration equals the
number, and sharing a square bites in both directions — the carrier
walking in, or anyone walking onto the carrier. Older ledgers hold
targeted disease casts with full stack exchanges, so the legacy attack
path survives for rev ≤6 games and all 33 ledgers replay clean. The
client offers the plain Cast button for it in rev-7 games.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-28 12:35:35 -04:00
Eric WagonerandClaude Fable 5 db3b14fd51 The duel skill records the carrier-breaker combo
Game ten went the distance: the champion unpacked my winning carry
with drop-object + adrenaline + teleport-exile, ferried his own
clause-vulnerable chest beside him rather than leave it stealable,
and banked at ten life through a point-blank fireball. Scars: verify
a card counters before trusting it (NO SPELL is a curse, not a
counter), carry through his reach only with real counteractions, and
re-route everything after a sector relocation rewrites the world.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-28 12:00:19 -04:00
Eric WagonerandClaude Fable 5 f90fdfa42e The duel skill learns to rob one victim twice
Game nine, four rounds: Kestrel stole both of one bot's treasures —
two bankings for the win, the second doubling as the victim's
elimination. Concentrated theft beats spread theft: same points, one
fewer opponent. Also recorded: never chain move commands blind after
the (6,6) nook ate a full turn of refused exits.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-28 11:23:10 -04:00
Eric WagonerandClaude Fable 5 b59e11a4e4 The duel skill gains a turn poller and game-eight's swap gambit
Game eight: my SWAP HOME BASES mid-delivery eliminated Kestrel for
the first time in the series (instant bank + cross-board exile + the
captured-treasures clause), then the automaton shot me off its vault
steps at one life and won its second straight. The skill records the
poller workflow — a background watcher that exits when the game waits
on Claude, launched ONLY via run_in_background so the harness
actually wakes on it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-28 10:42:29 -04:00
Eric WagonerandClaude Fable 5 ca9b09c029 Powerstone blesses a number already played this turn
On the table the stone and the number land together; digitally the
display can come a beat late and the +1 silently vanished. Displaying
POWERSTONE now grants the stride retroactively when a number was
already played for movement this turn, with a chronicle line so the
gain is visible. Pure widening — no rev needed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-28 10:22:59 -04:00
Eric WagonerandClaude Fable 5 ca0a4ef2e3 Forced drops bank honestly; half-dead sockets confess
DROP OBJECT's forced drop hardcoded onHomeOf null and skipped the
victory check — a treasure shaken loose over a home square neither
reported the banking nor triggered scoring or the captured-treasures
clause until something else prodded the engine. It now lands like any
drop: homeOwnerAt reported, checkVictory immediate.

And the stuck-game mystery from 38YP: a deploy restart left the
browser holding a half-dead socket that never fired onclose, so the
existing reconnect loop and masthead banner never engaged and a live
game wore a frozen face. The client now pings every 15s and force-
closes a socket silent for 45s, which wakes the reconnect machinery;
the server answers pong.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 23:45:26 -04:00
Eric WagonerandClaude Fable 5 5eb5312637 The attached number rides every cast path too
A number attached to SHIFT WAND silently stayed in hand: the two-stage
caster paths (shift-wand, teleport-opponent, mental-force) went through
withMods, which carried the modifier cards but not the separately-held
attached number. withMods now folds the number in wherever the call
site did not already carry it, so what the hand shows attached is what
the command carries — all of it, on every path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 23:22:56 -04:00
Eric WagonerandClaude Fable 5 5f1eda2731 Boobytrap decoys die their own deaths
Stepping on a face-down token flips it: a blank leaves the board the
moment it is discovered, instead of all four indicators lingering
until the real one detonates. The trap itself still waits, the caster
still strolls over everything unharmed, and the chronicle narrates
the flip so the table learns which squares stopped being scary.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 22:52:09 -04:00
Eric WagonerandClaude Fable 5 e388691858 The tear waits for counteractions (rules rev 6)
STRENGTH's card says the grab "would be an attack," but the engine
resolved it instantly while punches opened counteraction windows — the
defender never got their say. At rev 6 the tear rides the stack like
any physical attack: the clutch roll waits out the counters, and only
an unstopped grab still in arm's reach of a still-laden defender gets
its wrestle. A TELEPORT escape now genuinely saves the chest (FULL
SHIELD does not — the card stops spell attacks only, and the grab is
physical). The automatons counter tears at their carried gold by not
being there when the hand closes. Narrowing, so rev-gated: games
pinned at rev 5 keep their instant tears and replay unchanged — all 29
ledgers verify.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 22:40:12 -04:00
Eric WagonerandClaude Fable 5 cbd4d80dea The clockwork learns three lessons from losing to Kestrel
Game six's table play, distilled into rungs. LOCK IN PLACE now roots
an enemy carrier closing on their home — the tempo theft that opened
game five, turned against the table. A pressed carrier of ANY
temperament casts MIST-BODY with its biggest number: an untouchable
delivery beats fear's radius, as the winning heist demonstrated. And
the pathfinder learns the thornbush is a jail, not a wade — entering
ends the turn, eats the next, and stings — so only a wizard with no
road at all dives in ("few will dive into one unless they are
desperate"). Also acquits Automaton II of game-six dithering: replay
showed its loop-de-loop was the true 13-step shortest path through a
walled quadrant.

Brains ship ungated; all 28 ledgers replay clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 21:53:47 -04:00
Eric WagonerandClaude Fable 5 3c70b9aedc The duel skill learns the thornbush is a jail
Game six went to Kestrel 6-0 by heist: a five-turn mist-body robbed
the bank I had just consolidated while I sat in his thornbush having
read only the flattering half of the card. Scars recorded: thornbush
ends your turn and eats the next, mist is immune to attack-typed
counterplay so plan for where it lapses, forks that only threaten
your own assets are published to-do lists, and spoken analysis is a
shown card.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 21:44:05 -04:00
Eric WagonerandClaude Fable 5 37a390ebbf A laden clockwork delivers before it avenges
Game five's automaton stood four steps from a winning drop and instead
warped across the board to chase the bot carrying its other treasure —
two compounding brain faults. First, the thief-chase rung outranked
delivery even while carrying; a carrier now never chases. Second, the
pathing ladder fell back to "march on any enemy with a clean corridor"
before trying the true objective through hazards, so one thornbush on
the road to the thief rerouted the whole campaign toward a bystander.
The objective now exhausts its hazard-waded route before any generic
enemy march. Replayed the FRP3 moment: the brain marches E,N,E straight
home instead of W through the warp. Brains ship ungated; ledgers
verified.

The duel skill gains game-five scars: the captured-treasures
elimination clock, FEAR as a self-cast aura, key-cutters without keys,
and Kestrel's two-players-per-card table play.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 20:35:40 -04:00
Eric WagonerandClaude Fable 5 825a73b154 The cockpit's spells fire: fx timers survive the state message
Two lightning blasts at an adjacent wizard drew nothing in first
person. The fx pipeline staged the bolt correctly — then died unfired:
the server sends `events` and `state` back to back, the state message
re-derives `me`, and the fx effect tracked it, so Svelte ran the
cleanup — which cleared every pending timer and stripped in-flight
sprites — before the bolt's zero-delay start could fire. Every live
cast effect in the pane died this way since the pane was born.

The effect now tracks only the batch; everything else reads under
untrack, and timers are cleared only when the component goes down.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 19:15:55 -04:00
Eric WagonerandClaude Fable 5 773f0a7d21 Visionstone shots draw their ray and mark the pierced wall
A stone-bearing automaton fired Blind through a warp mouth and one
wall, and the table saw nothing but the attack modal — the sight trace
only knew plain and bent-corner lines, so a legal shot read as a cheat.
When the attacker displays VISIONSTONE and no plain line exists,
stackSightTrace now finds the single edge whose removal opens the line
(warp legs included), draws the ray through it, and the keymap pulses
the dissolved wall so the answer to "how can he even see me?" is on
the board. Verified against the live LZ5R blind moment: warp mouths
at (0,2)W and (4,7)E, pierced wall V:3,8.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 18:52:46 -04:00
Eric WagonerandClaude Fable 5 358633022c Attachments ride every targeted cast, not just player targets
The engine learned to bend neutral spells, but the client only sent
aroundCornerInstanceId (and amplify/add/extend) on player-target casts
— applyMods was never called on the cell, edge, creature, two-cell,
trap, or teleport-opponent paths, so a SAFE aimed around the corner
went out bare and the engine rightly refused it. All targeted cast
dispatches now pass through withMods, so what the hand shows attached
is what the command carries.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 17:41:52 -04:00
Eric WagonerandClaude Fable 5 3bf3c33fdc Around the Corner bends every spell, hairpins included
Two holes, found when a SAFE cast at a treasure 'around the 180 degree
corner' refused with no line of sight (room LZ5R). First: the bend was
honored only in the attack path — every neutral resolve (creations,
summons, utilities, edge targets) checked straight sight and ignored
the attached card, though the card says 'any line of sight spell'.
castSight/castSightEdge now thread the bend through all of them, and
the chronicle narrates the neutral bend too.

Second: the bend itself pivoted only at cell centers, so the card's
flagship shot — doubling back up to 180 degrees around a wall's end —
never resolved: both legs graze the corner and die. The pivot may now
sit in the wall's open gap itself (bentSightThroughGap), which is what
rounding a corner physically is. Closed doors still block; two corners
still refuse.

The client lights bent-reachable squares for real now instead of the
old one-step-adjacency guess, creations included. Pure widening, so no
rev bump: every one of these casts was refused before, so no ledger
holds one. All 26 production ledgers replay clean; the LZ5R moment
itself replayed and the exact refused cast now lands.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 17:34:48 -04:00
Eric WagonerandClaude Fable 5 f53f26ace9 The cockpit's camera ignores your own casts entirely
A cast through the glass is aimed by the eyes that fired it — you
face it by definition — and a keymap cast is a deliberate off-screen
act. Neither moves the camera. Aims and cutaways serve only deeds
done by others.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 16:10:27 -04:00
Eric WagonerandClaude Fable 5 72f5df5bba Your own casts never cut away
Casting a door onto the wall you already faced tripped the blocked-
sight cutaway: the camera leapt to film the wall from another
vantage, reading as a spin that put your back to your own door. In
the live cockpit your own deeds now only ever TURN the head, gently
and never past a quarter-turn — cutaways remain for things done TO
you.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 16:09:57 -04:00
Eric WagonerandClaude Fable 5 e2dfbd14e3 Edge cards light their targets; own casts never wrench the neck
Raising an edge-target card now makes every wall and door face
breathe faint gold in the pane — the cockpit's answer to the board's
edge handles — with hover still brightening the chosen face. And the
director's own-magic aim gains a quarter-turn cap: a deed you aimed
behind you via the keymap stays behind you, while deeds done TO you
may still spin the world.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 16:08:51 -04:00
Eric WagonerandClaude Fable 5 a4a871592b First person play arrives: the pane is the game
The first-person-play branch merges. The 3D pane becomes a full
cockpit — click-to-act with hover answers, eligibility dimming in the
world, tappable and keyable movement in a bezel of instruments, the
at-your-feet and sharing-your-square trays, creature possession with
the facing ribbon riding the mount, warp-preserved headings, and the
keymap wearing the camera's compass. Ships opt-in via preferences.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 15:58:00 -04:00
Eric WagonerandClaude Fable 5 64a6041a28 The first-person pane becomes an invitation, not a default
Through-your-eyes ships opt-in: the preferences toggle turns it on,
and only an explicit yes is remembered.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 15:57:32 -04:00
Eric WagonerandClaude Fable 5 4354a1860f Rules divide the checkbox stanza only
Between checkboxed rows and nowhere else — no frame above or below
the stanza, none around the control rows.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
2026-08-27 15:53:17 -04:00