Connect all fourteen physical skills and private setup to five card-role battle modifiers, public posture, Harkonnen skilled capture, death return and optional own-leader revival through controls, legal AI and persisted room actions. Nine skill effects and combined-mode/publication acceptance remain unfinished. Captured replacement entitlement and foreign ghola integration stay guarded. Fresh publisher/designer research supports skilled-capture publicity through its unique known physical card; this is recorded as a component inference. Independent review found and fixed Voice/must-use-leader and invalid saved assignment/offer cases. A pre-existing Discovery privacy assertion confused card ID prefixes; the corrected deterministic physical-pair scenario was independently reviewed. The first broad run was 4410/4411; corrected final verification passes types/lint, all 4411 offline tests, build and 43 HTTP tests. Final durations: check 149741ms, build 6659ms, integration 28274ms. Source fingerprint: aef655ac1ebc0eb2f64294e13d3d27337167312cf8ab17568a166ee9c39f6a85. Private final report: 20260913-leader-skills/checks-final/report.json. Three seeded prototype games completed with no rejected bot candidates. Browser setup/card inspection/refresh passed. Another user-reported power outage stopped the server; backup and necessary restart restored the same private seat. All 292 games at restart and their original application records remain unchanged; 33 isolated HTTP-test rooms bring the current total to 325. No database reset. Efficiency: one shared setup/lifecycle implementation supports five connected role effects; selective existing agents handled catalog/UI/tests/research and independent reviews. One repeated broad check was required by the reproduced ID-prefix assertion failure. Aggregate goal counter rose from 65529766 to 67313673 through this checkpoint (1783907), including inherited context and coordination; this is not a billing or savings estimate. Full goal remains active.
78 lines
2.4 KiB
TypeScript
78 lines
2.4 KiB
TypeScript
import type { DatabaseSync } from 'node:sqlite';
|
|
import {
|
|
initializeIxGameForAudit,
|
|
initializeDiscoveryGameForAudit,
|
|
initializeLeaderSkillsGameForAudit,
|
|
viewGame,
|
|
type Game,
|
|
} from '../game/engine';
|
|
|
|
/** Local development only. This cannot create a seat, change its owner, or
|
|
* redeal a started game. The caller backs up the database before invoking it. */
|
|
export function startIxPrototypeRoom(
|
|
db: DatabaseSync,
|
|
code: string,
|
|
expectedVersion: number,
|
|
) {
|
|
return startPrototypeRoom(db, code, expectedVersion, 'ix');
|
|
}
|
|
export function startPrototypeRoom(
|
|
db: DatabaseSync,
|
|
code: string,
|
|
expectedVersion: number,
|
|
profile: 'ix' | 'discovery' | 'leader-skills',
|
|
) {
|
|
if (
|
|
!/^[A-Z0-9]{8}$/.test(code) ||
|
|
!Number.isSafeInteger(expectedVersion) ||
|
|
expectedVersion < 0
|
|
)
|
|
throw new Error('Provide an eight-character room and its current version.');
|
|
const row = db
|
|
.prepare('SELECT state, version FROM rooms WHERE code = ?')
|
|
.get(code);
|
|
if (!row || typeof row.state !== 'string' || row.version !== expectedVersion)
|
|
throw new Error(
|
|
'The room is missing or changed. Refresh before starting the prototype.',
|
|
);
|
|
const initial = JSON.parse(row.state) as Game;
|
|
if (initial.code !== code)
|
|
throw new Error('The room identity is inconsistent.');
|
|
if (!['ix', 'discovery', 'leader-skills'].includes(profile))
|
|
throw new Error('Unknown prototype profile.');
|
|
const game =
|
|
profile === 'ix'
|
|
? initializeIxGameForAudit(initial)
|
|
: profile === 'leader-skills'
|
|
? initializeLeaderSkillsGameForAudit(initial)
|
|
: initializeDiscoveryGameForAudit({
|
|
...initial,
|
|
discoveryEnabled: true,
|
|
});
|
|
// Exercise the same player projection before accepting the new saved state.
|
|
for (const player of game.players) viewGame(game, player.id);
|
|
const version = expectedVersion + 1;
|
|
game.version = version;
|
|
const result = db
|
|
.prepare(
|
|
'UPDATE rooms SET state = ?, version = ?, updated_at = ? WHERE code = ? AND version = ? AND state = ?',
|
|
)
|
|
.run(
|
|
JSON.stringify(game),
|
|
version,
|
|
Date.now(),
|
|
code,
|
|
expectedVersion,
|
|
row.state,
|
|
);
|
|
if (result.changes !== 1)
|
|
throw new Error('The lobby changed during setup. No prototype was saved.');
|
|
return {
|
|
code,
|
|
version,
|
|
status: game.status,
|
|
advanced: game.advanced,
|
|
players: game.players.length,
|
|
};
|
|
}
|