An opponent's wraith refused to be dispelled — the engine was willing
all along (any controller's creature, sight required), but creature
clicks never routed cell-target spells, so the cast never left the
client. Clicking a creature with a cell spell selected now lands on
its square. The dimming aid told the same lie twice over: it lit
every created square including ones out of sight (a caster's own
thornbush beyond the walls) and never lit creatures at all. It now
mirrors the engine — anything created, whoever made it, in sight.
And "click a wall line" stops standing in for every edge card: each
now says what the click actually is — a locked door for the keys, a
corridor line for the fire, the creation itself for the dispel — and
attacks no longer show two hints for one wall.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
Three cards sat wrongly in the creation bucket of eligibleCellsFor,
so the targeting dim demanded sighted empty squares the engine never
asks for. Boobytrap tokens go anywhere on the board but solid stone —
no sight required; a trap you can see coming is a poor trap. Glue and
the safe were worse than restricted: inverted. Both seize a square
that HOLDS a loose object or treasure, exactly the squares the empty-
square rule dimmed out. Each now has its own branch mirroring the
engine's actual checks, pinned by tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>