Credibility pass: the duels leave the code, staying in the ledgers
Third pass, scoped from 7a32370. Three blind reviewers (engine, web,
server/tools) each concluded the work is coherent engineering with
seam-level tells; every finding was verified before touching a line.
Session biography left the comments: the bot brain's heuristics no
longer cite the opponent who taught them, the RNRX coma parenthetical
and the thief-chase citation are gone, the seat-wallet comments state
their invariants without the war stories, and process-named test
groups now name the behaviors they pin. The incident record lives
where history belongs — commit messages and the ledgers.
Structural dedup: one VISIONSTONE one-edge-sight loop serves both
LOS paths; one creature-arrival touch handler serves walking and
warp-stepping (error text aligned); one facingWedge helper draws both
keymap ribbons; one spriteVisibleInCol rule serves the draw pass and
the hover test (which also stops re-sorting per pointermove); and
deepestFacing joins the director, replacing four copied scans.
Test hardening exposed real rot the tells were hiding: the tight
CreatureState cast caught two literals with a bogus field masking
three missing ones; the number-hoarding rig had NEVER run (its
column didn't exist on seed 42 — it now carves its own geometry);
the bank-guard rig now drives the whole table to an arrival
assertion; the bent-trace test walls off straight sight so the bend
must answer. Silent `return`-on-rig-failure became loud throws, and
can-never-fail assertions were removed.
Sweep-up: the eyeTurn ghost comment, the stacked leave() doc
comments (leave now delegates to leaveLocal), the dead ternary in
the seat client, the kick handler's name-coercion drift, kick ledger
lines gain timestamps, archiveRoomFile reuses fileFor, the RULES_REV
alias retires in favor of the engine constant, hitTest un-exports,
the NUL-sentinel hover shape becomes an honest "none" variant, and
the steering holds get named constants. The bezel's stride cluster
also centers per the table's note.
288 tests, 24 ledgers verified, all workspaces typecheck.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
This commit is contained in:
co-authored by
Claude Fable 5
parent
7bd8eff11c
commit
3bd7e3c81d
@@ -54,11 +54,6 @@ export interface Room {
|
||||
|
||||
const rooms = new Map<string, Room>();
|
||||
|
||||
/** Rules revision new games are dealt under (stored games keep their own).
|
||||
* A rules change while games are live must bump this and gate the engine;
|
||||
* local hotseat games ride the engine's default and follow in lockstep. */
|
||||
const RULES_REV = CURRENT_RULES_REV;
|
||||
|
||||
const ROOM_CODE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
||||
|
||||
/** Tokens live hashed at rest (memory and disk); clients hold the raw form. */
|
||||
@@ -164,7 +159,7 @@ export function kickSeat(room: Room, byId: PlayerId, name: PlayerId): string | n
|
||||
room.tokens.delete(name);
|
||||
room.bots.delete(name);
|
||||
room.colorChoices.delete(name);
|
||||
appendLine(room.id, { kind: "kick", name });
|
||||
appendLine(room.id, { kind: "kick", name, at: new Date().toISOString() });
|
||||
recordRoom(room);
|
||||
return null;
|
||||
}
|
||||
@@ -228,9 +223,9 @@ function startInMemory(room: Room, expansion: boolean, colors?: number[], deckRe
|
||||
export function startGame(room: Room, expansion: boolean): { events: GameEvent[] } | { error: string } {
|
||||
if (room.state) return { error: "already started" };
|
||||
const colors = resolveColors(room);
|
||||
const result = startInMemory(room, expansion, colors, RULES_REV);
|
||||
const result = startInMemory(room, expansion, colors, CURRENT_RULES_REV);
|
||||
if ("error" in result) return result;
|
||||
appendLine(room.id, { kind: "start", expansion, colors, deckRev: RULES_REV });
|
||||
appendLine(room.id, { kind: "start", expansion, colors, deckRev: CURRENT_RULES_REV });
|
||||
recordRoom(room);
|
||||
return result;
|
||||
}
|
||||
@@ -320,22 +315,22 @@ function actingSeat(room: Room): PlayerId | null {
|
||||
*/
|
||||
export function driveOneAutomaton(
|
||||
room: Room,
|
||||
): { seat: PlayerId; events: GameEvent[]; hesitated?: { refused: Command; error: string } } | null {
|
||||
): { seat: PlayerId; events: GameEvent[]; hesitated?: true } | null {
|
||||
const seat = actingSeat(room);
|
||||
if (!seat || !room.bots.has(seat)) return null;
|
||||
const view = viewFor(room.state!, seat);
|
||||
const bot = room.bots.get(seat);
|
||||
const chosen = automatonCommand(view, bot?.style, bot?.tier);
|
||||
let hesitated: { refused: Command; error: string } | undefined;
|
||||
let hesitated: true | undefined;
|
||||
let r = runCommand(room, seat, chosen ?? automatonFallback(view, bot?.tier));
|
||||
if ("error" in r) {
|
||||
// A refused choice retries with the fallback — unless the fallback IS
|
||||
// what just failed — then burns down the ladder to endTurn and pass.
|
||||
// The refusal is remembered: a brain whose choice the engine rejects
|
||||
// is a bug in the brain, and the table deserves to see the stumble
|
||||
// rather than an unexplained idle turn (the RNRX coma lesson).
|
||||
// rather than an unexplained idle turn.
|
||||
if (chosen) {
|
||||
hesitated = { refused: chosen, error: r.error };
|
||||
hesitated = true;
|
||||
console.warn(
|
||||
`automaton ${seat} hesitated in ${room.id}: ${JSON.stringify(chosen)} refused (${r.error})`);
|
||||
r = runCommand(room, seat, automatonFallback(view, bot?.tier));
|
||||
|
||||
Reference in New Issue
Block a user