감사 정책 head 유실을 복구하고 데몬 준비 상태로 배포를 검증한다

This commit is contained in:
2026-09-26 15:21:17 +00:00
parent 11d0a4afdd
commit daf7a87799
14 changed files with 323 additions and 31 deletions
+3 -1
View File
@@ -1,7 +1,7 @@
import { persistAuditDecisions } from '../playAudit/decisionPersistence.js';
import { persistAuditDiplomacyEvents } from '@sammo-ts/infra';
import { hasAuditDocumentBaseline, persistAuditDocumentBaseline } from '../playAudit/documentBaseline.js';
import { persistAuditPolicies } from '../playAudit/policyPersistence.js';
import { persistAuditPolicies, restoreMissingAuditPolicyHeads } from '../playAudit/policyPersistence.js';
import { prunePreviousAuditBatch, type AuditRetentionResult } from '../playAudit/retention.js';
import { persistAuditMonth } from '../playAudit/persistence.js';
import { persistGeneralAccessScores, persistGeneralUpdates } from './generalBatchPersistence.js';
@@ -78,6 +78,7 @@ import { prepareRealtimeRecovery } from './prepareRealtimeRecovery.js';
export interface DatabaseTurnHooks {
hooks: TurnDaemonHooks;
flushChanges(): Promise<void>;
restoreMissingAuditPolicyHeads(): Promise<boolean>;
flushInitialAudit(observedAt: Date, force?: boolean): Promise<void>;
takeCommittedReadModelChanges(): RealtimeReadModelChanges | null;
takeCommittedReadModelChangeReceipt(): CommittedReadModelChangeReceipt | null;
@@ -2164,6 +2165,7 @@ export const createDatabaseTurnHooks = async (
hooks,
flushChanges,
flushInitialAudit,
restoreMissingAuditPolicyHeads: () => restoreMissingAuditPolicyHeads(prisma, world),
takeCommittedReadModelChanges: () => {
return takeCommittedReceipt()?.changes ?? null;
},
@@ -396,7 +396,8 @@ export const createRaiseInvaderHandler = (options: {
}
world.updateNation(nationId, {
chiefGeneralId: ruler.id,
meta: { ...nation.meta, gennum: npcEachCount },
// addNation이 붙인 감사 이력 head를 오래된 생성 객체로 덮어쓰지 않는다.
meta: { ...world.getNationById(nationId)!.meta, gennum: npcEachCount },
});
for (const officerLevel of [12, 11, 10, 9]) {
options.reservedTurns.ensureNationTurns(nationId, officerLevel);
@@ -395,7 +395,8 @@ export const createRaiseNpcNationHandler = (options: {
}
world.updateNation(nationId, {
chiefGeneralId: ruler.id,
meta: { ...nation.meta, gennum: 1 + subordinateCandidates.length },
// addNation이 붙인 감사 이력 head를 오래된 생성 객체로 덮어쓰지 않는다.
meta: { ...world.getNationById(nationId)!.meta, gennum: 1 + subordinateCandidates.length },
});
options.reservedTurns.ensureNationTurns(nationId, 12);
options.reservedTurns.ensureNationTurns(nationId, 11);
+2 -1
View File
@@ -937,10 +937,11 @@ const createTurnDaemonRuntimeWithLease = async (
await dbHooks.prepareRealtimeRecovery({ paused: await gatewayGate?.shouldPause() });
// 복구된 clock에서 기준을 고정하고 readiness 공개 전에 원자적으로 저장한다.
// 명령 없는 PREOPEN도 기록하며 input_event나 게임 RNG를 만들지 않는다.
const policyHeadsRestored = await dbHooks.restoreMissingAuditPolicyHeads();
initializeAuditPolicies(world);
const diplomacyInitialized = initializeAuditDiplomacy(world, new Date(clock.nowMs()));
initializeAuditCollection(world, new Date(clock.nowMs()));
await dbHooks.flushInitialAudit(new Date(clock.nowMs()), diplomacyInitialized);
await dbHooks.flushInitialAudit(new Date(clock.nowMs()), diplomacyInitialized || policyHeadsRestored);
dbHooks.takeCommittedReadModelChangeReceipt();
} catch (error) {
await Promise.allSettled([