fix: 게임 시계 완료 감사 경계 보강
This commit is contained in:
@@ -5,14 +5,12 @@ import path from 'node:path';
|
||||
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const schemaPath = path.join(root, 'packages/infra/prisma/game.prisma');
|
||||
const inventoryPath = path.join(root, 'docs/architecture/game-clock-participants.json');
|
||||
const [schema, inventoryText] = await Promise.all([
|
||||
readFile(schemaPath, 'utf8'),
|
||||
readFile(inventoryPath, 'utf8'),
|
||||
]);
|
||||
const [schema, inventoryText] = await Promise.all([readFile(schemaPath, 'utf8'), readFile(inventoryPath, 'utf8')]);
|
||||
const inventory = JSON.parse(inventoryText);
|
||||
const covered = new Set(inventory.coveredFields ?? []);
|
||||
const policies = new Set(inventory.policies ?? []);
|
||||
const failures = [];
|
||||
const participantKeys = new Set();
|
||||
|
||||
if (inventory.tickPerTurn !== 36_000_000) {
|
||||
failures.push(`tickPerTurn must remain 36000000, found ${inventory.tickPerTurn}`);
|
||||
@@ -41,9 +39,16 @@ for (const field of discovered) {
|
||||
}
|
||||
}
|
||||
for (const participant of inventory.participants ?? []) {
|
||||
if (participantKeys.has(participant.key)) {
|
||||
failures.push(`duplicate participant key: ${participant.key}`);
|
||||
}
|
||||
participantKeys.add(participant.key);
|
||||
if (!policies.has(participant.policy)) {
|
||||
failures.push(`participant ${participant.key} has unknown policy ${participant.policy}`);
|
||||
}
|
||||
if (participant.policy === 'FORBID') {
|
||||
failures.push(`active participant must not remain FORBID: ${participant.key}`);
|
||||
}
|
||||
if (!participant.owner || !Array.isArray(participant.authorityFields)) {
|
||||
failures.push(`participant ${participant.key} is missing owner or authorityFields`);
|
||||
}
|
||||
@@ -52,19 +57,54 @@ for (const requiredKey of [
|
||||
'world-clock',
|
||||
'turn-cursor',
|
||||
'general-next-turn',
|
||||
'general-recent-war-occurrence',
|
||||
'auction-open-occurrence',
|
||||
'auction-deadline',
|
||||
'auction-finalizing-recovery',
|
||||
'message-occurrence',
|
||||
'message-expiry',
|
||||
'vote-start-occurrence',
|
||||
'vote-end-deadline',
|
||||
'select-pool-reservation',
|
||||
'npc-selection-window',
|
||||
'accepted-command-coordinate',
|
||||
'tournament-deadlines',
|
||||
'movable-json-rule-anchors',
|
||||
'unification-wait',
|
||||
'clock-operation-ledger',
|
||||
]) {
|
||||
if (!(inventory.participants ?? []).some((participant) => participant.key === requiredKey)) {
|
||||
if (!participantKeys.has(requiredKey)) {
|
||||
failures.push(`required participant is missing: ${requiredKey}`);
|
||||
}
|
||||
}
|
||||
|
||||
const redisKeyPatterns = new Set();
|
||||
for (const entry of inventory.redis ?? []) {
|
||||
if (!entry.keyPattern) {
|
||||
failures.push('Redis participant is missing keyPattern');
|
||||
continue;
|
||||
}
|
||||
if (redisKeyPatterns.has(entry.keyPattern)) {
|
||||
failures.push(`duplicate Redis participant: ${entry.keyPattern}`);
|
||||
}
|
||||
redisKeyPatterns.add(entry.keyPattern);
|
||||
if (!policies.has(entry.policy) || entry.policy === 'FORBID') {
|
||||
failures.push(`Redis participant ${entry.keyPattern} has invalid policy ${entry.policy}`);
|
||||
}
|
||||
if (typeof entry.status !== 'string' || !entry.status.startsWith('implemented-')) {
|
||||
failures.push(`Redis participant ${entry.keyPattern} is not implemented: ${entry.status ?? 'missing status'}`);
|
||||
}
|
||||
}
|
||||
for (const requiredKeyPattern of [
|
||||
'sammo:{profile}:clock:active-revision',
|
||||
'sammo:{profile}:auction:timer',
|
||||
'sammo:{profile}:tournament:state',
|
||||
]) {
|
||||
if (!redisKeyPatterns.has(requiredKeyPattern)) {
|
||||
failures.push(`required Redis participant is missing: ${requiredKeyPattern}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (failures.length > 0) {
|
||||
console.error(failures.join('\n'));
|
||||
process.exitCode = 1;
|
||||
|
||||
@@ -13,7 +13,10 @@ import {
|
||||
} from '../src/turn-differential/referenceSnapshot.js';
|
||||
|
||||
const workspaceRoot = process.env.TURN_DIFFERENTIAL_WORKSPACE_ROOT ?? findTurnDifferentialWorkspaceRoot(process.cwd());
|
||||
const integration = describe.skipIf(!workspaceRoot || process.env.TURN_DIFFERENTIAL_REFERENCE !== '1');
|
||||
const integration =
|
||||
workspaceRoot && process.env.TURN_DIFFERENTIAL_REFERENCE === '1'
|
||||
? describe
|
||||
: (_name: string, _factory: () => void): void => undefined;
|
||||
const databaseUrl = process.env.INPUT_EVENT_DATABASE_URL;
|
||||
const persistence = describe.skipIf(!databaseUrl);
|
||||
const schedule: TurnSchedule = { entries: [{ startMinute: 0, tickMinutes: 10 }] };
|
||||
|
||||
Reference in New Issue
Block a user