# Time-domain inventory

This document is the authoritative classification of persistent timestamps,
deadlines, cooldowns, and process-local elapsed-time rules. Classification is
per rule, not per table. A feature may record both a wall occurrence and a game
effect; those are two facts, never one fallback clock.

## Domain contract

| Domain                   | Authority                                                      | Advances while suspended/reconciling | Reconciliation                |
| ------------------------ | -------------------------------------------------------------- | ------------------------------------ | ----------------------------- |
| `GAME_TIME`              | `world_state.clock_tick` under phase/revision/generation fence | no                                   | `SHIFT`, `KEEP`, or `REBUILD` |
| `WALL_TIME`              | PostgreSQL UTC `CURRENT_TIMESTAMP` for persistent decisions    | yes                                  | never                         |
| `MONOTONIC_ELAPSED_TIME` | `performance.now()` / monotonic process clock                  | process-local only                   | never persisted               |

`GameTick`, `ClockRevision`, `DeadlineGeneration`, `WallInstant`, and
`MonotonicDuration` name these meanings in new/refactored APIs. Existing
`createdAt`/`updatedAt` fields remain wall audit timestamps unless this inventory
explicitly calls them game projections.

## Recovery execution rate

A turn always contains 36,000,000 GAME ticks. The configured normal duration
remains unchanged during outage recovery. A persisted boundary-to-boundary
window projects GAME time at 2x wall speed, then 1x after rejoining the normal
schedule. The window and its wall anchor belong to clock authority; they are
not gameplay deadlines or wall audit occurrences. See
[reconciliation](./game-clock-reconciliation.md) for the 12-turn skip rule,
planned-start boundaries, readiness fencing and deployment compatibility.

## Game database inventory

PREOPEN user commands are executable even though scheduled turns are stopped.
Their authoritative processing coordinate remains signed GAME_TIME. Direct and
selection-pool creation clamp only the first runnable schedule to opening tick
zero; receipt audit, account sanctions, and pre-opening deletion use WALL_TIME.

| Pre-opening/account rule                                                 | Domain and authority                                                                                                                                                     | Reconciliation                                                                          |
| ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------- |
| `general.meta.prestart_delete_after`                                     | WALL deadline from the creation `InputEvent.createdAt` plus the configured minimum-turn wall duration; legacy missing cutoffs use `general_access_log.last_refresh` once | excluded; never shift with GAME projections                                             |
| account `legacyPenalty.*.*.expire` copied at general creation/possession | WALL Unix seconds compared with the durable request receipt                                                                                                              | excluded; an expired account sanction must not reappear when GAME dates are in the past |
| pre-opening action availability                                          | `clock_phase`, then executed `last_turn_tick` (zero equality retained); uninitialized legacy readers may compare old date fields                                         | phase/cursor authority, not `meta.opentime` display text                                |

`Pause` means whether the rule continues to age during `SUSPENDED` or
`RECONCILING`. `Projection` means a non-authoritative compatibility/display
representation.

| Table / rule / field(s)                                                                                                                                                    | Current meaning                                                  | Domain and authority                 | Pause                                                                | Reconcile / projection                                                              | Decision and reason                                                                                                  |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | ------------------------------------ | -------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `world_state.clock_tick`                                                                                                                                                   | observed world coordinate                                        | GAME, self-authoritative             | stop                                                                 | REBUILD                                                                             | root of all game-time decisions                                                                                      |
| `world_state.last_turn_tick`                                                                                                                                               | executed turn cursor                                             | GAME                                 | stop                                                                 | SHIFT                                                                               | execution order must preserve skipped-turn policy                                                                    |
| `world_state.clock_revision`, `deadline_generation`                                                                                                                        | clock/future-deadline generations                                | GAME metadata                        | stop                                                                 | REBUILD                                                                             | stale commands/workers must fail their fence                                                                         |
| `world_state.clock_base_time`, `clock_wall_anchor`                                                                                                                         | tick-to-date mapping and wall observation anchor                 | GAME projection metadata             | n/a                                                                  | REBUILD                                                                             | not business wall deadlines                                                                                          |
| `world_state.updated_at`                                                                                                                                                   | row audit                                                        | WALL, DB UTC                         | advance                                                              | excluded                                                                            | operational history is not shifted                                                                                   |
| `clock_suspension.source_revision`, `target_revision`, `cut_tick`, `catch_up_ticks`, `gap_ticks`, `shift_ticks`, `aligned_tick`                                            | reconciliation plan/audit                                        | GAME metadata                        | stop                                                                 | KEEP                                                                                | immutable clock operation facts                                                                                      |
| `clock_suspension.cut_wall_at`, `resume_wall_at`, `created_at`, `updated_at`                                                                                               | operator/runtime occurrence audit                                | WALL, DB UTC                         | advance                                                              | excluded                                                                            | records when the real operation occurred                                                                             |
| `clock_projection_outbox.target_revision`                                                                                                                                  | target GAME generation                                           | GAME metadata                        | stop                                                                 | KEEP                                                                                | projection fence                                                                                                     |
| `clock_projection_outbox.available_at`, `locked_at`, `applied_at`, `created_at`, `updated_at`                                                                              | retry/lease/audit                                                | WALL, DB UTC                         | advance                                                              | excluded                                                                            | worker control cannot pause with game time                                                                           |
| `clock_reconciliation_participant` checksum/count/policy                                                                                                                   | immutable operation evidence                                     | GAME operation metadata              | n/a                                                                  | KEEP                                                                                | evidence, not a deadline                                                                                             |
| `input_event.accepted_game_tick`, `accepted_clock_revision`, `accepted_deadline_generation`                                                                                | daemon-claim boundary                                            | GAME metadata                        | stop                                                                 | KEEP across matching revision; rebase pending legacy rows only                      | API does not pre-stamp these; daemon owns acceptance                                                                 |
| `input_event.processing_game_tick`, `processing_clock_revision`, `processing_deadline_generation`                                                                          | actual mutation boundary                                         | GAME metadata                        | stop                                                                 | KEEP                                                                                | effect validation/RNG uses this coordinate                                                                           |
| `input_event.created_at`, `processing_at`, `completed_at`, `lease_until`                                                                                                   | request receipt, processing audit, lease                         | WALL, DB UTC                         | advance                                                              | excluded                                                                            | external occurrence and worker lease                                                                                 |
| `read_model_outbox.*_at`, `web_push_outbox.*_at`                                                                                                                           | availability, claim, delivery, audit                             | WALL, DB UTC                         | advance                                                              | excluded                                                                            | retry and notification delivery are operational                                                                      |
| `turn_daemon_lease.lease_until`, `heartbeat_at`                                                                                                                            | daemon liveness                                                  | WALL, DB UTC                         | advance                                                              | excluded                                                                            | acquire/renew/assert/release use `CURRENT_TIMESTAMP AT TIME ZONE 'UTC'`, including KST sessions                      |
| `general.turn_tick`                                                                                                                                                        | next general turn                                                | GAME                                 | stop                                                                 | SHIFT; `turn_time` projection                                                       | determines engine order                                                                                              |
| `general.recent_war_tick`                                                                                                                                                  | past battle occurrence                                           | GAME                                 | stop                                                                 | KEEP; `recent_war_time` projection                                                  | historical event does not move                                                                                       |
| `general.meta.next_change_tick`                                                                                                                                            | N-turn reselection cooldown                                      | GAME                                 | stop                                                                 | SHIFT; `next_change`/`nextChangeAt` projections                                     | expressed in turns; missing tick fails closed                                                                        |
| `general.created_at`, `updated_at`                                                                                                                                         | entity audit                                                     | WALL, DB UTC                         | advance                                                              | excluded                                                                            | no gameplay deadline meaning                                                                                         |
| `select_pool.reserved_until_tick`                                                                                                                                          | selection reservation deadline                                   | GAME                                 | stop                                                                 | SHIFT; `reserved_until` projection                                                  | reservation is measured in game turns                                                                                |
| `select_npc_token.valid_until_tick`, `pick_more_from_tick`                                                                                                                 | NPC selection windows                                            | GAME                                 | stop                                                                 | SHIFT; DateTime projections                                                         | token is a game selection schedule; missing ticks fail closed                                                        |
| `general_access_log.last_refresh`, `last_action_at`; `general_access_batch.created_at`; `traffic_period.started_at`, `last_refresh`; `traffic_period_general.last_refresh` | traffic/access accounting                                        | WALL, DB UTC                         | advance                                                              | excluded                                                                            | community/operations usage, not world progression                                                                    |
| `message.created_at_wall`, `delete_until_wall`, `tombstoned_at_wall`                                                                                                       | envelope send/delete lifecycle                                   | WALL, DB UTC                         | advance                                                              | excluded                                                                            | normal messages work while the game is paused; deletion is real five minutes                                         |
| `message.occurred_game_tick`                                                                                                                                               | optional game context                                            | GAME occurrence                      | stop                                                                 | KEEP                                                                                | context only, never deletion authority                                                                               |
| `message.time`, `time_tick`, `valid_until`, `valid_until_tick`                                                                                                             | rolling compatibility projections                                | projection only                      | n/a                                                                  | recompute only for `message_action`; general-envelope values never decide lifecycle | old columns are not fallback authority                                                                               |
| `message_action.created_game_tick`, `resolved_game_tick`                                                                                                                   | action occurrence/resolution                                     | GAME occurrence                      | stop                                                                 | KEEP                                                                                | actionable message lifecycle is separate from envelope                                                               |
| `message_action.expires_game_tick`                                                                                                                                         | proposal response deadline                                       | GAME                                 | stop                                                                 | SHIFT                                                                               | remaining game duration survives pause                                                                               |
| `message_action.clock_revision`, `deadline_generation`                                                                                                                     | response fence                                                   | GAME metadata                        | stop                                                                 | REBUILD                                                                             | stale responses are rejected                                                                                         |
| `message_action.created_at_wall`, `updated_at_wall`; `message_read_state.updated_at`                                                                                       | audit/read occurrence                                            | WALL, DB UTC                         | advance                                                              | excluded                                                                            | community UX state                                                                                                   |
| `diplomacy_letter.date`                                                                                                                                                    | document authored/sent time                                      | WALL, DB UTC                         | advance                                                              | excluded                                                                            | game effect dates live in diplomacy/action state, not the document timestamp                                         |
| diplomacy war/nonaggression start/end month data                                                                                                                           | diplomatic effect schedule                                       | GAME calendar                        | stop                                                                 | handled by engine schedule                                                          | affects world turns and war validity                                                                                 |
| `inheritance_point.updated_at`, `inheritance_log.created_at`, `inheritance_result.created_at`, baseline/user-state audit fields                                            | account ledger/result audit                                      | WALL, DB UTC                         | advance                                                              | excluded                                                                            | account/external-currency history                                                                                    |
| `inheritance_ledger.requested_at_wall`, `consumed_at_wall`, `created_at_wall`                                                                                              | direct purchase receipt                                          | WALL, DB UTC                         | advance                                                              | excluded                                                                            | real request/debit receipt                                                                                           |
| `inheritance_ledger.applied_clock_revision`, `applied_deadline_generation`                                                                                                 | game-effect fence metadata                                       | GAME metadata                        | stop                                                                 | KEEP                                                                                | no `applied_game_tick`: current direct effects are timeless immediate state changes                                  |
| inheritance command `input_event`                                                                                                                                          | durable effect state/idempotency                                 | WALL receipt + GAME processing fence | mixed, separated                                                     | only GAME coordinate participates                                                   | one transaction commits debit, receipt, effect, and command success; failure leaves durable input event and no debit |
| `auction.open_tick`, `auction_bid.occurred_game_tick`                                                                                                                      | open/bid game occurrence                                         | GAME                                 | stop                                                                 | KEEP; bid `event_at` is projection                                                  | event order/RNG/replay context                                                                                       |
| `auction.close_tick`                                                                                                                                                       | in-world close deadline                                          | GAME                                 | stop                                                                 | SHIFT; `close_at` projection                                                        | authoritative worker/finalizer deadline; missing tick fails closed                                                   |
| `auction_bid.requested_at_wall`, `created_at`; `auction.finalizing_at`, `finished_at`, `created_at`, `updated_at`                                                          | request/processing/audit                                         | WALL, DB UTC                         | advance                                                              | excluded                                                                            | real action and recovery history                                                                                     |
| `auction.latest_event_at`                                                                                                                                                  | optimistic compatibility projection of latest game event         | GAME projection                      | stop                                                                 | follows authoritative event tick                                                    | never used as wall deadline                                                                                          |
| `vote_poll.start_tick`, `end_tick`                                                                                                                                         | poll occurrence/deadline                                         | GAME                                 | stop                                                                 | KEEP/SHIFT; `start_at`/`end_at` projections                                         | poll is an in-world survey; missing deadline tick fails closed                                                       |
| `vote_poll.closed_at`, `created_at`, `updated_at`; `vote.created_at`; `vote_comment.created_at`                                                                            | closure/user/audit occurrence                                    | WALL, DB UTC                         | advance                                                              | excluded                                                                            | closure receipt and community content history                                                                        |
| tournament `nextTick`, `bettingCloseTick` in Redis                                                                                                                         | stage/betting deadlines                                          | GAME                                 | stop                                                                 | REBUILD; `nextAt`/`bettingCloseAt` projections                                      | stages advance with the world; legacy date-only state fails closed                                                   |
| nation betting open/close year-month and tournament phase                                                                                                                  | in-world availability                                            | GAME calendar/tick                   | stop                                                                 | engine/Redis participant                                                            | tied to tournament turns                                                                                             |
| tournament/nation bet submission                                                                                                                                           | user WALL request + effect at the current frozen GAME coordinate | WALL + GAME, separated               | submission is allowed during `SUSPENDED`; GAME deadline does not age | receipt excluded; GAME availability/fence retained                                  | pausing stage progress must not close an already-open betting window                                                 |
| `nation_betting.*_at`, `nation_bet.*_at`                                                                                                                                   | user/audit occurrence                                            | WALL, DB UTC                         | advance                                                              | excluded                                                                            | receipts, not close authority                                                                                        |
| `game_history.date`, old-general `turntime`, archived projected dates                                                                                                      | archived game-calendar projection                                | GAME historical display              | stop                                                                 | KEEP, never shifted                                                                 | immutable archive/replay record                                                                                      |
| archive/entity `created_at`, cancellation `opened_at`/`cancelled_at`, unification `completed_at`                                                                           | operation/archive audit                                          | WALL, DB UTC                         | advance                                                              | excluded                                                                            | real creation/completion facts                                                                                       |
| `general_turn_revision.lease_expires_at`, `nation_turn_revision.lease_expires_at` and audit timestamps                                                                     | edit lease/revision audit                                        | WALL, DB UTC                         | advance                                                              | excluded                                                                            | editor concurrency timeout                                                                                           |
| board post/comment, log/error/event, legacy migration timestamps                                                                                                           | content/audit/migration history                                  | WALL, DB UTC                         | advance                                                              | excluded                                                                            | community and operational evidence                                                                                   |

The year-9999 message sentinel remains a legacy projection only.
`MAX_SAFE_GAME_TICK` is the separate GAME-domain infinite sentinel. Neither is
converted into or used as the other domain's ordinary deadline.

## Gateway database inventory

Gateway has no gameplay clock authority. Every Gateway `DateTime` is WALL_TIME:

- `app_user`: identity/session/icon/terms/privacy/Kakao/grace/deletion/login and
  `created_at`/`updated_at` fields.
- access grants, retired identities, admin audits, user icons, legacy member
  logs, and migration timestamps.
- profile lifecycle `preopen_at`, `open_at`, `scheduled_start_at`, build request,
  start/completion/last-used, and row audit timestamps. These are real control
  plane schedules; they do not replace a profile's `world_state.clock_tick`.
- subscriptions/preferences/receipts/notifications and web-push delivery
  `available_at`, `locked_at`, `delivered_at`, expiration and audit fields.
- runtime actions, operations, releases, and bulk releases: schedule, start,
  completion, retry, lease, heartbeat, successful and audit timestamps.

Competitive Gateway operation/release claim and lease renewal decisions read
PostgreSQL `CURRENT_TIMESTAMP` inside the persistence transaction; the caller's
poll timestamp is not authoritative. A Gateway PREOPEN wall schedule is an operational request; once
the game exists, gameplay schedules use the game database tick.

## Process-local monotonic inventory

The following are `MONOTONIC_ELAPSED_TIME` and are never persisted: daemon/RPC
wait budgets, turn processing budgets, worker poll/resync intervals, lock
acquisition waits, readiness loops, short-lived cache TTLs, latency metrics, and
test wait loops. Production implementations use `performance.now()` where an
elapsed duration is measured. `Date.now()`/`new Date()` remains valid only when
creating or formatting a WALL occurrence, calculating a non-competitive auth
TTL for an external protocol, or providing an explicit test clock.

## API phase policy

| Operation                                                                                                                  | During `SUSPENDED` / `RECONCILING`                                    | Fence                                                                   |
| -------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| normal public/private/nation message send/read/delete, including receiving/reading an existing recruitment letter envelope | allowed                                                               | WALL DB transaction only; actionable deadline remains frozen GAME state |
| notification/account/inheritance history/audit reads                                                                       | allowed                                                               | WALL                                                                    |
| actionable message response                                                                                                | rejected/queued except the explicitly authorized unification response | daemon clock phase/revision/generation                                  |
| tournament/nation bet submission while its GAME window is open                                                             | allowed in `SUSPENDED`; rejected in `RECONCILING`                     | frozen GAME deadline + phase/revision/generation fence                  |
| tournament stage transition/close/settlement and nation-bet close/settlement                                               | not applied                                                           | daemon GAME fence                                                       |
| turn, reservation, war/diplomacy effect, auction, vote, other tournament mutation                                          | not applied                                                           | daemon GAME fence                                                       |
| direct inheritance state mutation                                                                                          | rejected if the daemon GAME fence cannot commit                       | atomic input-event + revision/generation fence                          |

There is currently no account-only inheritance purchase endpoint. Direct
inheritance commands use policy 1 (no debit if game mutation cannot commit), not
an ambiguous partially-applied state. Their `InputEvent.requestId` is the durable
idempotency/effect state; `InheritanceLedger.requestId` proves the one successful
receipt.

## `loadCurrentGameTime` call-site audit

All production call sites were reviewed. The remaining uses are GAME-only:

- `messages/store`: create/read/invalidate the separate `message_action`; normal
  envelope creation, display, read state, and deletion do not load game time.
- `messages/diplomaticResponse`: game-effect/log calendar context after an
  actionable response fence; the letter's authored date is DB WALL_TIME.
- auction `open`, `scheduler`, `worker`, and router: open/close tick projection,
  due evaluation, and fence context; bid receipt time is separate WALL_TIME.
- vote router, tournament router/worker: GAME poll/stage deadlines and Redis
  projection fences.
- troop/general/join selection routers: current world turn/schedule context;
  the NPC reservation mutation holds the clock advisory lock and `world_state`
  row fence before reading it.
- lobby: display-only projected server game time and phase.

No inheritance receipt, ordinary message timestamp/delete rule, audit log,
lease, outbox retry, API timeout, or worker budget calls this helper.

Ordinary message send/read-state/delete mutations retain their durable API
`InputEvent` transaction and read-model journal, but use the WALL-only input
boundary. That boundary deliberately does not acquire the game clock advisory
lock, so a reconciliation transaction cannot unnecessarily serialize community
messaging. Actionable responses continue to use the GAME-fenced boundary.

## Migration boundary

Migration `20260903140000_split_message_wall_and_game_time` adds and backfills
the explicit message, action, auction-bid, inheritance receipt, and selection
cooldown authorities. It never extends an already-expired message delete window.
Old projection columns remain during rolling deployment, but new code never
chooses a clock by NULL fallback: GAME rules require their tick; WALL rules use
their wall column. The disposable migration verifier covers populated upgrade,
indexes/constraints, replay safety, and a second no-op deploy.

Migration `20260903183000_turn_daemon_lease_utc_wall` treats daemon leases as
ephemeral WALL authority: it expires pre-deployment rows, changes the heartbeat
default to DB UTC, and requires the new daemon to acquire a fresh fencing epoch.
Migration `20260903201500_complete_invader_game_clock` moves historical
`isUnited>=3` worlds from `RUNNING`/`MANUAL` to `COMPLETED` and resolves pending
unchosen invader actions at `max(created_game_tick, world_state.clock_tick)`.
Neither migration shifts a WALL occurrence or turns one rule into a clock
fallback.

## WALL lease precision and query parameters

Gateway operation/release lease recovery rechecks expiration in the database
under the existing claim lock. It does not compare a JavaScript Date to the
original `timestamptz(6)` value: that round trip loses microseconds and can prevent
expired jobs from being reclaimed. Owner fences and renewal checks remain active.
Read-model outbox dispatch casts an injected WALL timestamp explicitly before
subtracting a retry interval; production still defaults to the database WALL clock.
