diff --git a/docs/architecture/general-command-differential-testing.md b/docs/architecture/general-command-differential-testing.md index 1d5ba6b..81eb564 100644 --- a/docs/architecture/general-command-differential-testing.md +++ b/docs/architecture/general-command-differential-testing.md @@ -8,14 +8,16 @@ - 범위: 명령 결과, RNG 소비, 로그, 예약 턴 lifecycle, DB 영속화 현재 ref MariaDB와 core memory를 잇는 공통 runner, 성공 경로 55개, -실행 중 확률 실패 9개, full constraint fallback 7개와 모략 확률 clamp +실행 중 확률 실패 9개, full constraint fallback 12개와 모략 확률 clamp 8개, 모략 결과값 경계 5개, 부상 경계 3개가 구현됐다. 실패 9개는 내정 critical `주민선정/정착장려/상업투자/기술연구/물자조달`과 모략 `화계/선동/파괴/탈취`이며 RNG 전체 trace, semantic state delta와 실패 -로그 본문을 비교한다. 제약 7개는 무소속, 방랑국, 타국 도시, 보급 단절, -금·쌀 부족과 민심 상한을 대표하며 휴식 fallback과 RNG/state delta를 -비교한다. clamp 8개는 `화계/선동/파괴/탈취` 각각의 계산 확률 0과 +로그 본문을 비교한다. 공통 제약 7개는 무소속, 방랑국, 타국 도시, 보급 +단절, 금·쌀 부족과 민심 상한을 대표한다. 모략 제약 5개는 동일 도시, +중립 도시, 불가침국, 계략 비용 금·쌀 부족을 고정한다. 모두 휴식 +fallback과 RNG/state delta를 비교한다. clamp 8개는 +`화계/선동/파괴/탈취` 각각의 계산 확률 0과 0.5 경계에서 성공 판정 RNG의 무소비 또는 `nextBits(1)` 소비와 전체 state delta를 비교한다. 결과값 5개는 화계 농업·상업, 선동 치안·민심, 파괴 수비·성벽의 0 바닥과 탈취의 대상 국가 자원 상한·미보급 도시 최종 diff --git a/docs/architecture/turn-state-differential-testing.md b/docs/architecture/turn-state-differential-testing.md index 3c44ac4..0ea9860 100644 --- a/docs/architecture/turn-state-differential-testing.md +++ b/docs/architecture/turn-state-differential-testing.md @@ -179,10 +179,12 @@ responses pass a separate reference trace and core resolver/API boundary. Nine general in-action failure cases now also pass the common differential: five domestic critical failures and four sabotage failures. They compare the full command RNG trace, semantic state delta and the exact action-log body. -Seven full-constraint cases cover neutral status, wandering nation, city -ownership, supply, gold, rice and trust-cap rejection. Both engines replace -the denied command with rest, consume the same RNG and produce the same -semantic delta. Eight sabotage clamp cases cover probability zero and 0.5 for +Seven common full-constraint cases cover neutral status, wandering nation, +city ownership, supply, gold, rice and trust-cap rejection. Five sabotage +constraint cases add the occupied-city target, neutral target, non-aggression +status and insufficient sabotage gold or rice. Both engines replace the denied +command with rest, consume the same RNG and produce the same semantic delta. +Eight sabotage clamp cases cover probability zero and 0.5 for fire attack, agitation, destruction and seizure. The zero boundary skips the success RNG primitive, while exactly 0.5 consumes `nextBits(1)`; the complete RNG trace and semantic delta match. These cases also fixed fire-attack city diff --git a/tools/integration-tests/test/turnCommandGeneralMatrix.integration.test.ts b/tools/integration-tests/test/turnCommandGeneralMatrix.integration.test.ts index 5994c8b..387c47d 100644 --- a/tools/integration-tests/test/turnCommandGeneralMatrix.integration.test.ts +++ b/tools/integration-tests/test/turnCommandGeneralMatrix.integration.test.ts @@ -763,6 +763,40 @@ const constraintCases: GeneralConstraintCase[] = [ action: 'che_주민선정', fixturePatches: { cities: { 3: { trust: 100 } } }, }, + { + name: 'sabotage targets the occupied city', + action: 'che_화계', + args: { destCityID: 3 }, + }, + { + name: 'sabotage targets a neutral city', + action: 'che_화계', + args: { destCityID: 70 }, + fixturePatches: { cities: { 70: { nationId: 0 } } }, + }, + { + name: 'sabotage targets a non-aggression nation', + action: 'che_화계', + args: { destCityID: 70 }, + fixturePatches: { + diplomacy: { + '1:2': { state: 7 }, + '2:1': { state: 7 }, + }, + }, + }, + { + name: 'insufficient sabotage gold', + action: 'che_화계', + args: { destCityID: 70 }, + actorPatch: { gold: 0 }, + }, + { + name: 'insufficient sabotage rice', + action: 'che_화계', + args: { destCityID: 70 }, + actorPatch: { rice: 0 }, + }, ]; integration('general command full-constraint fallback matrix', () => {