test live sortie full log parity

This commit is contained in:
2026-07-26 13:13:15 +00:00
parent 6dec59430a
commit 6d642bb759
4 changed files with 50 additions and 7 deletions
@@ -7,6 +7,7 @@ export interface TurnSnapshotSelector {
logAfterId?: number;
messageAfterId?: number;
includeNationHistoryLogs?: boolean;
includeGlobalHistoryLogs?: boolean;
}
export interface CanonicalTurnSnapshot {
@@ -24,6 +25,7 @@ export interface CanonicalTurnSnapshot {
messages: Array<Record<string, unknown>>;
watermarks: {
logId: number;
historyLogId: number;
messageId: number;
};
}
@@ -259,6 +261,7 @@ export const projectCoreDatabaseSnapshot = (rows: {
messages: [],
watermarks: {
logId: logs.reduce((max, row) => Math.max(max, Number(row.id) || 0), 0),
historyLogId: logs.reduce((max, row) => Math.max(max, Number(row.id) || 0), 0),
messageId: 0,
},
};
@@ -68,6 +68,7 @@ export interface TurnCommandFixtureRequest {
logAfterId?: number;
messageAfterId?: number;
includeNationHistoryLogs?: boolean;
includeGlobalHistoryLogs?: boolean;
generalCooldowns?: GeneralCooldownSelector[];
nationCooldowns?: NationCooldownSelector[];
diplomacyPairs?: Array<{ fromNationId: number; toNationId: number }>;
@@ -469,7 +470,7 @@ const buildWorldInput = (
lastTurnTime: turnTime,
meta: {
hiddenSeed: request.setup?.world?.hiddenSeed ?? 'turn-command-differential-seed',
killturn: 24,
killturn: readNumber(referenceBefore.world, 'killTurn', 24),
isUnited: readNumber(referenceBefore.world, 'isUnited'),
scenarioId: readNumber(referenceBefore.world, 'scenarioId'),
initYear: readNumber(
@@ -661,7 +662,7 @@ const projectWorld = (
),
logs,
messages,
watermarks: { logId: logs.length, messageId: messages.length },
watermarks: { logId: logs.length, historyLogId: logs.length, messageId: messages.length },
};
};
@@ -785,8 +786,8 @@ export const runCoreTurnCommandTrace = async (
id: index + 1,
scope: log.scope,
category: log.category,
generalId: log.generalId ?? actor.id,
nationId: log.nationId ?? actor.nationId,
generalId: log.generalId ?? (log.scope === 'GENERAL' ? actor.id : undefined),
nationId: log.nationId ?? (log.scope === 'NATION' ? actor.nationId : undefined),
year: state.currentYear,
month: state.currentMonth,
text: log.text,
@@ -20,11 +20,30 @@ const ignoredLifecyclePaths = [
/^logs/,
/^messages/,
/^world\.turnTime$/,
/^generals\[[^\]]+\]\.(?:turnTime|recentWarTime|lastTurn|killTurn|mySet)(?:\.|$)/,
/^generals\[[^\]]+\]\.(?:turnTime|recentWarTime|lastTurn|mySet)(?:\.|$)/,
/^generals\[[^\]]+\]\.meta(?:\.|$)/,
/^nations\[[^\]]+\]\.meta(?:\.|$)/,
];
const normalizeStoredLogText = (value: unknown): string =>
String(value)
.replace(/^(?:<C>●<\/>|<S>◆<\/>|<R>★<\/>)(?:(?:\d+년 )?\d+월:|\d+년:)?/, '')
.replace(/<span class='hidden_but_copyable'>(.*?)<\/span>/g, '$1')
.replace(/ <1>\d{2}:\d{2}<\/>$/, '');
const semanticLogSignatures = (logs: Array<Record<string, unknown>>): string[] =>
logs
.map((entry) =>
JSON.stringify({
scope: String(entry.scope).toLowerCase(),
category: String(entry.category).toLowerCase(),
generalId: Number(entry.generalId) || null,
nationId: Number(entry.nationId) || null,
text: normalizeStoredLogText(entry.text),
})
)
.sort();
const readFixture = (relativePath: string): TurnCommandFixtureRequest => {
const stackRoot = path.join(workspaceRoot!, 'docker_compose_files/reference');
const fixture = JSON.parse(
@@ -34,6 +53,7 @@ const readFixture = (relativePath: string): TurnCommandFixtureRequest => {
...fixture,
setup: {
...fixture.setup,
isolateWorld: true,
world: {
...fixture.setup?.world,
hiddenSeed: 'turn-command-differential-seed',
@@ -60,6 +80,10 @@ integration('core ↔ legacy command-boundary differential', () => {
'%s matches command RNG and canonical state delta',
async (_label, fixturePath) => {
const request = readFixture(fixturePath);
if (request.action === 'che_출병') {
request.observe!.includeNationHistoryLogs = true;
request.observe!.includeGlobalHistoryLogs = true;
}
const reference = runReferenceTurnCommandTraceRequest(
workspaceRoot!,
request as unknown as Record<string, unknown>
@@ -73,9 +97,24 @@ integration('core ↔ legacy command-boundary differential', () => {
});
expect(reference.execution.outcome).toMatchObject({ completed: true });
expect(core.rng).toEqual(reference.rng);
if (request.action === 'che_출병') {
const generalLogWatermark = reference.before.watermarks.logId;
const historyLogWatermark = reference.before.watermarks.historyLogId;
const referenceAddedLogs = reference.after.logs.filter((entry) =>
String(entry.scope).toLowerCase() === 'nation' ||
(String(entry.scope).toLowerCase() === 'system' &&
String(entry.category).toLowerCase() === 'history')
? (Number(entry.id) || 0) > historyLogWatermark
: (Number(entry.id) || 0) > generalLogWatermark
);
expect(semanticLogSignatures(core.after.logs)).toEqual(semanticLogSignatures(referenceAddedLogs));
}
expect(
compareTurnSnapshotDeltas(reference.before, reference.after, core.before, core.after, {
ignoredPathPatterns: ignoredLifecyclePaths,
ignoredPathPatterns:
request.action === 'che_출병'
? ignoredLifecyclePaths
: [...ignoredLifecyclePaths, /^generals\[[^\]]+\]\.killTurn(?:\.|$)/],
})
).toEqual([]);
},
@@ -23,7 +23,7 @@ const snapshot = (
nationTurns: [],
logs: [],
messages: [],
watermarks: { logId: 0, messageId: 0 },
watermarks: { logId: 0, historyLogId: 0, messageId: 0 },
...overrides,
});