fix: Ref 게임 로직과 시나리오 풀 호환을 보정

월 경계, 전투 기술 상한, 연감과 베팅·설문·경매 정산 순서를 Ref 계약에 맞춘다.\n\n시나리오 일반 풀을 ENGINE mutation과 logical tick 기반으로 직렬화하고 914·915 catalog 및 조건부 100기 pool 실행 경계를 추가한다.\n\n경매 worker는 세대별 durable event만 만들고 ENGINE이 row lock 후 상태 전이와 정산을 단일 transaction으로 소유한다.
This commit is contained in:
2026-08-23 16:26:14 +00:00
parent bf6b7be7b0
commit 85591c68ad
114 changed files with 13327 additions and 901 deletions
+29 -2
View File
@@ -110,6 +110,7 @@ const buildContext = (options: {
rankRows?: Array<{ type: string; value: number }>;
inheritanceLogs?: Array<{ id: number; year: number; month: number; text: string; createdAt: Date }>;
configConst?: Record<string, unknown>;
configMap?: Record<string, unknown>;
}) => {
const auth = options.auth === undefined ? buildAuth() : options.auth;
const general = options.general === undefined ? buildGeneral() : options.general;
@@ -128,12 +129,14 @@ const buildContext = (options: {
const inheritanceLogFindMany = vi.fn(async () => options.inheritanceLogs ?? []);
const webPushOutboxCreateMany = vi.fn(async () => ({ count: 1 }));
const activeWorldState =
options.configConst === undefined
options.configConst === undefined && options.configMap === undefined
? worldState
: {
...worldState,
config: {
const: options.configConst,
...worldState.config,
...(options.configConst === undefined ? {} : { const: options.configConst }),
...(options.configMap === undefined ? {} : { map: options.configMap }),
},
};
const messageRows: CapturedMessage[] = [];
@@ -269,6 +272,30 @@ describe('inherit router actor and permission boundaries', () => {
});
});
it('reports and enforces the Ref S100 stat-reset ban without dispatching or charging', async () => {
const fixture = buildContext({
configMap: { targetGeneralPool: 'SPoolUnderU100' },
inheritancePoint: 0,
});
const caller = appRouter.createCaller(fixture.context);
await expect(caller.inherit.getStatus()).resolves.toMatchObject({ canResetStat: false });
await expect(
caller.inherit.resetStat({
leadership: 70,
strength: 45,
intel: 85,
inheritBonusStat: [2, 1, 1],
})
).rejects.toMatchObject({
code: 'BAD_REQUEST',
message: '100기 올스타 장수는 능력치 초기화를 사용할 수 없습니다.',
});
expect(fixture.requestCommand).not.toHaveBeenCalled();
expect(fixture.pointUpsert).not.toHaveBeenCalled();
expect(fixture.logCreate).not.toHaveBeenCalled();
});
it('projects every Ref inheritance source with its own coefficient and stored/calculated boundary', async () => {
const fixture = buildContext({
general: buildGeneral({