독자 수준별 구조 문서와 게이머 입문·전술 안내를 재정비한다

This commit is contained in:
2026-09-29 08:53:30 +00:00
parent 71155186b7
commit 08c3d0e936
34 changed files with 1175 additions and 271 deletions
+47 -47
View File
@@ -1,61 +1,61 @@
# Game clock reconciliation recovery
# 게임 시계 재정렬 실패 복구
This runbook is intentionally fail-closed. Do not force a profile to `RUNNING`
or delete an outbox row merely because its process is alive.
이 문서는 운영 경험이 있는 개발자를 위한 절차입니다. 개념부터 읽으려면
[게임 시계](../architecture/game-clock.md), 계산·저장 계약은
[시계 재정렬](../architecture/game-clock-reconciliation.md)을 참고하세요.
프로세스가 살아 있다는 이유만으로 `RUNNING`을 강제하거나 outbox 행을 지우지 않습니다.
## Observe
## 먼저 관찰하기
Read only the target game schema. Record `world_state.clock_phase`,
`clock_revision`, `deadline_generation`, the latest `clock_suspension`, all its
participant checksums, and the matching `clock_projection_outbox`. Compare that
target revision with `sammo:{profile}:clock:active-revision`. Never print DB or
Redis credentials.
대상 게임 schema에서 `world_state.clock_phase`, `clock_revision`,
`deadline_generation`, 최신 `clock_suspension`, 참여자 checksum과 대응하는
`clock_projection_outbox`를 읽습니다. Redis의
`sammo:{profile}:clock:active-revision`과 목표 revision을 비교합니다.
DB·Redis 접속 비밀은 출력하지 않습니다.
## Status meaning
**outbox**는 DB에서 확정했지만 다른 저장소에 전달해야 할 일을 보관한 원장입니다.
**checksum**은 재정렬 대상이 예상한 상태인지 비교하기 위한 요약값입니다.
DB와 Redis를 하나의 트랜잭션으로 묶었다고 가정하지 말고 두 단계의 상태를 봅니다.
- `SUSPENDED`: the cut is durable; no alignment DB transaction has committed.
- `RECONCILING` with `PENDING`/`FAILED` outbox: DB schedules moved, Redis is not
authoritative yet, and gameplay must remain stopped.
- `RECONCILING` with `APPLIED` outbox: verify Redis active revision and all
participant checksums before finalizing.
- `RUNNING`: DB revision, deadline generation, and Redis active revision must
agree. A mismatch is an incident and workers must not dequeue.
## 상태를 해석하기
## Retry
| 상태 | 의미와 확인할 일 |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| `SUSPENDED` | 중단 지점은 저장됐지만 일정 정렬 DB transaction은 아직 확정되지 않음 |
| `RECONCILING`, outbox `PENDING`·`FAILED` | DB 일정은 옮겼지만 Redis 전환이 끝나지 않음. 게임 진행을 열지 않음 |
| `RECONCILING`, outbox `APPLIED` | Redis 활성 revision과 모든 참여자 checksum을 확인하고 최종 확정 |
| `RUNNING` | DB revision·deadline generation·Redis 활성 revision이 일치해야 함. 불일치하면 worker가 작업을 꺼내서는 안 됨 |
Retry the same suspension ID and target revision through the clock-operation
service. The service must re-read participant checksums and either return the
already-applied result or resume the pending outbox. Never create a replacement
revision to hide a failed target revision.
## 같은 작업을 재시도하기
For `UNIFICATION_WAIT`, never rerun invader creation as a separate repair.
The input event, aligned schedules, optional rate, deterministic invader IDs,
reserved turns, and outbox committed together. A committed command with a
`RECONCILING` world therefore needs only the same outbox retry. If the command
transaction rolled back, the original prompt and source revision remain and
the same response can be retried without changing IDs or RNG results.
시계 작업 서비스를 통해 **같은 suspension ID와 목표 revision**으로 재시도합니다.
서비스는 checksum을 다시 확인하고, 이미 적용됐다면 그 결과를 사용하거나 남은
outbox 처리를 이어갑니다. 실패를 숨기려고 새 revision을 만들지 않습니다.
When an outbox row is `FAILED`, the profile must remain `RECONCILING`. A retry
is safe in both crash locations:
`UNIFICATION_WAIT`에서는 이민족 생성을 별도 복구로 다시 실행하지 않습니다.
입력 이벤트, 정렬된 일정, 선택적 간격 변경, 결정적인 이민족 ID, 예약 턴과 outbox가
함께 확정됩니다. 명령이 확정됐고 세계가 `RECONCILING`이라면 같은 outbox만 이어
처리합니다. transaction이 rollback됐다면 원래 질문·source revision이 남으므로
ID나 RNG 결과를 바꾸지 않고 같은 응답을 재시도할 수 있습니다.
- before Redis commit, the Lua operation reapplies from the source revision;
- after Redis commit but before DB finalization, the Lua operation returns the
already-active target result and DB finalization resumes without shifting any
tournament deadline twice.
실패 위치에 따른 처리는 다음과 같습니다.
`lastError` naming a legacy tournament deadline means the tournament lacks its
tick dual-write. Do not force the active revision; migrate or prove the
tournament inactive, then retry the same outbox.
- Redis 반영 전: Lua 작업이 원래 revision에서 적용합니다.
- Redis 반영 후·DB 최종 확정 전: Lua가 이미 활성화한 결과를 돌려주고 DB 확정을
이어갑니다. 토너먼트 기한을 두 번 이동하지 않습니다.
## Rollback
`lastError`가 구형 토너먼트 기한을 지목하면 tick 기록이 갖춰졌는지 확인합니다.
활성 revision을 강제하지 말고 migration이나 비활성 상태의 근거를 확인한 뒤 같은
outbox를 재시도합니다.
There is no blind inverse update. Before enabling exact reconciliation in an
environment, keep the normal database backup required for schema migrations.
If participant verification shows an unexpected mutation, stop the profile,
retain the ledger/outbox evidence, and restore the whole game schema from that
backup. Redis projections are then rebuilt from the restored DB revision.
## 되돌리기와 검증 범위
The conditional clock suite exercises `SUSPENDED`, `RECONCILING/PENDING`,
`RECONCILING/FAILED` before and after Redis commit, recovered `APPLIED`, and
final `RUNNING`. The admin status endpoint exposes the phase, revision,
participant checksums, and outbox error needed to choose the matching step.
모든 값을 반대로 이동하는 일괄 역연산은 복구 절차가 아닙니다. 운영 변경 전
정상 백업을 준비하고, 예상하지 못한 mutation이 확인되면 대상 profile을 멈춰
원장·outbox 증거를 보존합니다. 백업 복원이 필요하면 해당 시점 이후 데이터 손실
범위를 평가하고 승인된 운영 복구 절차로 game schema를 복원합니다. Redis 투영은
복원한 DB revision에서 다시 구성합니다.
조건부 시계 통합 suite는 `SUSPENDED`, Redis 적용 전·후의 실패, `APPLIED` 복구와
최종 `RUNNING`을 검사합니다. 실행에 필요한 DB·Redis가 없어 skip된 결과는 복구
검증 성공이 아닙니다. [테스트 정책](../testing-policy.md)과 해당 suite 설정을 확인하세요.