NPC 감사에서 최근 기록 월을 기본 조회하고 실제 시나리오로 검증한다

This commit is contained in:
2026-09-26 17:37:32 +00:00
parent 6b65633324
commit aea5056834
10 changed files with 462 additions and 6 deletions
+31 -1
View File
@@ -173,7 +173,35 @@ export const decisionHistory = auditProcedure
.query(({ ctx, input }) =>
readAudit(ctx, async (tx) => {
const world = await readAuditWorld(tx);
const month = input.month ?? { year: world.year, month: world.month };
// 장수 턴은 월 경계와 동시에 실행되지 않는다. 현재 상태에서는 마지막으로
// 실제 결정이 저장된 월을 열고, 명시한 과거 월은 빈 월이어도 그대로 보존한다.
const latest =
!input.month && world.serverId
? await tx.playAuditDecision.findFirst({
where: {
serverId: world.serverId,
generalId: input.generalId,
phase: input.phase,
AND: [
{
OR: [
{ year: { gt: world.startYear } },
{ year: world.startYear, month: { gte: world.startMonth } },
],
},
{
OR: [
{ year: { lt: world.year } },
{ year: world.year, month: { lte: world.month } },
],
},
],
},
orderBy: [{ year: 'desc' }, { month: 'desc' }, { tick: 'desc' }, { id: 'desc' }],
select: { year: true, month: true },
})
: null;
const month = input.month ?? latest ?? { year: world.year, month: world.month };
const ordinal = monthOrdinal(month.year, month.month);
if (
ordinal < monthOrdinal(world.startYear, world.startMonth) ||
@@ -206,6 +234,8 @@ export const decisionHistory = auditProcedure
return {
...world,
month,
currentMonth: { year: world.year, month: world.month },
selection: input.month ? ('MONTH' as const) : ('LATEST' as const),
coverage: world.serverId ? ('PROCEDURES_ONLY' as const) : ('IDENTITY_MISSING' as const),
items: rows.slice(0, input.limit).map(project),
nextCursor: rows.length > input.limit && last ? { tick: last.tick.toString(), id: last.id } : null,
@@ -2352,6 +2352,33 @@ integration('game API security over HTTP transport', () => {
],
});
const decisionInput = { generalId: decisionGeneral, month: { year: 190, month: 1 }, limit: 1 };
// 월 경계 뒤 장수의 첫 턴 전에도 직전 결정에 도달할 수 있어야 한다.
expect((await get('decisionHistory', admin, { generalId: decisionGeneral })).body).toMatchObject({
result: {
data: {
selection: 'LATEST',
month: { year: 190, month: 1 },
currentMonth: { year: 190, month: 2 },
items: expect.arrayContaining([expect.objectContaining({ id: decisionIds[0] })]),
},
},
});
expect(
(await get('decisionHistory', admin, { generalId: decisionGeneral, month: { year: 190, month: 2 } }))
.body
).toMatchObject({
result: { data: { selection: 'MONTH', month: { year: 190, month: 2 }, items: [] } },
});
expect(
(await get('decisionHistory', admin, { generalId: decisionGeneral, phase: 'nation' })).body
).toMatchObject({
result: {
data: { selection: 'LATEST', month: { year: 190, month: 1 }, items: [{ id: decisionIds[1] }] },
},
});
expect((await get('decisionHistory', admin, { generalId: 2147483647 })).body).toMatchObject({
result: { data: { selection: 'LATEST', month: { year: 190, month: 2 }, items: [] } },
});
expect((await get('decisionHistory', undefined, decisionInput)).status).toBe(401);
expect((await get('decisionHistory', await token(['admin']), decisionInput)).status).toBe(403);
const decisionList = await get('decisionHistory', admin, decisionInput);