Skip to content

Quantum Nebula Depletion Service

Status: 📐 Design-only — Fully unbuilt and honestly marked 📐 Design-only: no quantum_depletion_service, no Sector.depletion_state/depletion_replenish_at schema, no nebula_replenished event … (impl audit 2026-06-16)

📐 Design-only. No service code is committed yet; this page is the prescriptive runtime spec. Canonical decision in ADR-0053 WR6. Player-facing nebula-depletion mechanics live in ../FEATURES/galaxy/quantum-resources.md.

The runtime that walks Sector rows where quantum nebulae have been harvested, tracks their replenishment timers, and transitions them back toward HEALTHY state. Depletion timers per-color are spec'd in quantum-resources.md (Crimson 14 days; all other colors 5 days). This service implements the timer.

Cadence and scan target

Cadence: every 60 seconds (UTC).

Scan target: Sector rows where:

SELECT * FROM sectors
WHERE depletion_state IS NOT NULL
  AND depletion_state != 'HEALTHY'
  AND depletion_replenish_at <= NOW()
FOR UPDATE SKIP LOCKED;

The SKIP LOCKED clause makes multiple service instances safe — concurrent scans don't block each other or double-process rows.

Action

For each scanned row, transition the depletion state one step healthier:

Current state Next state Action
DEPLETED RECOVERING Set depletion_replenish_at = now() + per_color_timer
RECOVERING HEALTHY Clear depletion_replenish_at; emit nebula_replenished realtime event
HEALTHY (no-op) This state shouldn't be in the scan; if encountered, log warning

The per-color timer (when transitioning from DEPLETED → RECOVERING) is:

Nebula color Timer
Crimson 14 days
Azure 5 days
Emerald 5 days
Violet 5 days
Amber 5 days
Obsidian 5 days

A nebula sector cycles HEALTHY → DEPLETED (on harvest) → RECOVERING (after timer 1) → HEALTHY (after timer 2). Total round-trip: 28 days for Crimson, 10 days for the others.

Realtime emission

When a sector transitions to HEALTHY, the service emits:

{
  "event_type": "nebula_replenished",
  "sector_id": "uuid",
  "region_id": "uuid",
  "nebula_color": "crimson",
  "replenished_at": "iso8601"
}

Subscribers: any player in the sector, any player with the sector marked in their ARIA exploration map, and the region's owner (for governance dashboard awareness).

Idempotency

  • Running the service twice in quick succession with no eligible rows is a no-op.
  • Running with overlapping scans (multiple instances) uses SKIP LOCKED to avoid double-processing.
  • A row whose timer hasn't elapsed yet is filtered out at the SQL level — never picked up.

Failure modes

Mode Detection Handling
Service down for > 1 minute Heartbeat absent On restart, the next tick processes any backlog. Replenishment timers extend by however long the service was down. Acceptable — the granularity is days; minutes of skew per outage is invisible.
DB connection failure mid-scan Transaction rollback Row stays in pre-transition state; next tick retries.
Sector deleted mid-tick (region terminated, etc.) Row no longer exists at update time Skipped silently. The terminating region's cleanup orchestrator handles cascade-deletion of the sector and its replenishment state goes with it.
depletion_replenish_at somehow null on a non-HEALTHY row Defensive check Log warning, treat row as if depletion_replenish_at = now() − 1 so the next tick can transition it.

Source map

Concern Path (target)
Service entry point services/gameserver/src/services/quantum_depletion_service.py:run_tick
Cron / scheduler services/gameserver/src/scheduling/cron_jobs.py:quantum_depletion_tick (60-sec cadence)
Realtime event emission Existing realtime_bus.emit for nebula_replenished
Sector model fields Sector.depletion_state, Sector.depletion_replenish_at (per DATA_MODELS/galaxy.md)