Credibility pass: the collapse loses its scaffolding

Blind reviews over the rev-37..40 features and the gate collapse. The
scripted surgery's scars come out: bare brace blocks unwrapped (with one
hiding an unreachable scrambleHands), the amputated comment healed, the
dead events parameter unthreaded from the illusion-sight chain, the
laziness probe in perceivedBoard collapsed to the rule it always produced,
GameView.deckRev retired with its last reader, the ward's arming stub
told honestly, and every comment or test title still citing the retired
revision numbering reworded to the rule it guards. Rim mechanics unify on
rimWarpMouth and breachRim; the test suite gains plainRimWall and
pushSustained and loses its loop-shaped scars and rev-named helpers.
No behavior changes; 255 tests pass unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-21 13:04:01 -04:00
co-authored by Claude Fable 5
parent 8a50ff7f36
commit 4a91d56d24
17 changed files with 367 additions and 452 deletions
+18 -21
View File
@@ -308,7 +308,7 @@ describe("stored-log compatibility", () => {
});
});
describe("deck revisions", () => {
describe("the two-player deck", () => {
it("two-player games shed LIFESAVER; bigger tables keep it", () => {
const two = createGame({ playerIds: ["a", "b"], seed: 9, sets: ["basic", "expansion1"] });
const inGame = (s: typeof two.state) =>
@@ -391,7 +391,7 @@ describe("the ward window and chaos shields", () => {
const thief = activePlayer(state);
const owner = state.players.find((p) => p.id !== thief.id)!;
giveCard(state, owner.id, "ward", "W", 0);
expect(applyCommand(state, owner.id, { type: "armWard", armed: true }).ok).toBe(false);
expect(applyCommand(state, owner.id, { type: "armWard" }).ok).toBe(false);
const treasure = state.treasures.find((t) => t.owner === owner.id)!;
thief.position = { ...treasure.position! };
state = must(state, thief.id, { type: "pickUpTreasure" });
@@ -452,7 +452,6 @@ describe("the ward window and chaos shields", () => {
expect(state.chaosPending).toBeNull();
expect(defenderHand()).toEqual(kept);
});
});
describe("zero-damage utility attacks", () => {
@@ -493,7 +492,6 @@ describe("zero-damage utility attacks", () => {
target: { kind: "player", playerId: defender },
});
state = must(state, defender, { type: "counteract", instanceId: "full-shield#FS" });
// A total stop settles on the attacker's pass.
const result = applyCommand(state, attacker, { type: "pass" });
if (!result.ok) throw new Error(result.error);
const resolved = result.events.find((e) => e.type === "attackResolved");
@@ -515,7 +513,6 @@ describe("teleport as a counteraction", () => {
type: "cast", instanceId: fb.instanceId, target: { kind: "player", playerId: defender },
});
state = must(state, defender, { type: "counteract", instanceId: tp.instanceId, params: { cell: escape } });
// The escape is a total stop: the attacker's pass settles it.
state = must(state, attacker, { type: "pass" });
const after = state.players.find((p) => p.id === defender)!;
expect(after.life).toBe(15);
@@ -618,12 +615,12 @@ describe("slime holds spells", () => {
});
describe("answering counteractions (FAQ rulings)", () => {
function rev6() {
function freshGame() {
return createGame({ playerIds: ["alice", "bob"], seed: 42, sets: ["basic"] });
}
it("ABSORB SPELL steals a FULL REFLECTION out of the air", () => {
let { state } = rev6();
let { state } = freshGame();
state = toRound2(state);
const { attacker, defender } = faceOff(state);
const fb = giveCard(state, attacker, "fireball");
@@ -643,7 +640,7 @@ describe("answering counteractions (FAQ rulings)", () => {
});
it("FULL SHIELD cannot be absorbed — it is not cast at you", () => {
let { state } = rev6();
let { state } = freshGame();
state = toRound2(state);
const { attacker, defender } = faceOff(state);
const fb = giveCard(state, attacker, "fireball");
@@ -658,8 +655,8 @@ describe("answering counteractions (FAQ rulings)", () => {
if (!r.ok) expect(r.error).toMatch(/cannot be absorbed/);
});
it("ANTI-ANTI does not work against a teleport escape (rev 6)", () => {
let { state } = rev6();
it("ANTI-ANTI does not work against a teleport escape", () => {
let { state } = freshGame();
state = toRound2(state);
const { attacker, defender } = faceOff(state);
const fb = giveCard(state, attacker, "fireball");
@@ -680,7 +677,7 @@ describe("answering counteractions (FAQ rulings)", () => {
});
});
describe("speed and warp-token creation (rules rev 8)", () => {
describe("speed and warp-token creation", () => {
it("a SPEED bonus turn burns a turn of durations on the hastened wizard", () => {
let { state } = createGame({ playerIds: ["alice", "bob"], seed: 42, sets: ["basic"] });
state = toRound2(state);
@@ -715,7 +712,7 @@ describe("speed and warp-token creation (rules rev 8)", () => {
});
});
describe("redirection (rules rev 9)", () => {
describe("redirection", () => {
it("the two chosen exits connect; their old partners pair with each other", () => {
let { state } = createGame({ playerIds: ["alice", "bob"], seed: 42, sets: ["basic"] });
state = toRound2(state);
@@ -740,8 +737,8 @@ describe("redirection (rules rev 9)", () => {
});
});
describe("total stops end the exchange (rules rev 10)", () => {
function rev10Game() {
describe("total stops end the exchange", () => {
function faceOffRig() {
let { state } = createGame({ playerIds: ["alice", "bob"], seed: 42, sets: ["basic"] });
state = toRound2(state);
const { attacker, defender } = faceOff(state);
@@ -749,7 +746,7 @@ describe("total stops end the exchange (rules rev 10)", () => {
}
it("a declined answer to Force Field resolves at once — no goading re-prompt", () => {
let { state, attacker, defender } = rev10Game();
let { state, attacker, defender } = faceOffRig();
const fb = giveCard(state, attacker, "fireball");
const d = state.players.find((p) => p.id === defender)!;
const lifeBefore = d.life;
@@ -763,7 +760,7 @@ describe("total stops end the exchange (rules rev 10)", () => {
});
it("a partial counter still invites the defender to stack more", () => {
let { state, attacker, defender } = rev10Game();
let { state, attacker, defender } = faceOffRig();
const fb = giveCard(state, attacker, "fireball");
const d = state.players.find((p) => p.id === defender)!;
d.hand[0] = { instanceId: "blunt#T", cardId: "blunt" };
@@ -776,7 +773,7 @@ describe("total stops end the exchange (rules rev 10)", () => {
});
it("a nullified shield is no stop — the exchange returns to the defender", () => {
let { state, attacker, defender } = rev10Game();
let { state, attacker, defender } = faceOffRig();
const fb = giveCard(state, attacker, "fireball");
const a = state.players.find((p) => p.id === attacker)!;
const d = state.players.find((p) => p.id === defender)!;
@@ -839,7 +836,7 @@ describe("escapes and elemental walls as counteractions", () => {
const lifeBefore = state.players.find((p) => p.id === defender)!.life;
state = must(state, defender, { type: "counteract", instanceId: "waterwall#T" });
state = must(state, attacker, { type: "pass" });
// A total stop: the attacker's declined answer resolves at once (rev 10+).
// A total stop: the attacker's declined answer resolves at once.
expect(state.stack).toBeNull();
expect(state.players.find((p) => p.id === defender)!.life).toBe(lifeBefore);
});
@@ -894,7 +891,7 @@ describe("empathy as a counteraction", () => {
});
});
describe("empathy mirrors resolution-hook blows (rules rev 16)", () => {
describe("empathy mirrors resolution-hook blows", () => {
it("a believed illusion bites both wizards", () => {
let { state } = createGame({ playerIds: ["alice", "bob"], seed: 42, sets: ["basic", "expansion1"] });
state = toRound2(state);
@@ -997,7 +994,7 @@ describe("a reflected lightning blast ends the caster's turn", () => {
});
});
describe("fireball burns only the stones in play (rules rev 33)", () => {
describe("fireball burns only the stones in play", () => {
it("a displayed stone dies; a hidden one stays secret and safe", () => {
let { state } = createGame({ playerIds: ["a", "b"], seed: 42, sets: ["basic"] });
state = toRound2(state);
@@ -1015,7 +1012,7 @@ describe("fireball burns only the stones in play (rules rev 33)", () => {
});
});
describe("stone dead counts only the stones in play (rules rev 34)", () => {
describe("stone dead counts only the stones in play", () => {
it("hidden stones neither add damage nor betray their count", () => {
let { state } = createGame({ playerIds: ["a", "b"], seed: 42, sets: ["basic", "expansion1"] });
state = toRound2(state);