feat: 통일 대기 시계를 원자적 reconciliation으로 전환
This commit is contained in:
@@ -163,11 +163,16 @@
|
||||
},
|
||||
{
|
||||
"key": "unification-wait",
|
||||
"policy": "FORBID",
|
||||
"authorityFields": ["world_state.meta.isunited", "world_state.meta.lastTurnTime"],
|
||||
"projectionFields": [],
|
||||
"policy": "REBUILD",
|
||||
"authorityFields": [
|
||||
"world_state.meta.isunited",
|
||||
"world_state.meta.unificationClockSuspensionId",
|
||||
"clock_suspension.cut_tick",
|
||||
"clock_suspension.cut_wall_at"
|
||||
],
|
||||
"projectionFields": ["world_state.meta.lastTurnTime"],
|
||||
"owner": "game-engine/unification",
|
||||
"migration": "Replace the lastTurnTime workaround with a durable UNIFICATION_WAIT suspension."
|
||||
"migration": "Implemented as one exact alignment, optional rate change, invader creation, and revisioned outbox transaction."
|
||||
},
|
||||
{
|
||||
"key": "clock-operation-ledger",
|
||||
@@ -190,7 +195,7 @@
|
||||
{
|
||||
"keyPattern": "sammo:{profile}:clock:active-revision",
|
||||
"policy": "REBUILD",
|
||||
"status": "planned"
|
||||
"status": "implemented-with-db-phase-and-deadline-generation-fence"
|
||||
},
|
||||
{
|
||||
"keyPattern": "sammo:{profile}:auction:timer",
|
||||
|
||||
@@ -50,6 +50,23 @@ The authoritative registry is
|
||||
architecture gate rejects a new tick/revision field that is absent from that
|
||||
inventory.
|
||||
|
||||
## Unification wait
|
||||
|
||||
A unification month with an invader choice changes `RUNNING -> SUSPENDED` and
|
||||
persists a deterministic `UNIFICATION_WAIT` suspension in the same transaction
|
||||
as the archive, prompts, and final unification state. Only a `raiseInvader`
|
||||
message response tied to that active suspension may pass the suspended command
|
||||
queue; all other gameplay remains pending.
|
||||
|
||||
The response transaction verifies daemon authority, performs the exact
|
||||
alignment, applies all participant shifts, optionally changes the turn rate,
|
||||
then creates the invader nation, deterministic general IDs/RNG results, first
|
||||
turns, and the final target-revision outbox. The optional rate change refreshes
|
||||
the outbox with the final base/rate before commit. DB remains `RECONCILING`
|
||||
until the daemon projection worker applies Redis and verifies the target
|
||||
revision/generation. Games without an invader choice move directly to
|
||||
`COMPLETED`.
|
||||
|
||||
## DB to Redis boundary
|
||||
|
||||
The database transaction leaves the phase `RECONCILING` and creates exactly one
|
||||
@@ -114,9 +131,7 @@ future anchored realtime profiles as `PREOPEN`, and other profiles as
|
||||
`RUNNING`. Existing DateTime columns remain projections while tick columns are
|
||||
authoritative.
|
||||
|
||||
Exact reconciliation stays disabled while an active registry participant is
|
||||
`FORBID`. Tournament writes now carry tick/revision/generation coordinates and
|
||||
are revision-fenced in Redis. The remaining unification wait participant must
|
||||
be moved from its `lastTurnTime` workaround to a durable suspension before that
|
||||
workflow can reach `RUNNING`. Removing this guard to make a partial operation
|
||||
pass is prohibited.
|
||||
No active participant remains `FORBID`. Tournament writes carry
|
||||
tick/revision/generation coordinates and are revision-fenced in Redis.
|
||||
Unification wait uses the same durable ledger and outbox boundary; the former
|
||||
temporary `lastTurnTime` save/restore workaround is not part of the workflow.
|
||||
|
||||
@@ -46,10 +46,10 @@ mean deployment or production validation.
|
||||
- [x] All durable input events record accepted tick and accepted revision.
|
||||
- [x] Processing converts accepted coordinates across revisions or fails closed.
|
||||
- [x] Gateway pause/resume/open orchestration writes the DB clock phase.
|
||||
- [ ] Unification wait becomes a durable `UNIFICATION_WAIT` suspension.
|
||||
- [ ] Alignment, optional rate change, invader IDs/RNG, creation, first schedule,
|
||||
- [x] Unification wait becomes a durable `UNIFICATION_WAIT` suspension.
|
||||
- [x] Alignment, optional rate change, invader IDs/RNG, creation, first schedule,
|
||||
outbox, verification, and RUNNING transition form one retry-safe workflow.
|
||||
- [ ] Multi-host drift and general-access/clock-operation deadlock tests.
|
||||
- [x] Multi-host drift and general-access/clock-operation deadlock tests.
|
||||
|
||||
## Milestone 5 - test-branch release gate
|
||||
|
||||
@@ -57,11 +57,11 @@ mean deployment or production validation.
|
||||
integration suites.
|
||||
- [ ] Dedicated PostgreSQL/Redis conditional integration suite with skip count
|
||||
recorded.
|
||||
- [ ] Recovery runbook exercised from each incomplete status.
|
||||
- [x] Recovery runbook exercised from each incomplete status.
|
||||
- [x] Admin status/readiness exposes revision, phase, participant checksums, and
|
||||
incomplete outbox state.
|
||||
- [ ] User-test deployment evidence is recorded separately from Git push.
|
||||
- [ ] All `FORBID` inventory entries are removed by typed migrations or proven
|
||||
- [x] All `FORBID` inventory entries are removed by typed migrations or proven
|
||||
inactive preconditions.
|
||||
|
||||
## Evidence log
|
||||
@@ -112,3 +112,17 @@ mean deployment or production validation.
|
||||
to `RUNNING`; the Redis clock phase is revision/generation fenced.
|
||||
- `pnpm --filter @sammo-ts/gateway-api test` passed 313 tests with 35
|
||||
environment-conditional skips. Gateway typecheck and target lint passed.
|
||||
|
||||
### 2026-09-03 - atomic unification wait
|
||||
|
||||
- A unification flush now commits the finalization, actionable prompts, and one
|
||||
deterministic `UNIFICATION_WAIT` suspension together. A late archive failure
|
||||
rolls the whole boundary back; retry creates one ledger.
|
||||
- The suspended command queue admits only an invader decision tied to the
|
||||
active ledger. The daemon-authorized command transaction applies a 36-hour
|
||||
exact gap, preserves participant positions, changes the fixture rate from 10
|
||||
to 20 minutes, creates one invader nation and ten deterministic generals with
|
||||
future first turns, and writes one final-rate projection outbox.
|
||||
- The dedicated PostgreSQL/Redis fixture reached `RUNNING@2/2` only after the
|
||||
Redis projection. DB-wall versus a mocked 12-hour host drift and concurrent
|
||||
general-access lock acquisition completed without drift or deadlock.
|
||||
|
||||
@@ -28,6 +28,13 @@ 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.
|
||||
|
||||
When an outbox row is `FAILED`, the profile must remain `RECONCILING`. A retry
|
||||
is safe in both crash locations:
|
||||
|
||||
@@ -48,5 +55,7 @@ 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 implementation-plan release gate remains open until these steps have an
|
||||
automated fixture and an operator-facing status endpoint.
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user