The great simplification: every vintage gate collapses, the count restarts at 1

All 50 rooms were retired (backed up on the droplet and in Spaces), so no
ledger needs an old branch to replay: forty revisions of deckRev gates
fold into one canonical ruleset — the newest behavior everywhere. The
ward's arming, the idiot's steering, the lazy illusion roll, the legacy
redirection swap, and the flat wave all leave with their gates; RULES_REV
restarts at 1 for whenever the rules fork again. Old-vintage test pins go
with them. The opening screen now quietly drops seats whose rooms the
server no longer knows, instead of listing them "unreachable" forever.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-21 12:45:35 -04:00
co-authored by Claude Fable 5
parent e8df6efcde
commit 8a50ff7f36
19 changed files with 383 additions and 685 deletions
+16 -17
View File
@@ -33,7 +33,6 @@ function playOut(
playerIds: ids,
seed,
sets: expansion ? ["basic", "expansion1"] : ["basic"],
deckRev: 8,
});
let commands = 0;
let stuck = 0;
@@ -120,7 +119,7 @@ describe("automaton vs automaton", () => {
});
function underAttack(attackId: string, defenderHand: { instanceId: string; cardId: string }[], rig?: (s: GameState, defender: string) => void) {
let { state } = createGame({ playerIds: ["human", "bot"], seed: 42, sets: ["basic", "expansion1"], deckRev: 13 });
let { state } = createGame({ playerIds: ["human", "bot"], seed: 42, sets: ["basic", "expansion1"] });
// burn round 1
for (let i = 0; i < 2; i++) {
const r = applyCommand(state, actingSeat(state), { type: "endTurn", draw: 0 });
@@ -175,7 +174,7 @@ describe("the clockwork guards gold only within sight", () => {
// A refused cast forfeits the bot's whole turn (the fallback is endTurn),
// so SAFE must only ever be offered where the engine's sight rule allows it.
function goldOnTheFloor() {
let { state } = createGame({ playerIds: ["bot", "foe"], seed: 7, sets: ["basic", "expansion1"], deckRev: 36 });
let { state } = createGame({ playerIds: ["bot", "foe"], seed: 7, sets: ["basic", "expansion1"] });
while (actingSeat(state) !== "bot") {
const r = applyCommand(state, actingSeat(state), { type: "endTurn", draw: 0 });
if (!r.ok) throw new Error(r.error);
@@ -227,7 +226,7 @@ describe("the clockwork guards gold only within sight", () => {
describe("the clockwork honors IDIOT's march", () => {
// Rev 37 retired the engine's steering, so the duty falls to the brain.
function cursedBot() {
let { state } = createGame({ playerIds: ["bot", "foe"], seed: 7, sets: ["basic", "expansion1"], deckRev: 37 });
let { state } = createGame({ playerIds: ["bot", "foe"], seed: 7, sets: ["basic", "expansion1"] });
// Past round 1 (no combat) and around to the bot's turn.
for (let i = 0; i < 2; i++) {
const r = applyCommand(state, actingSeat(state), { type: "endTurn", draw: 0 });
@@ -285,7 +284,7 @@ describe("the clockwork honors IDIOT's march", () => {
describe("a clogged hand gets shed, not hoarded", () => {
it("the bot discards dead weight so the end-of-turn draw has room", () => {
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic"], deckRev: 13 });
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic"] });
while (actingSeat(state) !== "bot") {
const r = applyCommand(state, actingSeat(state), { type: "endTurn", draw: 0 });
if (!r.ok) throw new Error(r.error);
@@ -331,7 +330,7 @@ describe("the clockwork honors absorb's fine print", () => {
describe("the clockwork wields destroy wall", () => {
it("blasts its way out when no road leads to the gold", () => {
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic"], deckRev: 24 });
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic"] });
while (actingSeat(state) !== "bot") {
const r = applyCommand(state, actingSeat(state), { type: "endTurn", draw: 0 });
if (!r.ok) throw new Error(r.error);
@@ -353,7 +352,7 @@ describe("the clockwork wields destroy wall", () => {
});
it("values destroy wall above the chaff when forced to discard", () => {
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic"], deckRev: 24 });
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic"] });
const bot = state.players.find((p) => p.id === "bot")!;
bot.hand = [
{ instanceId: "destroy-wall#T", cardId: "destroy-wall" },
@@ -376,7 +375,7 @@ describe("the clockwork wields destroy wall", () => {
describe("the clockwork wields pass through wall", () => {
it("banks a crossing when bricked in, then steps through the wall", () => {
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic"], deckRev: 24 });
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic"] });
while (actingSeat(state) !== "bot") {
const r = applyCommand(state, actingSeat(state), { type: "endTurn", draw: 0 });
if (!r.ok) throw new Error(r.error);
@@ -408,7 +407,7 @@ describe("the clockwork wields pass through wall", () => {
describe("the clockwork denies the road", () => {
it("walls a thief's corridor when its treasure is being carried home", () => {
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic"], deckRev: 24 });
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic"] });
while (actingSeat(state) !== "bot") {
const r = applyCommand(state, actingSeat(state), { type: "endTurn", draw: 0 });
if (!r.ok) throw new Error(r.error);
@@ -446,7 +445,7 @@ describe("the clockwork denies the road", () => {
describe("the widened spellbook", () => {
it("dispels a conjured wall standing between it and the only road", () => {
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic", "expansion1"], deckRev: 24 });
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic", "expansion1"] });
while (actingSeat(state) !== "bot") {
const r = applyCommand(state, actingSeat(state), { type: "endTurn", draw: 0 });
if (!r.ok) throw new Error(r.error);
@@ -468,7 +467,7 @@ describe("the widened spellbook", () => {
});
it("offers a buddy pact to the hound at its heels", () => {
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic", "expansion1"], deckRev: 24 });
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic", "expansion1"] });
while (actingSeat(state) !== "bot") {
const r = applyCommand(state, actingSeat(state), { type: "endTurn", draw: 0 });
if (!r.ok) throw new Error(r.error);
@@ -490,7 +489,7 @@ describe("the widened spellbook", () => {
describe("finishing tactics: exile and adrenaline", () => {
it("exiles a thief carrying its gold to the far end of nowhere", () => {
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic", "expansion1"], deckRev: 24 });
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic", "expansion1"] });
// burn round 1 and reach the bot's turn
for (let guard = 0; guard < 10 && !(actingSeat(state) === "bot" && state.turn.round > 1); guard++) {
const r = applyCommand(state, actingSeat(state), { type: "endTurn", draw: 0 });
@@ -518,7 +517,7 @@ describe("finishing tactics: exile and adrenaline", () => {
});
it("casts adrenaline when two blows finish what one cannot", () => {
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic", "expansion1"], deckRev: 24 });
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic", "expansion1"] });
for (let guard = 0; guard < 10 && !(actingSeat(state) === "bot" && state.turn.round > 1); guard++) {
const r = applyCommand(state, actingSeat(state), { type: "endTurn", draw: 0 });
if (!r.ok) throw new Error(r.error);
@@ -543,7 +542,7 @@ describe("finishing tactics: exile and adrenaline", () => {
describe("the fireball-then-buddy lockout", () => {
it("burns the target, then signs the pact so they cannot hit back", () => {
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic", "expansion1"], deckRev: 24 });
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic", "expansion1"] });
for (let guard = 0; guard < 10 && !(actingSeat(state) === "bot" && state.turn.round > 1); guard++) {
const r = applyCommand(state, actingSeat(state), { type: "endTurn", draw: 0 });
if (!r.ok) throw new Error(r.error);
@@ -584,7 +583,7 @@ describe("the fireball-then-buddy lockout", () => {
describe("a pact once signed is honored", () => {
it("will not attack the wizard it just buddied", () => {
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic", "expansion1"], deckRev: 25 });
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic", "expansion1"] });
for (let guard = 0; guard < 10 && !(actingSeat(state) === "bot" && state.turn.round > 1); guard++) {
const r = applyCommand(state, actingSeat(state), { type: "endTurn", draw: 0 });
if (!r.ok) throw new Error(r.error);
@@ -610,7 +609,7 @@ describe("a pact once signed is honored", () => {
describe("no number is wasted on a turn that ends at a grab", () => {
it("gold two free steps away: the berserker charges without spending its 5", () => {
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic", "expansion1"], deckRev: 29 });
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic", "expansion1"] });
for (let guard = 0; guard < 10 && !(actingSeat(state) === "bot" && state.turn.round > 1); guard++) {
const r = applyCommand(state, actingSeat(state), { type: "endTurn", draw: 0 });
if (!r.ok) throw new Error(r.error);
@@ -636,7 +635,7 @@ describe("no number is wasted on a turn that ends at a grab", () => {
describe("the clockwork flees the dread", () => {
it("caught in FEAR's bubble, it spends its legs moving away", () => {
let { state } = createGame({ playerIds: ["bot", "grim"], seed: 42, sets: ["basic"], deckRev: 32 });
let { state } = createGame({ playerIds: ["bot", "grim"], seed: 42, sets: ["basic"] });
for (let guard = 0; guard < 10 && !(actingSeat(state) === "bot" && state.turn.round > 1); guard++) {
const r = applyCommand(state, actingSeat(state), { type: "endTurn", draw: 0 });
if (!r.ok) throw new Error(r.error);