feat: dashboard source coverage를 안전하게 활성화
엔진의 부대·예약턴·집계 변화와 mailbox writer를 저널에 연결하고 dashboard.global 및 인증 아이콘 source를 dependency vector에 포함한다. post-deploy coverage v1 활성화는 shared head seed와 CAS를 한 transaction으로 수행한다.
This commit is contained in:
@@ -165,6 +165,7 @@ integration('game-engine read-model journal PostgreSQL transaction', () => {
|
||||
globalRecordsChanged: true,
|
||||
});
|
||||
expect(stateAndLogReceipt?.invalidation.revisions).toEqual([
|
||||
{ domain: 'dashboard.global', entityId: 0, revision: 1n },
|
||||
{ domain: 'map.world', entityId: 0, revision: 1n },
|
||||
{ domain: 'records.global', entityId: 0, revision: 1n },
|
||||
{ domain: 'world.content', entityId: 0, revision: 1n },
|
||||
@@ -177,6 +178,7 @@ integration('game-engine read-model journal PostgreSQL transaction', () => {
|
||||
const monthReceipt = hooks.takeCommittedReadModelChangeReceipt();
|
||||
expect(monthReceipt?.changes.worldChanged).toBe(true);
|
||||
expect(monthReceipt?.invalidation.revisions).toEqual([
|
||||
{ domain: 'dashboard.global', entityId: 0, revision: 2n },
|
||||
{ domain: 'map.world', entityId: 0, revision: 2n },
|
||||
{ domain: 'world.content', entityId: 0, revision: 2n },
|
||||
]);
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
createReadModelChangeJournal,
|
||||
createRealtimeReadModelBaseline,
|
||||
createWorldReadModelSignature,
|
||||
hasDashboardSourceMutation,
|
||||
mergePersistedVisibleLogChanges,
|
||||
summarizeRealtimeReadModelChanges,
|
||||
} from '../src/turn/databaseHooks.js';
|
||||
@@ -59,6 +60,51 @@ describe('durable read-model change journal mapping', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('detects troop, leader-turn, and aggregate dashboard dependencies conservatively', () => {
|
||||
const emptyWorldChanges = {
|
||||
accessScoreResetGeneralIds: [],
|
||||
generals: [],
|
||||
cities: [],
|
||||
nations: [],
|
||||
troops: [],
|
||||
deletedTroops: [],
|
||||
deletedGenerals: [],
|
||||
deletedNations: [],
|
||||
deletedNationSnapshots: [],
|
||||
diplomacy: [],
|
||||
logs: [],
|
||||
messages: [],
|
||||
createdGenerals: [],
|
||||
createdNations: [],
|
||||
createdTroops: [],
|
||||
createdDiplomacy: [],
|
||||
createdEvents: [],
|
||||
deletedEvents: [],
|
||||
lifecycleEvents: [],
|
||||
pendingNeutralAuctions: [],
|
||||
inheritancePointAdjustments: [],
|
||||
pendingNationBettingOpens: [],
|
||||
pendingNationBettingFinishes: [],
|
||||
pendingYearbookSnapshots: [],
|
||||
pendingUnificationFinalizations: [],
|
||||
} satisfies TurnWorldChanges;
|
||||
const readModelChanges = createEmptyRealtimeReadModelChanges();
|
||||
|
||||
expect(hasDashboardSourceMutation(emptyWorldChanges, readModelChanges)).toBe(false);
|
||||
expect(
|
||||
hasDashboardSourceMutation(
|
||||
{ ...emptyWorldChanges, troops: [{ id: 3 } as TurnWorldChanges['troops'][number]] },
|
||||
readModelChanges
|
||||
)
|
||||
).toBe(true);
|
||||
expect(
|
||||
hasDashboardSourceMutation(emptyWorldChanges, {
|
||||
...readModelChanges,
|
||||
reservedGeneralIds: [7],
|
||||
})
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('ignores moving clock and lease metadata but detects month, turn-term, config, and gameplay meta', () => {
|
||||
const state = {
|
||||
currentYear: 190,
|
||||
|
||||
@@ -175,6 +175,7 @@ describe('persistUnificationFinalization', () => {
|
||||
await expect(persistUnificationFinalization(transaction, input, buildWorld())).resolves.toEqual({
|
||||
status: 'ALREADY_APPLIED',
|
||||
generationKey: input.generationKey,
|
||||
messageMailboxes: [],
|
||||
});
|
||||
expect(transaction.unificationFinalization.create).not.toHaveBeenCalled();
|
||||
});
|
||||
@@ -221,6 +222,7 @@ describe('persistUnificationFinalization', () => {
|
||||
await expect(persistUnificationFinalization(transaction, input, buildWorld())).resolves.toEqual({
|
||||
status: 'APPLIED',
|
||||
generationKey: input.generationKey,
|
||||
messageMailboxes: [],
|
||||
});
|
||||
|
||||
expect(inheritanceUpsert).toHaveBeenCalledWith(
|
||||
|
||||
Reference in New Issue
Block a user