Skip to content

Anchor-Repair Service

Status: 📐 Design-only — Fully unbuilt and honestly marked 📐 Design-only: no anchor_repair_service, no Phase-11 anchor-check or placement-helper symbols resolve, no repair events … (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 WR12. Anchor placement is set at galaxy generation in Phase 11 per ./galaxy-generator-design.md.

Galaxy generation Phase 11 anchors four critical structures per region: the Capital welcome planet (TERRA), the Class-1 commerce station, SpaceDock #1 (starter-cluster anchor), and SpaceDock #2 (frontier anchor). These are load-bearing for new-player onboarding, faction-rep economics, and ship-construction services. Phase 11 is worldgen-time only — no runtime mechanism detects-and-repairs a missing anchor (e.g., destroyed in late-game faction war, or never injected due to a Phase 11 transient failure that wasn't caught by Phase 13 validation).

This service is the daily-cadence safety net that detects missing anchors and re-injects them.

Cadence and scan target

Cadence: daily at UTC midnight (alongside the ./region-lifecycle.md WR9 cron — same scheduler tick).

Scan target: each Region with status = 'active'. Skipped for pending, suspended, grace, terminated, generation_corrupt, attachment_pending. Skipped for Central Nexus (it has its own anchor model).

Anchor checks per region

For each active region, verify all four Phase-11 anchors:

Anchor Check
Capital welcome planet EXISTS row in Planet with region_id = region.id, sector_number = region.capital_sector_number, planet_type = 'TERRA'
Class-1 commerce station EXISTS row in Station with region_id = region.id, station_class = CLASS_1, sector_number IN (region.capital_sector_number + 1, ...starter-cluster fallback)
SpaceDock #1 (starter-cluster anchor) EXISTS row in Station with region_id = region.id, is_spacedock = true, region_assignment_role = 'starter_cluster', in starter cluster
SpaceDock #2 (frontier anchor) EXISTS row in Station with region_id = region.id, is_spacedock = true, region_assignment_role = 'frontier', in Frontier zone

Each check is a single existence query. Total per-region cost: 4 SQL queries; very small.

Action on missing anchor

For each missing anchor:

  1. Re-inject via Phase 11 placement logic. The placement code lives in services/gameserver/src/services/galaxy_service.py:GalaxyGenerator._place_phase_11_anchors (or equivalent helper). The service imports it directly — no duplication.
  2. Idempotent placement: the helper picks the canonical anchor sector, but if that sector is occupied by player infrastructure (e.g., a player station has been built in the Capital sector + 1 since worldgen), the placement falls back per the same Phase 11 fallback rules (next eligible sector within the cluster).
  3. On success: emit region_anchor_repaired realtime event with the anchor type and the new placement sector. Operator dashboard shows the repair in the audit log.
  4. On failure (no eligible sector available, or other validation rule blocks it): emit region_anchor_repair_failed realtime event + admin alert (email/Slack). The region remains active but with the missing anchor — manual ops intervention required.

Idempotency

  • A region with all four anchors intact is a no-op pass (4 quick existence queries, 0 actions).
  • Running the service twice on a region with a missing anchor is safe — the second pass finds the anchor already injected by the first pass.
  • A missing anchor that fails injection is logged and alerted, but the service does not retry within the same daily run; the next day's pass tries again.

Why daily, not faster

Anchor destruction is rare. Capital welcome planets, Class-1 stations, and SpaceDocks are heavily defended (citadel-level structures + faction patrol presence). Players generally cannot destroy them; the failure mode is mostly "Phase 11 had a transient bug that Phase 13 missed, and the anchor was never injected" — a worldgen-time issue caught at the next daily scan.

A more frequent cadence (hourly, every-15-min) would burn cycles re-checking unchanged regions for the rare destruction event. Daily catches the realistic failure modes without overhead.

Failure modes

Mode Detection Handling
Service down for > 1 day Heartbeat absent for > 24h On restart, runs immediately; backlogged repairs surface.
Re-injection fails (sector occupied + fallback exhausted) Placement helper returns failure Emit region_anchor_repair_failed + admin alert. Region operates with missing anchor until manual ops fix.
Re-injection succeeds but the new anchor is in an unexpected location Placement-helper picked a fallback Emit region_anchor_repaired with the chosen sector in the payload; operator can review and decide if a manual relocation is warranted.
Multiple service instances scanning concurrently Two instances both attempt re-injection on the same region The placement helper uses a per-region advisory lock (pg_advisory_xact_lock(hashtext('region:' || region_id))), per the SK18 pattern from ADR-0050. One instance wins; the other no-ops.

Source map

Concern Path (target)
Service entry point services/gameserver/src/services/anchor_repair_service.py:run_daily_scan
Cron / scheduler services/gameserver/src/scheduling/cron_jobs.py:anchor_repair_daily
Phase 11 placement helper (reused) services/gameserver/src/services/galaxy_service.py:GalaxyGenerator._place_phase_11_anchors
Per-region advisory lock Shared utility (per ADR-0050 SK18 pattern)
Realtime event emission Existing realtime_bus.emit for region_anchor_repaired / region_anchor_repair_failed