Commit Graph
3 Commits
Author SHA1 Message Date
Eric WagonerandClaude Fable 5 3eda686e29 The full clockwork curriculum: keys, vengeance, spellcraft, and voice
Every play-strength item, in one education. DOORS: the pathfinder
walks through doors it can open — already-opened ones freely, locked
ones when holding Master Key or Pick Lock, casting the key at the
door on the path before stepping through (and a loop where the
clockwork re-keyed an already-open door forever is fixed: opened
doors read as open). TREASURE DEFENSE: a wizard carrying the
automaton's gold becomes the priority — chased over all objectives,
shaken down with DROP OBJECT when held, and attacked first. WIDER
SPELLCRAFT: blaster wands charged by number and fired; teleport as
escape when wounded and hunted, and as a counteraction clear of big
incoming spells; SPEED cast on sight; WARD armed to guard the gold;
shieldstone displayed so spare numbers soak small hits; ANTI-ANTI
pressed against counters (never against escapes); the berserker grows
BIG with an enemy near, the worrier fades invisible or slams a
CREATE WALL in its pursuer's face; ambushes armed from held
interrupts — the worrier trapping its doorstep, the others trapping
the treasure. Tournament suite green across all temperaments.

And the clockwork speaks: sparing, temperament-voiced table talk on
its own deeds — "ACQUISITION COMPLETE.", "SCHEDULED DEMISE:
DELIVERED.", "good wall. safe wall." — through the same chat ledger
as everyone else. The tally gains "games fought against the
clockwork", and automatons no longer pollute the count of wizards
seated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 17:10:47 -04:00
Eric WagonerandClaude Fable 5 f62fcf2510 Harden the hotseat tally endpoint
Security review of the accumulator commit found three holes, all in
the unauthenticated hotseat ping. Worst: Number(undefined) is NaN,
and NaN survives Math.min/max — one malformed report would have
poisoned commandsPlayed and friends permanently (NaN serializes to
null). All numeric fields now pass through a NaN-proof clamp with a
fallback. The dedupe ledger caps at 50k hotseat entries so spammed
random ids cannot grow stats.json without bound, and each connection
may deliver at most 20 reports — a real device finishes a handful of
games; a firehose is abuse.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 11:41:20 -04:00
Eric WagonerandClaude Fable 5 4114386ed8 The tally becomes a ledger of its own — and hotseat tables count
Instead of re-scanning every room's log on demand, stats.json now
accumulates beside the room files: each room is remembered at its
highest counted stage (created → started → finished), so boots and
replays reconcile without double-counting, and the tally will survive
any future pruning of old rooms. Finished games contribute their
moves, table-time, and manner of victory exactly once, at the moment
of victory.

And with an accumulator to receive them, hotseat games finally count:
each local game mints an anonymous id, pings "started" with its
player count, tracks its own between-moves clock, and on the final
move reports counts only — commands, minutes, players, win reason.
No names, no moves leave the device. The server dedupes by id, clamps
everything to sane ranges, and the booklet's tally now shows how many
of the games were hotseat tables.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 11:38:05 -04:00