Skip to content

Galaxy / Region / Cluster / Zone / Sector / WarpTunnel

Status: 🚧 Partial — Galaxy/Cluster/Zone/Sector/WarpTunnel/SectorCelestial model layer is committed; design-only items confirmed absent (is_latent on warps, ANOMALY sector type, message_beacons, is_outlaw_zone … · ⚠︎ contains code↔spec divergence (impl audit 2026-06-16)

The spatial hierarchy. Region is the unified ownership unit. Regions contain Clusters (thematic groupings) and Zones (security/policing slices). A Sector belongs to exactly one Cluster and at most one Zone.

Galaxy (singleton metadata)
  └─ Region (Central Nexus | Terran Space | Player-owned)
       ├─ Cluster (navigation/thematic)
       │    └─ Sector
       └─ Zone (security: EXPANSE/FEDERATION/BORDER/FRONTIER)
            └─ Sector (also belongs to a Cluster)

Schema status

Per ADR-0066 D-V1, schema-level implementation status is consolidated here. Field descriptions describe the target schema.

Design-only columns — present in the spec, not yet committed:

  • Region: tier-headroom widening of total_sectors upper bound, nebula_properties.
  • Sector: ANOMALY enum value on type; x_coord / y_coord / z_coord Quantum-Jump bearing-projection use; is_nexus_protected, message_beacons, is_outlaw_zone, is_npc_barracks_sector.
  • sector_warps, WarpTunnel: is_latent flag (per ADR-0034).
  • WarpTunnel: Quantum-Jump construction_cost field.

All other columns on this page are committed.


Galaxy

Source: services/gameserver/src/models/galaxy.py

Purpose: Singleton metadata + global statistics container. Subdivision happens at the Region level.

Fields:

name type constraints notes
id UUID PK
name String(100) not null
statistics JSONB not null counts: total_sectors, discovered_sectors, station_count, planet_count, player_count, team_count, warp_tunnel_count, genesis_count
density JSONB not null station_density %, planet_density %, one_way_warp_percentage, resource_distribution map
faction_influence JSONB not null per-faction influence numbers
state JSONB not null age_in_days, resource_depletion, economic_health, exploration_percentage, player_wealth_distribution
events JSONB not null active_events / scheduled_events arrays (sector-scoped phenomena: spacetime anomalies, warp storms — see SYSTEMS/sector-presence.md)
max_sectors Integer nullable Soft observability target, not enforced. Per SK23 in ADR-0050, the galaxy has no hard sector cap — it grows organically as paying subscribers buy regions. Operator dashboards can alert at thresholds for capacity planning. Per-region cap lives on Region.total_sectors (CHECK 100–1500).
resources_regenerate Boolean default true
default_turns_per_day Integer default 1000
combat_penalties JSONB not null per-zone-type penalty levels (federation/border/frontier)
economic_modifiers JSONB not null
hidden_sectors Integer default 5
special_features ARRAY(String) default []

Relationships: none directly modeled on Galaxy; aggregates are populated from related entities via update_statistics(). Region is the ownership/cascade root for sectors.


Region

Source: services/gameserver/src/models/region.py

Purpose: Owned territory unit. Three kinds: Central Nexus (5000 sectors, the universal hub), Terran Space (the operator-run vanilla starter region that ships at universe creation), and player-owned (subscription-purchased regions, sized by tier; Standard tier targets ~1000 sectors with ±20% variability — see ../OPERATIONS/multi-regional.md). Player regions attach to the Central Nexus when provisioned, like petals on a flower.

Sectors are identified by a compound key (Region.id, Cluster.id, Sector.sector_number). Sector numbers are scoped to the region, not globally unique — Region A's sector 47 and Region B's sector 47 are distinct sectors with no relationship to each other. The compound tuple is what guarantees universe-wide identity.

Fields:

name type constraints notes
id UUID PK
name String(255) unique machine name
display_name String(255) not null
region_type String(50) default player_owned enum-like: central_nexus / terran_space / player_owned
owner_id UUID FK users.id nullable null for special regions
subscription_tier String(50) default standard
paypal_subscription_id, subscription_status, subscription_started_at, subscription_expires_at, last_payment_at, next_billing_at mixed nullable PayPal billing trail
status String(50) default active pending / active / suspended / grace / terminated / generation_corrupt / attachment_pending — extended per ADR-0050. State transitions documented in ../SYSTEMS/region-lifecycle.md.
suspended_at DateTime nullable Set on transition to suspended (payment failure event). Cleared on takeover or payment recovery. Per ADR-0050.
terminated_at DateTime nullable Set on transition to terminated (30 days suspended, no payment recovery, no takeover).
scheduled_hard_delete_at DateTime nullable terminated_at + 7 days; cleanup orchestrator targets this for the final region row + content hard-delete via CASCADE.
generation_seed BigInteger not null The seed used at Phase 0 input validation. Required for ops repro and bang-side reproducibility. Per SK19 in ADR-0050.
generation_phase_checksums JSONB default {} Per-phase row-count sentinels committed at each phase boundary; restart re-verifies counts before advancing. Schema: {phase_N: {row_count, duration_ms, completed_at}} per phase 1–14. Per SK17 in ADR-0050.
governance_type String(50) default autocracy autocracy/democracy/council
voting_threshold DECIMAL(3,2) default 0.51, 0.1–0.9 check constraint
election_frequency_days Integer default 90, 30–365 check constraint
constitutional_text Text nullable
tax_rate DECIMAL(5,4) default 0.10, 0.0–0.25 check constraint (zero permitted for tax-haven regional governance)
trade_bonuses JSONB default {} per-resource multipliers
economic_specialization String(50) nullable
starting_credits Integer default 1000, ≥100
starting_ship String(50) default scout
language_pack, aesthetic_theme, traditions, social_hierarchy JSONB default {} cultural identity
nexus_warp_sector Integer nullable Frontier-zone sector hosting the bidirectional natural warp to the Central Nexus, per ADR-0043. The warp is is_latent = true; per-player visibility lives in player_warp_knowledge per ADR-0045. Null for Central Nexus and Terran Space.
total_sectors Integer default 1000, CHECK 100–1,500 sized by subscription_tier for player regions; fixed for central_nexus (5000) and terran_space (300). Standard tier 800–1,200 (±20% from 1,000); higher tiers widen the upper bound — schema CHECK 100–1,500 accommodates Standard plus tier headroom.
capital_sector_number Integer not null The region-local sector_number of the Capital Sector (welcome hub, population-hub planet host, only place pioneer migration contracts can be secured). Randomly placed inside the Federation Zone of player regions. Fixed at sector 1 for Terran Space; canonically anchored in the Gateway Plaza cluster of the Central Nexus. See ../SYSTEMS/galaxy-generation.md#step-8-capital-sector.
active_players_30d, total_trade_volume counts default 0
pirate_ecosystem_state JSONB default {} Cached ecosystem snapshot per ADR-0048. Formal shape per ADR-0065 R-I5: {current_population_score: int, current_target: int, suppression_modifier: float (0.20..1.0), kill_weight_last_30_days: float, zero_population_since: iso8601 or null, cleansed_at: iso8601 or null, last_growth_tick_at: iso8601, last_evolution_tick_at: iso8601, evolutions_since_creation: int}. Updated by the weekly tick service. Authoritative source remains the live PirateHolding and PirateKillLog tables; this column is the fast-path read cache.

Relationships: - ownerUser (FK owner_id). - membershipsRegionalMembership (1:many, cascade delete). - zones / clusters / sectors / planets / stations (1:many). - elections, policies, treaties_as_a, treaties_as_b for governance/diplomacy.


Cluster

Source: services/gameserver/src/models/cluster.py

Purpose: Thematic grouping of sectors inside a Region (resource-rich, trade hub, frontier outpost, etc.).

Fields:

name type constraints notes
id UUID PK
name String(100) not null, UNIQUE per (region_id, name) AI-generated at bang time per ADR-0044; names are unique within a region (two regions may each have a "Commerce Central").
region_id UUID FK regions.id not null, CASCADE
type Enum cluster_type not null STANDARD, RESOURCE_RICH, POPULATION_CENTER, TRADE_HUB, MILITARY_ZONE, FRONTIER_OUTPOST, CONTESTED, SPECIAL_INTEREST
sector_count Integer default 0
is_discovered Boolean default true
discovery_requirement JSONB nullable gates discovery
stats JSONB not null total_sectors, populated_sectors, resource_value, danger_level, development_index, exploration_percentage
resource_modifiers JSONB default {}
economic_focus ARRAY(String) default []
resources JSONB not null primary_resources, resource_distribution, special_resources
economic_value Integer default 50 0-100
controlling_faction String nullable null = contested
faction_influence JSONB not null per-faction numbers + dominant_faction
nav_hazards ARRAY(String) default []
recommended_ship_class String default light_freighter
x_coord, y_coord, z_coord Integer default 0
special_features ARRAY(String) default []
is_hidden Boolean default false
warp_stability Float default 1.0
nebula_properties JSONB nullable nebula_type (Crimson/Azure/Emerald/Violet/Amber/Obsidian), color_hex (canonical galaxy-map render colors per ../FEATURES/galaxy/quantum-resources.md#nebula-types-and-field-strengths — Crimson #DC143C, Azure #1E90FF, Emerald #00FF7F, Violet #9370DB, Amber #FF8C00, Obsidian #2F4F4F), quantum_field_strength (0–100), shard_yield_band, secondary_effect, coverage_pct. Set when the cluster overlaps a nebula; null otherwise.

Relationships: - regionRegion (FK). - sectorsSector (1:many, cascade delete).


Zone

Source: services/gameserver/src/models/zone.py

Purpose: Security/policing slice of a Region defined by a sector-number range. Independent of cluster organization; orthogonal dimension.

Fields:

name type constraints notes
id UUID PK
region_id UUID FK regions.id not null, CASCADE, indexed
name String(200) not null e.g., "The Expanse", "Federation Space"
zone_type Enum zone_type not null EXPANSE, FEDERATION, BORDER, FRONTIER
start_sector Integer not null, ≥1 check constraint
end_sector Integer not null, ≥ start_sector check constraint
policing_level Integer default 5, 0–10 check constraint
danger_rating Integer default 5, 0–10 check constraint

Relationships: - regionRegion. - sectorsSector (1:many, cascade delete).


Sector

Source: services/gameserver/src/models/sector.py

Purpose: A discrete navigable space; the basic location unit for ships, planets, stations, drones, and combat.

Fields:

name type constraints notes
id UUID PK global UUID; used internally for FKs
sector_number Integer not null, part of composite UNIQUE (region_id, sector_number) region-scoped human-readable sector number; Region A's sector 47 and Region B's sector 47 are distinct. The compound key (region_id, cluster_id, sector_number) is the canonical identifier surfaced in UI and APIs (per ADR-0005).
name String(100) not null
region_id UUID FK regions.id not null, CASCADE
cluster_id UUID FK clusters.id not null, CASCADE
zone_id UUID FK zones.id nullable, SET NULL, indexed
type Enum sector_type default STANDARD STANDARD/NEBULA/ASTEROID_FIELD/BLACK_HOLE/RADIATION_ZONE/WARP_STORM/ANOMALY (ANOMALY is the spatial-oddity sector type with investigation-driven Quantum Shard / Lumen Crystal drops per ../FEATURES/galaxy/quantum-resources.md#2-anomaly-investigation-secondary; ~1–2% of generated sectors across all zones)
security_level, development_level, traffic_level Integer default 5/1/1 1-10
is_discovered Boolean default true
discovered_by_id UUID FK players.id nullable
discovery_date DateTime nullable
x_coord, y_coord, z_coord Integer not null 3D coordinates inside the parent region's coordinate frame. These integers are the basis for Quantum Jump bearing projection: the Phase 1 long-range scan cone and the Phase 3 arrival resolver both use true Euclidean distance computed from (x_coord, y_coord, z_coord) to project a bearing vector and select destination candidates within an accuracy radius (see ../FEATURES/galaxy/sectors.md#quantum-jump-warp-jumper).
radiation_level Float default 0.0
hazard_level Integer default 0 0-10
resources JSONB not null has_asteroids, asteroid_yield (ore/precious_metals/radioactives), gas_clouds, has_scanned
resource_regeneration Float default 1.0
players_present JSONB default [] live presence list
ships_present JSONB default []
defenses JSONB not null defense_drones, owner_id, owner_name, team_id, mines, mine_owner_id (player-controlled); patrol_ships (NPC-only — Federation patrols, faction-territory enforcement, pirate raid groups)
controlling_faction String nullable
controlling_team_id UUID FK teams.id nullable
last_combat DateTime nullable
active_events, special_features, nav_hazards, nav_beacons JSONB / ARRAY defaults
description String nullable
is_nexus_protected Boolean default false When true, the sector is part of the Nexus Sentinel Corps protected-sector set. Warp-gate Phase 1 deploy-beacon attempts in this sector are rejected with ERR_NEXUS_PROTECTED_SECTOR, and a Sentinel squad spawns and intercepts on attempted bypass. The galaxy generator's Phase 12.5b sets this on the Nexus Capital sector (2251) and all Gateway Plaza cluster sectors (2251–2500); operator-tunable for other Nexus clusters. See ../FEATURES/gameplay/police-forces.md.
message_beacons JSONB default [] Denormalized array of player-deployed message-beacon summaries (id, deployer_nickname, deployed_at, message preview, expiry) for fast sector-view reads. The canonical MessageBeacon rows live in their own table; this JSONB is a denormalized read-fast cache updated on deploy / salvage / expiry. See ../FEATURES/gameplay/message-beacons.md.
is_outlaw_zone Boolean default false When true, the sector hosts an OutlawBase for hostile-faction NPCs (pirates, Cabal). Player warp-gate construction is rejected in outlaw zones (a backstop similar to is_nexus_protected). See ./npc-lodging.md.
is_npc_barracks_sector Boolean default false Set when an NPCBarracks row's location_type = sector and points at this sector (e.g., the dedicated Sentinel barracks sector in Gateway Plaza). Surfaces in player-info UI as "this is a Sentinel barracks sector."

Relationships: - cluster (FK), zone (FK), region (FK). - planets, stations (1:many, cascade delete). - ships via Ship.sector_id (note: integer FK by sector_id, not UUID). - discovered_byPlayer, controlling_teamTeam. - deployed_dronesDrone, drone_deploymentsDroneDeployment, fleetsFleet. - outgoing_warps / incoming_warps (many-to-many via sector_warps). - warp_tunnels_origin, warp_tunnels_destinationWarpTunnel (1:many each direction).

sector_warps (association table)

Cheap point-to-point warp links — the heavier WarpTunnel is a separate concept with its own metadata. Carries the local-graph one-ways that natural worldgen and certain formations stamp (BACKDOOR, the local end of ESCAPE_HATCH, WARP_SINK).

name type constraints notes
source_sector_id UUID FK sectors.id PK part 1
destination_sector_id UUID FK sectors.id PK part 2
is_bidirectional Boolean default true false flags this row as a one-way link from source → destination. Per ADR-0034, directionality lives only on this column — never on a type enum.
is_latent Boolean default false true means the warp looks bidirectional in the raw sector view until revealed by a Warp Jumper's existing scan suite (Quantum Jump scan). ~20% of one-ways are latent; ~80% are marked (visible directional glyph in the player UI). — see ADR-0034 and ../FEATURES/galaxy/sectors.md#one-way-warps.
turn_cost Integer default 1
warp_stability Float default 1.0
created_at DateTime not null

WarpTunnel

Source: services/gameserver/src/models/warp_tunnel.py

Purpose: Named, often artificial, sector-to-sector connection with lifecycle, traversal cost, and discovery state — distinct from the lightweight sector_warps table.

Fields:

name type constraints notes
id UUID PK
name String(100) not null
origin_sector_id UUID FK sectors.id not null, CASCADE
destination_sector_id UUID FK sectors.id not null, CASCADE
type Enum warp_tunnel_type not null see Type enum below
status Enum warp_tunnel_status default ACTIVE see Status enum below
is_bidirectional Boolean default true false flags this tunnel as a one-way link from origin → destination. Used by the long-distance variant of ESCAPE_HATCH. Player-built warp gates anchor this flag to false at Phase 3 commit (gates are intrinsically one-way; reverse traversal requires a separately-built gate). Per ADR-0034, directionality lives only on this column — never on the type enum.
is_latent Boolean default false true means the tunnel looks bidirectional until revealed by a Warp Jumper's existing scan suite. ~20% of one-way tunnels are latent; ~80% are marked. — see ADR-0034 and ../FEATURES/galaxy/sectors.md#one-way-warps.
stability Float default 1.0 continuous score 0.0–1.0
stability_enum Enum warp_tunnel_stability_enum default STABLE discrete classification: STABLE / UNSTABLE
properties JSONB not null length, stability_rating, expected_lifetime, age, traversal_cost, cool_down, discovered, discoverer_id, discovery_date, affected_by_storms
tunnel_status JSONB not null is_active, disruption, traffic_level, last_traversal, maintenance_status
source_endpoint, destination_endpoint JSONB not null sector/cluster/region/coordinates/controlling_faction/is_secured/access_requirements
artificial_data JSONB nullable management data for player-built tunnels
total_traversals Integer default 0
traversal_history JSONB default []
turn_cost Integer default 1 mirrors properties.traversal_cost
energy_cost Integer default 0
is_public Boolean default true
access_requirements JSONB nullable
created_by_player_id UUID FK players.id nullable
created_by_faction String nullable
construction_cost Integer nullable Snapshot of the gate's all-in construction cost at build commit time (Warp Jumper hull value + Lumen Crystals + Phase 1–3 materials, summed at then-current market prices). Set on ARTIFICIAL tunnels with created_by_player_id IS NOT NULL; null for natural tunnels and operator-placed artificials. Immutable after build. Per ADR-0052 SK38, this snapshot drives the 50% refund on cascade-driven gate destruction.
max_uses, current_uses Integer nullable / default 0
expires_at DateTime nullable
special_effects JSONB default {}

Type enum (warp_tunnel_type)

Two values:

  • NATURAL — formed by spacetime fold during galaxy generation. Most tunnels in the universe. No maintenance, no owner.
  • ARTIFICIAL — engineered tunnel. Two sources, distinguished by created_by_player_id:
  • created_by_player_id IS NULL — generator-placed at world creation. Used to densely interconnect the low-numbered sectors of each region (sectors 1..fedspaceSize) so new-player areas remain well-connected regardless of random natural-tunnel layout.
  • created_by_player_id IS NOT NULL — player-built warp gate produced by the beacon → focus → quantum-link construction pipeline (see ../FEATURES/galaxy/warp-gates.md). Owner controls access, may charge tolls, can be destroyed.

Tunnel direction (one-way vs. bidirectional) is captured by the is_bidirectional column on the WarpTunnel row, not by the type.

Status enum (warp_tunnel_status)

  • ACTIVE — in normal use.
  • UNSTABLE — random failure rate elevated; usable.
  • DEGRADING — stability is dropping over time; collapse imminent.
  • COLLAPSED — no longer traversable; row kept for archaeology.
  • MAINTENANCE — owner has paused traffic for repairs/upgrades.
  • FORMING — under construction (player gate beacon/focus phase).
  • INITIALIZING — Phase 3 harmonization in progress. The Warp Jumper is in HARMONIZING ship-status and the focus structure has spawned, but the tunnel is not yet open for traffic. Flips to ACTIVE at harmonization-completion commit (per ADR-0036). Traversal attempts during this state fail with ERR_GATE_INITIALIZING.

Stability: continuous vs. discrete

stability (Float, 0.0–1.0) is the live continuous score consumed by traversal-risk calculations and decay ticks. stability_enum is the discrete bucket (STABLE / UNSTABLE) used for indexing, list filters, and UI badging. The two are kept consistent: when stability crosses the unstable threshold, stability_enum flips and status may advance to UNSTABLE or DEGRADING.

Disruption & maintenance

The tunnel_status JSONB blob carries the live operational signals:

  • disruption — active anomaly events (warp storms, gravitational shear, faction interdiction) that prevent traversal while present. Disruption events are randomly seeded by the world tick (e.g., warp storms sweeping a cluster) and clear after a defined duration; the tunnel returns to its prior status when the disruption expires.
  • last_traversal — timestamp of the most recent successful transit; feeds cool-down and traffic analytics.
  • maintenance_status — owner-initiated state for player-built gates only. While maintenance is in progress, traffic is paused and status is set to MAINTENANCE; the tunnel returns to ACTIVE on completion.
  • traffic_level — rolling counter feeding congestion modifiers and economic telemetry.

Natural tunnels never enter MAINTENANCE; only artificial (player-gated) tunnels expose maintenance controls.

State transitions

FORMING ──► ACTIVE ◄──► UNSTABLE ──► DEGRADING ──► COLLAPSED
              │
              ▼
         MAINTENANCE ──► ACTIVE

FORMING is the construction phase for artificial tunnels. ACTIVE is the steady state. UNSTABLE is reversible — stability can recover and the tunnel returns to ACTIVE. Once a tunnel enters DEGRADING, collapse is the only terminal: it advances to COLLAPSED and the row is retained for archaeology and discovery history. MAINTENANCE is reachable only from ACTIVE on player-owned tunnels and always returns to ACTIVE.

Relationships: - origin_sector, destination_sectorSector. - created_byPlayer.

Note: Per-traversal cost and stability are authoritative inside the properties JSONB (traversal_cost, stability_rating); the column-level turn_cost and stability fields are denormalized mirrors used for indexing and quick filters.

See also: - FEATURES/galaxy/warp-gates.md — player gate construction, beacon/focus phases, and maintenance flows for ARTIFICIAL tunnels. Gate construction requires a Warp Jumper to reach the destination first; that reach is provided by Quantum Jump (see Sector schema note above). - FEATURES/galaxy/sectors.md — natural-tunnel seeding, the lightweight sector_warps association table, and how sectors expose adjacency.

SectorCelestial — solar-system composition

A sector's "solar system" (its star(s), habitable zone, planets/orbits, belt, nebula, debris) is a persisted, generate-once-then-stable model — a dedicated sector_celestials table (1:1 with Sector), not JSONB on the hot, FOR-UPDATE-locked sectors row (ADR-0073). The gameplay/design rules (star types, HZ bands, orbit speed, axial rotation, generation weights) are canonized in FEATURES/galaxy/star-systems.md; this is the persistence shape.

Status: ✅ Shipped — services/gameserver/src/models/sector_celestial.py (SectorCelestial); filled by celestial_service.generate_skeleton, read through GET /api/v1/sectors/{id}/system.

sector_celestials

Column Type Notes
sector_uuid UUID PK FK → sectors.id (cascade delete)
sector_id Integer indexed; mirrors Sector.sector_id for convenience lookup
composition JSONB the deterministic procedural skeleton (below). Real Planet/Station rows are not stored here — they are merged over the skeleton at read time
seed BigInteger the sector_id × SECTOR_SEED_SALT root seed
created_at / updated_at timestamptz generate-once; mutable thereafter

composition JSONB shape

{
  star: { kind, label, color, secondary? } | null,   // null = VOID sector
  extra_stars?: [{ kind, color }],                    // STAR_CLUSTER: 2–4
  nebula?: { hue, density },                           // NEBULA sectors
  belt?: { inner_au, outer_au },                       // ASTEROID_FIELD always; else ~15%
  debris?: { inner_au, outer_au },                     // ~12% collision ring
  habitable_zone?: { inner_au, outer_au },             // per star kind; absent for neutron/black-hole
  bodies: [{
    slot, orbit_au, phase_deg,                         // orbit position + initial revolution phase
    kind,                                              // PlanetType (procedural subset, or real planet's type once merged)
    size_class, palette: { hue, sat }, rings, moons,
    rotation_period_hours, axial_tilt_deg,             // axial spin (the local "day" + obliquity) — distinct from revolution
    real: bool, planet_id?, name?, habitability?, owned?, can_rename?
  }]
}

All body fields are deterministic from the body's sub-seed. rotation_period_hours + axial_tilt_deg drive the windshield's per-planet axial spin (see star-systems.md → "Planet rotation"); the live orbital and spin angles are recomputed client-side per frame and not stored.

Relationships: sector_uuidSector (1:1, cascade delete). A sibling sector_feature_discoveries table tracks per-sector hidden-feature discovery ((sector, feature_type) unique), kept separate from planet discovery and the sector's own first-discoverer (ADR-0073).