Credibility pass: sweep the workshop floor
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>
This commit is contained in:
co-authored by
Claude Fable 5
parent
73150a89b5
commit
3308850bb6
@@ -9,6 +9,10 @@ import {
|
||||
type SectorPlacement,
|
||||
} from "../src/board";
|
||||
import { buildDeck } from "../src/cards";
|
||||
import { activePlayer, applyCommand, createGame } from "../src/game";
|
||||
import { createRng } from "../src/rng";
|
||||
import { setupBoard } from "../src/setups";
|
||||
import { giveCard } from "./helpers";
|
||||
|
||||
describe("card data", () => {
|
||||
it("basic deck is exactly 125 cards (official 6e rulebook)", () => {
|
||||
@@ -109,9 +113,7 @@ describe("board assembly", () => {
|
||||
});
|
||||
|
||||
describe("player counts 2-6", () => {
|
||||
it("assembles a coherent board for every supported count", async () => {
|
||||
const { setupBoard } = await import("../src/setups");
|
||||
const { createRng } = await import("../src/rng");
|
||||
it("assembles a coherent board for every supported count", () => {
|
||||
for (const n of [2, 3, 4, 5, 6]) {
|
||||
const { board } = setupBoard(n, createRng(n * 7));
|
||||
expect(board.homes.length).toBe(n);
|
||||
@@ -127,8 +129,7 @@ describe("player counts 2-6", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("full games start at every count", async () => {
|
||||
const { createGame } = await import("../src/game");
|
||||
it("full games start at every count", () => {
|
||||
for (const n of [3, 5, 6]) {
|
||||
const ids = Array.from({ length: n }, (_, i) => `w${i}`);
|
||||
const { state } = createGame({ playerIds: ids, seed: 99 + n, sets: ["basic", "expansion1"] });
|
||||
@@ -158,12 +159,7 @@ describe("sight and the wraparound openings", () => {
|
||||
});
|
||||
});
|
||||
|
||||
import { createRng } from "../src/rng";
|
||||
import { setupBoard as setupBoardForPins } from "../src/setups";
|
||||
|
||||
describe("setup diagram pairings (rulebook Set-Up Diagram)", () => {
|
||||
const setupBoard = setupBoardForPins;
|
||||
|
||||
function onEdge(c: { x: number; y: number }, origin: { x: number; y: number }, side: string): boolean {
|
||||
if (side === "N") return c.y === origin.y && c.x >= origin.x && c.x < origin.x + 5;
|
||||
if (side === "S") return c.y === origin.y + 4 && c.x >= origin.x && c.x < origin.x + 5;
|
||||
@@ -203,17 +199,16 @@ describe("setup diagram pairings (rulebook Set-Up Diagram)", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("relocation discards the aisle warp: only opposite edges connect after", async () => {
|
||||
const { createGame, applyCommand, activePlayer } = await import("../src/game");
|
||||
it("relocation discards the aisle warp: only opposite edges connect after", () => {
|
||||
let { state } = createGame({ playerIds: ["a", "b", "c"], seed: 7, sets: ["basic"], deckRev: 5 });
|
||||
const bent = (warps: typeof state.board.warps) =>
|
||||
warps.filter((w) => w.from.cell.x !== w.to.cell.x && w.from.cell.y !== w.to.cell.y);
|
||||
expect(bent(state.board.warps).length).toBeGreaterThan(0); // the arc exists
|
||||
const me = activePlayer(state);
|
||||
me.hand[0] = { instanceId: "rel#1", cardId: "relocate-sector" };
|
||||
const rel = giveCard(state, me.id, "relocate-sector");
|
||||
// Slide the top sector from (5,0) across to (0,0): an L becomes a block.
|
||||
const r = applyCommand(state, me.id, {
|
||||
type: "cast", instanceId: "rel#1",
|
||||
type: "cast", instanceId: rel.instanceId,
|
||||
target: { kind: "cell", cell: { x: 0, y: 0 } }, params: { cell: { x: 7, y: 2 } },
|
||||
});
|
||||
if (!r.ok) throw new Error(r.error);
|
||||
@@ -223,8 +218,10 @@ describe("setup diagram pairings (rulebook Set-Up Diagram)", () => {
|
||||
|
||||
describe("the aisle warp treats its corner as adjacent — sight included", () => {
|
||||
it("sight passes through the AUTO WARP, diagonals and all", () => {
|
||||
const { board } = setupBoardForPins(3, createRng(7));
|
||||
const aisle = board.warps.find((w) => w.aisle)!;
|
||||
const { board } = setupBoard(3, createRng(7));
|
||||
const aisle = board.warps.find(
|
||||
(w) => w.from.cell.x !== w.to.cell.x && w.from.cell.y !== w.to.cell.y,
|
||||
)!;
|
||||
expect(aisle).toBeDefined();
|
||||
// From the aisle mouth, squares beyond the corner are visible — including
|
||||
// at least one OFF the straight axis (the adjacency promise).
|
||||
|
||||
Reference in New Issue
Block a user