감사 수집과 저장 장애를 게임 진행에서 분리한다

This commit is contained in:
2026-09-26 16:26:02 +00:00
parent daf7a87799
commit 6b65633324
22 changed files with 1108 additions and 550 deletions
+4
View File
@@ -1,3 +1,7 @@
> 2026-09-26 정책 변경: 아래 단계별 검증 기록의 감사 실패 시 gameplay rollback은 당시 계약이다.
> 현재는 [기록·실패 계약](./play-audit.md#_6-1-공통-식별자와-내구성)에 따라 감사 savepoint만
> 취소하고 게임을 계속한다. 이력 누락·업데이트 경계의 단절을 허용하며 기존 원장은 수정하지 않는다.
# 플레이 감사 구현 기록과 수집 inventory
[확정 설계](play-audit.md)의 P1~P6 구현 기록이다. 현재 월별 상태·국가 시계열,
+12 -2
View File
@@ -298,7 +298,9 @@ NPC 결정은 적용한 불변 정책 버전을 참조하고 현재 정책으로
engine은 기존 메모리 상태·mutation 결과에서 수집해 pending 감사 자료를
`EngineStateManager` rollback과 dirty acknowledgement에 포함한다. gameplay flush와
감사 insert가 같은 PostgreSQL transaction에서 commit되고 실패 시 둘 다 rollback된다.
감사 insert는 같은 PostgreSQL transaction의 별도 savepoint에서 수행한다. 2026-09-26 사용자
결정으로 감사만 실패하면 해당 감사 묶음을 rollback하고 gameplay를 commit한다. 성공한 game
commit 뒤에는 실패한 pending도 acknowledge하여 무한 재시도·메모리 누적을 막는다.
행위/월별 snapshot/정책 버전에는 실행 ID와 종류·순번 기반 unique key로 중복을 막는다.
알림은 commit 뒤 보내며 `ChangeJournal`/Redis를 감사 원장으로 재구성하지 않는다.
@@ -306,7 +308,15 @@ API 즉시 mutation도 해당 transaction에서 사건을 기록한다. 인증
rollback된 시도의 진단은 별도 시도/오류 기록으로 남기되 gameplay 성공 사건으로 만들지
않는다. 외부 transaction rollback 전송 실패까지 '모든 시도가 반드시 기록됨'으로
주장하지 않는다. 관측하지 못한 구간은 coverage/운영 오류로 표시한다.
확정 gameplay 감사 저장 실패는 성공으로 숨기지 않고 기존 transaction 실패·복구 경계를 따른다.
감사 저장·수집 장애와 업데이트에 따른 이력 단절을 허용한다. `world_state.meta.playAuditGap`은
현재 기수의 최초 누락 연월을 보존하고, `playAudit.coverage` 및 감사 화면에 이를 표시한다.
정책 head가 저장되지 않은 버전을 가리킬 수 있으며 없는 버전은 복원·조작하지 않는다.
unique/hash 충돌 검사는 유지하고 기존 이력을 덮어쓰지 않는다. 다음 정상 수집은 재개한다.
감사 SQL은 1초 statement 제한과 250ms lock 제한(기존 제한이 더 짧으면 유지), 전체 1초
수집/쓰기 budget을 적용한다. 실행 중인 마지막 SQL 때문에 최대 약 2초가 걸릴 수 있다.
DB 연결/outer transaction 복구 실패, gameplay 저장, 권한, lease/fencing 및 clock 검증은
계속 실패를 전파한다. 필수 migration·배포 실패를 우회하거나 RESET하지 않는다.
이 정책은 플레이 감사에 한정하며 Gateway 운영/인증 감사와 input_event 처리 원장은 제외한다.
### 6.2 초기 도입·종료·초기화
+19 -6
View File
@@ -83,10 +83,10 @@ Gateway의 DB 보존 일괄 업데이트로 같은 고정 commit을 순차 적
Gateway의 새 진입/권한 catalog도 사용하려면 같은 commit의 Gateway 구성요소를 업데이트한다.
적용 전 기존 backup/운영 보호 절차를 따르고, migration 후 API/engine/frontend를 같은
버전으로 전환한다. 엔진은 clock 복구 후 조회 준비를 공개하기 전에 INITIAL·정책·관계·
보유 문서의 기준을 같은 fenced transaction에 저장한다. 문서 원문은200건씩 읽어 hash만
사건에 남긴다. 이 단계가 실패하면 정상 준비 상태로 숨기지 않는다. 원인을 해결하고
재시작하면 전체 transaction 재시도가 가능하다. 기존 migration을 되돌리거나 수정하지 않는다. tick 확장 migration은 기존 감사 행의
버전으로 전환한다. 엔진은 clock 복구 후 INITIAL·정책·관계·보유 문서의 기준을 수집한다.
문서 원문은 200건씩 읽어 hash만 사건에 남긴다. 감사 전용 오류는 savepoint만 되돌리고
게임 준비를 계속한다. 누락된 감사 묶음은 버리며 게임 상태와 누락 표시를 저장한다.
이전 구간의 자동 재구성이나 완전한 이력 연결을 보장하지 않는다. 기존 migration을 되돌리거나 수정하지 않는다. tick 확장 migration은 기존 감사 행의
값과 hash를 보존하지만 열 형식 변경의 테이블 잠금/재작성 비용이 있다. 첫 감사 도입에서는
앞 migration이 만든 빈 테이블에 적용되며, 시험판 감사 기록이 이미 많다면 기존 업데이트
유지보수 구간에서 적용 시간을 확인한다. API의 tick은 정밀도 손실을 막기 위해 문자열로 반환한다. 월별 결정 인덱스 교체도 기존 결정 기록이 많으면 인덱스 생성 시간과 잠금을 업데이트 구간에 고려한다.
@@ -130,6 +130,19 @@ writer와 rollback·정리 경계를 함께 추가하는 정식 migration으로
실제 replay payload 충돌 검사는 계속 적용한다.
`/healthz`는 clock reconciliation뿐 아니라 해당 profile의 만료되지 않은
`clock_ready=true` 데몬 lease까지 확인한다. 감사 startup 실패 중인 API는 503을
반환하므로 profile 배포 readiness가 이를 성공으로 처리하지 않는다. PREOPEN과 PAUSED도
`clock_ready=true` 데몬 lease까지 확인한다. 게임 clock·lease 초기화 실패는 503이지만
감사만 실패한 경우 게임 준비 완료를 허용한다. 감사 누락은 `playAuditGap`과 감사 화면,
`[play-audit]` 운영 로그로 구분한다. PREOPEN과 PAUSED도
데몬 초기화가 완료되면 준비 완료이며, 턴 진행 여부와 준비 상태는 별개다.
## 감사 장애 시 게임 지속 (2026-09-26)
현재 정책은 [실패·내구성 계약](./design/play-audit.md#_6-1-공통-식별자와-내구성)을 따른다.
정책·외교·NPC 결정·월말/최종 표본과 startup 수집이 대상이다. 같은 flush의 감사 묶음은
하나라도 실패하면 모두 취소하지만, 연감·통일 처리·게임 상태·입력 처리 원장은 그대로
검증하고 저장한다. API 외교 문서/관계도 감사만 취소하고 문서·알림을 정상 처리한다.
누락 표시는 기수별 sticky 상태이며 이후 성공해도 지우지 않는다. 감사 writer가 복구되면
다음 수집부터 다시 기록한다. 배포로 로직이 바뀐 과거 구간을 수정하거나 hash를 맞추지 않는다.
missing table/SQL 오류/충돌/수집 형식 오류를 게임 오류로 승격하지 않지만, DB 연결 단절이나
필수 core 행 저장 실패처럼 game commit 자체를 보장할 수 없는 상황은 기존 보호 동작을 유지한다.