Central Nexus Districts¶
Purpose¶
The Central Nexus is a single 5,000-sector region (Region.region_type = CENTRAL_NEXUS) that serves as the universal hub connecting all player-owned regions. Internally, the Nexus is partitioned into 10 thematic districts that drive sector spawn density, security/development/traffic gradients, and economic specialization.
Districts are a generation-time grouping layer distinct from Zone: the Nexus has exactly one Zone (EXPANSE, policing_level = 3, danger_level = 6), while districts are an additional cross-cut used by the generator and by Nexus-aware UI/admin tooling.
Inputs¶
The district generator reads:
total_sectors = 5000— fixed Nexus size.DISTRICT_CONFIGURATION— the 10-row table below (sector counts, security/development/traffic ranges, characteristics).- Generation
seed— propagated from the parent Nexus generation pipeline. Regionrow created by the Nexus generator (region_type = CENTRAL_NEXUS).Zonerow created by the Nexus generator (name = "The Expanse").
Process¶
District materialization runs as a phase inside the Nexus generation pipeline (see ./galaxy-generation.md):
┌──────────────────────────┐
│ Nexus Region + Zone made │
└──────────────┬───────────┘
▼
┌──────────────────────────┐
│ Partition 5000 sectors │
│ into 10 districts by │
│ contiguous sector range │
└──────────────┬───────────┘
▼
┌──────────────────────────┐
│ For each district: │
│ - allocate clusters │
│ - bias cluster type by │
│ district characters │
│ - generate sectors with │
│ security / dev / traf │
│ drawn uniformly from │
│ district ranges │
└──────────────┬───────────┘
▼
┌──────────────────────────┐
│ Tag each sector and │
│ cluster with district id │
│ (Sector.district) │
└──────────────────────────┘
Step-by-step:
- Range partition. The 5,000 Nexus sectors are partitioned into 10 contiguous ranges based on the per-district
sectorscount, in the legacyDistrictConfigurationdeclaration order. Ranges are computed at generator boot from the configuration table — they are not hard-coded. The generator validates the running sum equals 5,000 before any DB write. - Cluster allocation. Cluster generation runs within each district. Cluster
economic_focusandcontrolling_factionare biased by the district'scharacteristicslist (e.g.industrial_zonefavoursINDUSTRIAL/MANUFACTURINGclusters;research_campusfavoursSCIENCE;free_trade_zoneraises the weight onBLACK_MARKET/SMUGGLINGcluster types). The bias function takes the characteristics list and returns a weighted pool ofClusterTypevalues; the cluster's final type is sampled from that pool. - Sector roll. For each sector in a district,
security_level,development_level, andtraffic_levelare drawn uniformly at random from the district's[min, max]ranges (inclusive on both ends). The seed is mixed with the sector number so the same seed reproduces the same per-sector draws. - District tagging. Each generated
Sectorrow is written with itsdistrictslug; theClusteris likewise tagged so admin queries (WHERE region_id = nexus AND district = 'free_trade_zone') are O(index-lookup) viaidx_sectors_nexus_district. - Zone assignment. Every sector — regardless of district — is assigned to the Nexus's single
EXPANSEzone. Districts are an orthogonal grouping; they do not override zone policing/danger. A district's highsecurity_leveldoes not change its zone'spolicing_level; the security level is per-sector and additive on top of zone-level policing. - SpaceDock placement. Sector 1 is created first as the SpaceDock anchor and tagged
transit_hubdirectly. The remaining 4,999 sectors are then partitioned:transit_hub's configured count of 400 absorbs the SpaceDock slot, so 399 additional sectors are drawn from the partition for that district. Range arithmetic for all other districts is unaffected.
District table¶
The legacy DistrictConfiguration declares ten districts by sector count, not by an explicit numeric range. The generator derives contiguous ranges from those counts in declaration order. Counts sum to exactly 5,000.
| District | Sectors | Sector range | Security | Development | Traffic | Characteristics |
|---|---|---|---|---|---|---|
commerce_central |
500 | 1 – 500 | 7 – 9 | 8 – 10 | 8 – 10 | premium_markets, trade_hubs, financial_centers |
diplomatic_quarter |
300 | 501 – 800 | 8 – 10 | 7 – 9 | 4 – 7 | embassies, negotiation_chambers, cultural_centers |
industrial_zone |
600 | 801 – 1400 | 4 – 7 | 6 – 9 | 6 – 9 | manufacturing, shipyards, industrial_complexes |
residential_district |
800 | 1401 – 2200 | 5 – 8 | 5 – 8 | 3 – 6 | housing, services, entertainment |
transit_hub |
400 | 2201 – 2600 | 6 – 8 | 7 – 10 | 8 – 10 | warp_gates, transportation, logistics |
high_security_zone |
200 | 2601 – 2800 | 9 – 10 | 8 – 10 | 1 – 3 | restricted_access, high_value, premium_services |
cultural_center |
350 | 2801 – 3150 | 6 – 8 | 6 – 9 | 5 – 8 | events, festivals, cultural_exchange |
research_campus |
450 | 3151 – 3600 | 7 – 9 | 8 – 10 | 3 – 6 | technology, innovation, research_facilities |
free_trade_zone |
600 | 3601 – 4200 | 3 – 6 | 5 – 8 | 7 – 10 | unrestricted_trade, black_market, smuggling |
gateway_plaza |
800 | 4201 – 5000 | 6 – 8 | 6 – 8 | 8 – 10 | welcome_center, orientation, first_contact |
Notes:
- Sector numbers are Nexus-internal; in deployments where Nexus sectors are namespaced behind a Terran-space prefix the generator applies the offset uniformly (the within-district order and count are unchanged).
- Districts are listed in legacy declaration order, not in sector-range order. The numeric ranges above are the canonical mapping derived from that order.
sector 1(the SpaceDock-bearing sector) falls insidecommerce_centralby raw range, but is reassigned totransit_hub(see Invariants).
District semantics¶
Each district's characteristics list is an unordered set of free-form tags that informs three downstream behaviours:
Cluster-type bias¶
The cluster generator looks up each characteristic in a CHARACTERISTIC_TO_CLUSTER_WEIGHT map and accumulates weights into a sampling pool. Sample mappings:
| Characteristic | Boosted ClusterType |
|---|---|
manufacturing, shipyards, industrial_complexes |
INDUSTRIAL, MANUFACTURING |
technology, innovation, research_facilities |
SCIENCE, TECH |
premium_markets, trade_hubs, financial_centers |
COMMERCIAL, FINANCIAL |
unrestricted_trade, black_market, smuggling |
BLACK_MARKET, SMUGGLING |
embassies, negotiation_chambers |
DIPLOMATIC |
events, festivals, cultural_exchange |
CULTURAL |
restricted_access, high_value, premium_services |
MILITARY, RESTRICTED |
warp_gates, transportation, logistics |
TRANSIT |
welcome_center, orientation, first_contact |
GATEWAY, STANDARD |
housing, services, entertainment |
RESIDENTIAL, STANDARD |
If no characteristic matches any entry, the generator falls back to ClusterType.STANDARD.
Faction control¶
Each district's leading characteristic projects a controlling_faction onto its clusters:
| District | Default controlling_faction |
|---|---|
commerce_central |
MERCHANT_GUILD |
diplomatic_quarter |
FEDERATION |
industrial_zone |
INDUSTRIAL_CONSORTIUM |
residential_district |
CIVILIAN_AUTHORITY |
transit_hub |
TRANSPORT_AUTHORITY |
high_security_zone |
FEDERATION_MILITARY |
cultural_center |
CULTURAL_FEDERATION |
research_campus |
SCIENCE_COUNCIL |
free_trade_zone |
INDEPENDENT |
gateway_plaza |
FEDERATION |
These defaults are overridable per cluster by admin tooling; the generator only seeds them.
Spawn-distribution shape¶
The securityRange / developmentRange / trafficRange triples are the only stochastic inputs the per-sector roll consumes. They are uniform distributions, not biased toward midpoint. Two consequences:
- A district like
high_security_zone(security 9–10) cannot legally produce a low-security sector. Combat AI and patrol-spawn logic that key off Nexus sectors can therefore assume the floor. - A district like
free_trade_zone(security 3–6) intentionally never produces high-security sectors, so smuggler/black-market spawn rules can rely on the ceiling.
The generator does not currently weight draws by sector position within a district (e.g. denser at the centre); position-weighted draws are a future extension.
Outputs / state changes¶
For each Nexus generation run:
Region— one row,name = "central-nexus",region_type = CENTRAL_NEXUS.Zone— one row,name = "The Expanse",policing_level = 3,danger_level = 6,region_id = nexus.id.Cluster— multiple rows per district. Each row carriesregion_id,districtslug,cluster_type,economic_focus, andcontrolling_factionderived from the district's characteristics.Sector— 5,000 rows. Each carries:region_id = nexus.idzone_id = expanse.iddistrict— the slug from the table abovecluster_id— its parent clustersecurity_level∈ districtsecurityRangedevelopment_level∈ districtdevelopmentRangetraffic_level∈ districttrafficRange
No game-time events are emitted; this is a generation-phase write only. Subsequent edits (admin reassignment of a sector's district, for example) go through the normal Sector write path and trigger no special hook.
Invariants¶
- Sum-to-5000.
sum(district.sectors for district in DISTRICT_CONFIGURATION) == 5000. Enforced at generator boot. - No overlap. District sector ranges are contiguous and disjoint; every Nexus sector belongs to exactly one district.
- Total coverage. No Nexus sector has
district = NULL. - Single zone. Every Nexus sector has
zone_id = (the single Expanse zone). Districts never replace zones. - SpaceDock anchor. Sector 1 is reserved for the Nexus SpaceDock and is assigned to
transit_hubregardless of where its raw sector number falls in the range table — the generator places SpaceDock first, then partitions the remaining 4,999 sectors into the configured counts (withtransit_hublosing one slot to absorb sector 1). - Deterministic with seed. Given identical
seedand identicalDISTRICT_CONFIGURATION, the generator produces an identical district-to-sector mapping. - Range monotonicity. Within a district, generated
security_level,development_level, andtraffic_levelare bounded by the district's[min, max]inclusive on both ends.
Failure modes¶
| Mode | Target handling |
|---|---|
| District counts don't sum to 5,000 | Generator aborts at boot with ConfigurationError("district sectors sum != 5000"). No DB writes. |
District securityRange[0] > securityRange[1] (or dev/traffic) |
Generator aborts at boot with ConfigurationError("invalid range for <district>"). |
| Duplicate district slug in configuration | Generator aborts at boot with ConfigurationError("duplicate district slug"). |
| Cluster type bias produces zero-weight pool | Fall back to ClusterType.STANDARD for that cluster; emit a warning log carrying the offending district slug. |
| Random draw lands outside expected range (impossible barring code bug) | Generator clamps to range and logs an error so the test suite catches the regression. |
| Nexus already exists when generation runs | Generator returns {"status": "exists"}; districts are not rewritten or re-tagged. |
| Sector 1 already exists in another district on re-run | Idempotent re-run skips re-partition; the mismatch is recorded in the admin audit log for manual review. |
| District count drifts from 10 (config edit adds/removes a district) | Generator runs against the new shape so long as counts still sum to 5,000; admin tooling reads the live configuration rather than assuming "10". |
Admin operations¶
Admin tooling targets the district layer directly:
GET /api/v1/admin/nexus/districts— returns the liveDISTRICT_CONFIGURATION(slug, count, ranges, characteristics) for every district, plus per-district counts of generated clusters and sectors.GET /api/v1/admin/nexus/districts/{slug}— district detail, including the cluster list and aggregate security/development/traffic histograms.POST /api/v1/admin/nexus/districts/{slug}/regenerate— re-rolls the district's sector attributes in place (keeps sector ids; rerolls security/development/traffic from current ranges). Bounded by an admin-confirm step because it overwrites live state.PATCH /api/v1/admin/nexus/sectors/{sector_id}— admin override for a single sector'sdistrict,security_level,development_level, ortraffic_level. Writes an audit-log entry taggednexus.district_override.
District configuration itself is not runtime-editable through the API; changes go through code in nexus_districts.py and require a Nexus regeneration to take effect on existing rows.
Source map¶
| Concern | Path (target) |
|---|---|
| District configuration table | services/gameserver/src/core/nexus_districts.py |
| Nexus generation service | services/gameserver/src/services/nexus_generation_service.py |
| Nexus admin routes | services/gameserver/src/api/routes/nexus.py |
Sector.district column |
services/gameserver/src/models/sector.py |
Cluster.district column |
services/gameserver/src/models/cluster.py |
| Cluster type bias logic | services/gameserver/src/services/nexus_generation_service.py:_bias_cluster_type |
| Per-sector attribute roll | services/gameserver/src/services/nexus_generation_service.py:_roll_sector_attributes |
| Index for district queries | migration idx_sectors_nexus_district on sectors(region_id, district) |
| Audit-log channel for district overrides | services/gameserver/src/services/audit_service.py (event tag nexus.district_override) |
Related¶
- DATA_MODELS:
../DATA_MODELS/galaxy.md— Region, Cluster, Zone schema. - OPERATIONS:
../OPERATIONS/multi-regional.md— operational view of multi-regional architecture and the Nexus's role as universal hub. - FEATURES:
../FEATURES/galaxy/generation.md— player-/designer-facing galaxy generation overview, including the "10 specialized districts" summary. - SYSTEMS:
./galaxy-generation.md— the generation pipeline that calls Nexus generation and, in turn, district partitioning.