Bang integration¶
Status: 🚧 Partial — Path A (admin job) and the core translator are fully wired; Path B bootstrap script is absent, version versioning logic is simplified. Re-corrected 2026-08-06 (supersedes 2026-08-04, now stale): a gameserver-side validation gate (
galaxy_validation.py) shipped 2026-08-05 and runs structural/referential-integrity checks on import — but per-formation placement invariants (WARP_SINK/BUBBLE) and content-layer counts remain bang-side-only, not re-checked by the gate. See../SYSTEMS/bang-import-pipeline.md§ Canonicality contract for the precise coverage boundary.Status. The
sw2102-bangsidecar is the live generator path: the admin-ui's "Bang a New Galaxy!" form drives a bang generation job (Path A), and the gameserver'sBangImportServicetranslates its output and persists it. The in-processPOST /admin/galaxy/generateendpoint returns HTTP 410. The contract documented below is the canonical bang↔gameserver boundary; the fully standalone-service split, the completeUniverseJSON envelope, and thebang.*PostgreSQL schema remain launch-target. See../SYSTEMS/galaxy-generation.md.
sw2102-bang is the standalone universe generator that produces a fresh galaxy. The gameserver consumes its output to bootstrap (or rebuild) the world. This page documents the contract between the two repos.
The generator lives at https://github.com/.../sw2102-bang. The gameserver is services/gameserver/ inside the Sectorwars2102 repo. The two communicate by writing to and reading from the shared PostgreSQL database; there is no HTTP coupling.
Two execution modes¶
sw2102-bang supports two entry points. Both produce the same Universe shape internally; they differ in where the result goes.
CLI mode — JSON to disk or stdout¶
bigbang [options]
The CLI writes the generated universe as JSON to stdout, an output file, or as a human summary. Use this for review, reproducibility checks, and offline tooling.
Source: sw2102-bang/src/cli.ts
| Flag | Default | Meaning |
|---|---|---|
--sectors, -s <n> |
1000 | Total sectors (clamped 20-20000) |
--seed <n> |
random | RNG seed; same seed + same config = same universe |
--density <n> |
20 | Max course length, controls overall density (3-50). Recorded on Universe.config; enforcement semantics are pinned in a follow-up doc PR alongside bang's first enforcement implementation. |
--two-way-warps <n> |
30 | Two-way warp percentage (5-100). Drives the FORCED bidirectional bucket size; the total observed bidirectional fraction also includes natural k-NN symmetry from the bulge density gradient and is reported in --summary. |
--one-way-warps <n> |
5 | One-way warp percentage (0-25), the canon ~5% target ratified by ADR-0093 item 16 (WO-BANG-ONEWAY-ALGO; folded from ADR-0093, re-verified 2026-08-07). Drives the FORCED one-way bucket size; the remainder of pairs preserves natural k-NN symmetry. |
--max-warps <n> |
6 | Max warps per sector (2-10). Strictly enforced via post-categorization drop; bidirectional warps count toward both endpoints' degree, one-way warps only toward the source. |
--port-percent <n> |
omitted → densityFor(regionType) |
Sectors with ports (0-80). When omitted, schema 1.3.8 fills from region type: Central Nexus 5%, Terran Space / Player-Owned 15% (../FEATURES/galaxy/generation.md Step 2). Explicit value wins. |
--planet-percent <n> |
omitted → densityFor(regionType) |
Sectors with planets (0-60). When omitted: Central Nexus 10%, Terran Space / Player-Owned 25%. Explicit value wins. |
--nebula-percent <n> |
5 | Sectors in nebulae (0-30) |
--fedspace <n> |
10 | Federation-protected sectors (2-20) |
--stardock <n> |
0 (auto) | Stardock sector ID; 0 means auto-pick |
--region-type <r> |
player_owned |
Region kind: player_owned | terran_space | central_nexus. central_nexus requires --sectors=5000 (canonical 20-cluster overlay). Invalid values exit 2. |
--config-json <path\|-> |
— | GenerationRequest JSON from file or stdin (-). Individual CLI flags override conflicting fields (conflicts warn on stderr). |
--output, -o <file> |
stdout | Write JSON to file |
--summary |
off | Print a human-readable summary to stderr |
--render |
off | Print an ASCII map of the galaxy to stderr (3D → 2D projection with chalk colors). Density-binned grid; fedspace highlighted; cell-color gradient by sector count. |
--render-axis <axis> |
top | Projection axis for --render: top (XY plane), side (XZ plane), or iso (isometric). |
--no-color |
off | Disable chalk color codes in --render output. Useful for non-tty redirects, CI logs, and snapshot tests. |
--compact |
off | Compact JSON (no formatting) |
--quiet, -q |
off | Suppress progress output on stderr |
The same options resolve through resolveConfig() (sw2102-bang/src/config.ts), which clamps inputs, auto-picks a seed when seed === 0, and (schema 1.3.8 / LEG-48) fills omitted portPercent/planetPercent via densityFor(regionType).
Service mode — write directly to PostgreSQL¶
The generator can also run as a one-shot container that writes to a database and exits. This is the integration path with the gameserver.
docker compose up generator
Source: sw2102-bang/src/db-writer.ts, sw2102-bang/Dockerfile.generator, sw2102-bang/docker-compose.yml
Configuration is via environment variables:
| Env var | Default | Meaning |
|---|---|---|
DATABASE_URL |
postgresql://tw2102:tw2102@localhost:5432/tw2102 |
Connection string |
UNIVERSE_NAME |
default |
Identifier; reuse to overwrite |
TW_SECTORS |
1000 |
Total sectors |
TW_SEED |
random | RNG seed |
TW_REGION_TYPE |
unset → player_owned via bigbang |
player_owned | terran_space | central_nexus — pass via -e / env (not wired as a compose environment: default; same pattern as optional TW_PORT_PERCENT / TW_PLANET_PERCENT). central_nexus requires TW_SECTORS=5000. |
TW_PORT_PERCENT |
omitted → densityFor(regionType) |
Port density (0-80). Same region-derived defaults as --port-percent when unset; set env to override. |
TW_PLANET_PERCENT |
omitted → densityFor(regionType) |
Planet density (0-60). Same region-derived defaults as --planet-percent when unset; set env to override. |
The container waits for the database to accept connections, generates a universe, deletes any existing universe with the same name, and writes the new one in a single transaction.
Output shape — JSON¶
The CLI emits the Universe interface from sw2102-bang/src/types.ts, with the internal sectors map serialized as a keyed object. Per ADR-0069, bang emits a fully-formed region snapshot: the topology graph plus the named clusters, special formations, station and planet inventories, citadel content, and NPC rosters that go with it. Faction-influence values, the Region row, cross-region warp wiring, and runtime state remain gameserver-side.
Honesty (LEG-1147): bang wire commodity keys are gameserver-canonical — port JSON uses ore, not the retired fuel_ore name (sw2102-bang/src/content.ts TRADING_PATTERNS). The gameserver translator may still accept legacy aliases on ingest; do not treat fuel_ore as bang's primary emit key.
{
"version": "1.1.0",
"seed": 42,
"totalSectors": 1000,
"sectors": {
"1": {
"id": 1,
"position": {"x": 0, "y": 0, "z": 0},
"warps": [2, 3, 7],
"port": {
"name": "Capital Station",
"class": 1,
"black_market": false,
"commodities": {
"ore": {"action": "B", "quantity": 1000, "capacity": 5000, "regenRate": 100},
"organics": {"action": "B", "quantity": 800, "capacity": 3000, "regenRate": 80},
"equipment": {"action": "S", "quantity": 500, "capacity": 2000, "regenRate": 50}
}
},
"planets": [
{
"name": "Terra",
"type": "earth",
"owner": null,
"ore": 0,
"organics": 0,
"equipment": 0,
"colonists": 0,
"citadel": {
"level": 1,
"droneCapacity": 100,
"safeContents": 0
}
}
],
"navHazards": [
{"type": "mine", "owner": null, "quantity": 4}
],
"nebula": null,
"beacon": null,
"explored": true
}
},
"warps": [
{"from": 1, "to": 2, "oneWay": false}
],
"clusters": [
{
"id": 1,
"name": "Gateway Plaza",
"sectorRangeStart": 1,
"sectorRangeEnd": 250,
"type": "TRADE_HUB"
}
],
"specialFormations": [
{
"id": "f-001",
"type": "BUBBLE",
"anchorSectorId": 412,
"interiorSectorIds": [413, 414, 415, 416],
"properties": {
"interiorSize": 4,
"linkTunnelDepth": 0
}
},
{
"id": "f-002",
"type": "LOST_SECTOR",
"anchorSectorId": 731,
"interiorSectorIds": [731],
"properties": {
"exitWarp": null
}
},
{
"id": "f-003",
"type": "LOST_CLUSTER",
"anchorSectorId": 812,
"interiorSectorIds": [812, 813, 814, "...", 833],
"properties": {
"interiorClusterId": 7,
"exitWarp": { "sourceSectorId": 820, "destinationSectorId": 504 }
}
},
{
"id": "f-004",
"type": "ARCHIPELAGO",
"anchorSectorId": 850,
"interiorSectorIds": [850, 851, "...", 949],
"properties": {
"memberClusterIds": [8, 9, 10],
"crossWarpCount": 5,
"exitWarps": [
{ "sourceSectorId": 905, "destinationSectorId": 612 }
]
}
}
],
"npcRosters": [
{
"kind": "federation_marshal",
"factionCode": "terran_federation",
"targetCount": 9,
"hostSectorId": 5,
"namePool": ["..."]
}
],
"specialLocations": [
{"type": "terra", "sectorId": 1},
{"type": "stardock", "sectorId": 173},
{"type": "rylan", "sectorId": 401},
{"type": "alpha_centauri", "sectorId": 9},
{"type": "fringe_homeworld", "sectorId": 600}
],
"fedspaceSectors": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
"config": { "...": "the BigBangConfig used to generate this universe" },
"createdAt": "2026-04-30T18:00:00.000Z"
}
Field reference (from sw2102-bang/src/types.ts):
- Sectors. Each sector has a
position(integer 3D coordinates scaled by 10000, range roughly[-10000, 10000]),warps(an array of destination sector IDs), an optionalport, an array ofplanets, an array ofnavHazards, an optionalnebula, an optionalbeacon, and anexploredflag. - Ports. Class 0 is reserved for special ports (Stardock); classes 1–8 encode buy/sell combinations across the nine gameserver-canonical commodities (
ore,organics,equipment,fuel,precious_metals,gourmet_food,exotic_technology,luxury_goods,colonists) via bang'sTRADING_PATTERNStable (sw2102-bang/src/content.ts). Per-class coverage is enforced at generation time by validator rule B-200 (requiredCommoditiesFor()). Each commodity tracksaction(Bfor buying,Sfor selling),quantity,capacity, andregenRate. Per ADR-0069,quantityis the initial seeded value produced by bang's deterministic seeding pass (the gameserver translator passes pricing and seeding constants in as inputs so balance tuning stays gameserver-controlled, but the seed run itself executes inside bang). Feature status lives at../FEATURES/economy/trading.md. - Planets. Six types (
barren,earth,mountainous,oceanic,glacial,volcanic). Generator output carries the planet's initial inventory in the flatore,organics,equipment, andcolonistsfields (per ADR-0069, bang owns the seeded values — WO-BANG-PLANET-SEED-EMIT was greenlit alongside WO-BANG-ONEWAY-ALGO by ADR-0093 item 16, folded from ADR-0093, re-verified 2026-08-07) and, when a citadel is stamped, the citadel'slevel,droneCapacity, andsafeContents(numeric credit total — bang stamps0; populated safes are an operator-or-quest concern on the gameserver). - Citadels. Embedded inside each planet under
citadel.levelmatches the existing field;droneCapacityfollows the per-level table in../FEATURES/planets/citadels.md;safeContentsis a number (credit total) stamped0at generation time — bang does not emit the runtime vault object shape; the gameserver import maps it tocitadel_safe_contents(seebang_import_service.py). Named-safe quests populate vault contents post-import. - Nav hazards.
mine(Armid),limpet, orfighter(deployed); each carries an owner ID and quantity. Mine quantities per sector are bang's responsibility (already in scope; reaffirmed by ADR-0069). - Nebulae.
normal(hides contents) ormagnetic(disrupts navigation); 1-100 density. - Warps. A flat list paralleling each sector's
warpsarray; each entry specifiesfrom,to, andoneWay. - Clusters. One row per cluster in the region —
name(AI-generated per ADR-0044),sectorRangeStart/sectorRangeEnd, andtype(one of the standard cluster-type enum values). No faction-influence values — those depend on the gameserver's faction enum and stay gameserver-side, seeded post-import from the per-zone profile in../SYSTEMS/bang-import-pipeline.md. - Special formations. One row per stamped formation —
type(one of the 12 catalog values:BUBBLE,DEAD_END_BUBBLE,GOLD_BUBBLE,TUNNEL,DEAD_END,WARP_SINK,BACKDOOR,BLISTER,ESCAPE_HATCH, plus the lost-formation setLOST_SECTOR/LOST_CLUSTER/ARCHIPELAGOadded in ADR-0070),anchorSectorId,interiorSectorIds, and a type-specificpropertiesJSONB. Bang stamps lost formations first (Step 6.5a), then the rest of the catalog (Step 6.5b) between proximity-warp placement and long-distance-tunnel placement; long-distance tunnels (Step 7) skip lost-formation sector sets. Bang enforces invariants — notably ADR-0046's "noWARP_SINKinside aBUBBLE" and ADR-0070's "no external warps from a lost formation except the optional one-way exits" — internally so output is correct-by-construction. Re-corrected 2026-08-06 (supersedes 2026-08-04, now stale on the gate's existence though not its formation-placement claim): the gameserver still does not cross-check this specific WARP_SINK/BUBBLE placement invariant on import —galaxy_validation.py(shipped 2026-08-05, wired intobang_import_service.py) checks structural/referential integrity of formations (anchor/interior sectors exist in the plan) but not their placement semantics._validate_universe_shaperemains shape-only (required-key presence, version-prefix, sector-count) and runs first. Bang's own correct-by-construction guarantee is therefore still the only enforcement that exists for this specific invariant, even though a broader structural gate now runs on import. - NPC rosters. One row per worldgen-stamped roster:
kind(e.g.,federation_marshal,nexus_sentinel,pirate_captain),factionCode,targetCount,hostSectorId, and anamePoolfor runtime spawning. Bang emits the roster shapes specified by../FEATURES/gameplay/police-forces.mdPhase 12.5a (region rosters) and Phase 12.5b (Nexus rosters). NoNPCCharacterrows — runtime materialization (Phase 12.5c) stays gameserver-side vianpc_scheduler.bootstrap_region(region_id)after the import transaction commits. - Special locations. Terra, Stardock, Rylan, Alpha Centauri, Fringe Alliance homeworld; the generator places each one once.
- Fedspace. Sectors 1 through
fedspaceSize; protected from PvP.
Output shape — PostgreSQL¶
When run in service mode, the generator writes to the bang schema defined in sw2102-bang/db/init.sql:
| Table | Purpose | Key columns |
|---|---|---|
universes |
One row per generated universe. | id PK, name UNIQUE, version, seed, total_sectors, config (JSONB) |
sectors |
One row per sector. | id PK, universe_id FK, sector_number, beacon, explored |
warps |
Connections between sectors. | id PK, universe_id FK, from_sector, to_sector, one_way |
clusters |
One row per cluster (named, sector-range bounded). | id PK, universe_id FK, name, type, sector_range_start, sector_range_end |
special_formations |
One row per stamped formation. | id PK, universe_id FK, type, anchor_sector_id FK, interior_sector_ids (ARRAY), properties (JSONB) |
ports |
One row per port. | id PK, sector_id FK, name, class, commodities (JSONB — wire keys include ore/organics/equipment/…; quantity is the initial seeded value) |
planets |
One row per planet. | id PK, sector_id FK, name, type, owner, commodity columns (ore/organics/equipment/colonists — initial seeded values), citadel_level, citadel_drone_capacity, citadel_safe_contents (JSONB) |
nebulae |
One row per nebula sector. | id PK, sector_id FK, type, density |
nav_hazards |
One row per hazard placement. | id PK, sector_id FK, type, quantity, owner |
npc_rosters |
One row per worldgen-stamped roster. | id PK, universe_id FK, kind, faction_code, target_count, host_sector_id FK, name_pool (JSONB) |
special_locations |
Terra/Stardock/etc. | id PK, universe_id FK, type, sector_number |
The writer deletes any prior universes row with the same name (cascading to all dependent rows) and writes the new universe in a single BEGIN/COMMIT transaction with batched inserts (500 rows per batch).
Gameserver consumption¶
The bang schema does not match the gameserver's domain schema. The gameserver expects Galaxy, Region, Cluster, Zone, Sector, Planet, Station, WarpTunnel, SpecialFormation, NPCRoster rows with multi-region scaffolding (Central Nexus, Terran Space, player-owned regions), faction-influence values, security/development/traffic levels, and the Sectorwars-specific nine-commodity catalog.
Per ADR-0069, bang emits a fully-formed region snapshot — clusters, formations, station and planet inventories, citadel content, and NPC rosters all arrive in the payload. The gameserver translator's job is therefore narrower than a content-derivation pipeline: it shape-checks the payload (_validate_universe_shape — required-key presence, version-prefix, sector-count) and structurally validates the translated plan (galaxy_validation.py, shipped 2026-08-05 — referential integrity, not per-formation placement invariants, re-corrected 2026-08-06 — see § Special formations), scaffolds the rows that depend on per-customer state (the Region row plus its operator config: subscription tier, governance, tax rate, language pack, aesthetic theme), glues the imported entities into the multi-region world (cluster faction-influence percentages, cross-region warp-gate wiring, Nexus attachment), and projects bang port commodities onto the gameserver's nine-commodity wire (canonical keys from bang's TRADING_PATTERNS; catalog defaults fill any omitted key — see bang_import_service.py). It does not derive clusters, stamp formations, or seed inventories — those arrive ready in the payload.
The translation algorithm — numbered steps with explicit per-entity translation tables, JSONB defaults, idempotency rules, and failure modes — is specified in ../SYSTEMS/bang-import-pipeline.md. All three operational paths below invoke the same translator pipeline; they differ only in how the bang payload reaches the translator and where the trigger comes from.
Path A — admin-triggered import¶
The admin endpoint POST /admin/galaxy/import-bang (see Swagger at <api-host>/docs) is the operator-facing trigger. The handler:
- Receives the admin's parameters (target region context, sector count, seed, density, faction balance, optional overrides).
- Invokes the generator out-of-process (CLI mode with the requested params), capturing the JSON.
- Hands the captured JSON plus the target region context to the translator pipeline.
- Returns the new
Galaxy.idandRegion.idto the admin.
Used for: post-launch region creation, admin-driven re-imports, and player-region provisioning. Because the import takes 60–120 seconds for a 5,000-sector Nexus, the admin endpoint runs the translator as an async background job and returns a job ID; the admin UI polls the job until completion.
Path B — bootstrap script¶
For first-time environment setup, the generator runs as a one-shot container that writes to a separate bang database (see "Service mode" above). A bootstrap script then reads bang.universes plus dependent rows, hands them to the translator pipeline, and exits. The script lives at services/gameserver/scripts/bootstrap_from_bang.py (target). It accepts a bang connection URL, a target Galaxy.name, and the target region context, and runs once per region during environment bring-up — typically twice on a fresh install (central_nexus then terran_space).
Used for: initial environment provisioning, full-galaxy re-rolls during major releases.
Path C — Alembic data migration¶
For test fixtures and CI environments, the generator output is checked in as a JSON artifact under services/gameserver/tests/fixtures/bang/ (target) and replayed via an Alembic data migration. The migration calls the same translator pipeline with the JSON loaded from disk. Suitable for deterministic tests; unsuitable for production-sized galaxies due to file size and migration time.
Used for: integration test fixtures, deterministic CI seeds.
Per-entity translation¶
The full per-entity translation (Sector, Warp, Port → Station, Planet, Nebula → Cluster nebula classification, NavHazard, SpecialLocation, fedspaceSectors, Cluster → Cluster, SpecialFormation → SpecialFormation, NPCRoster → NPCRoster) is documented in the appendices of ../SYSTEMS/bang-import-pipeline.md:
- Appendix A — bang port commodity keys → gameserver nine-commodity wire (catalog defaults for any omitted key).
- Appendix B — bang
NebulaeType(2) → gameserver nebula classification (6) by zone bias and density. - Appendix C — bang
PlanetType(6) → gameserverPlanetTypeenum. - Appendix D — bang
SpecialLocationType→ gameserver Sectorspecial_featuresand associated rows. - Appendix E — bang Port
class0–8 → gameserverStationClassandStationType. - Appendix F — bang
Cluster(named, sector-range-bounded) → gameserverClusterrow with seeded faction-influence overlay. - Appendix G — bang
SpecialFormation→ gameserverSpecialFormationrow (1:1 type-and-properties copy; gameserver validates). - Appendix H — bang
NPCRoster→ gameserverNPCRosterrow, with Phase 12.5cbootstrap_regionhook running post-commit.
This operations doc does not duplicate the appendices; consult the SYSTEMS doc when implementing any of the three paths.
Reproducibility¶
Both modes are deterministic given a seed and a BigBangConfig. The same seed always produces the same universe regardless of when or where the generator runs. Operators wanting to reproduce a specific galaxy should record the seed and the full config from the universe row.
Versioning¶
The version field in the Universe and universes row is the generator schema version. The gameserver's translator must check this version against its supported-version allowlist and refuse to import an unknown one. Per ADR-0069, the contract is load-bearing: bang and the gameserver release in lockstep on contract bumps. Adding a field, changing a field's shape, or relocating an invariant from one side of the boundary to the other is a contract change and bumps the version.
Supported versions:
| Version | Status | Notes |
|---|---|---|
1.0.0 |
Legacy | Original shape; no per-sector position field. Translator at bang-import-pipeline.md step 7 synthesizes 3D coordinates from a Hilbert-curve packing of sector-number ranges. |
1.1.0 (and 1.1.0-pre.x pre-releases) |
Superseded | Adds Sector.position: {x, y, z} integer fields scaled by 10000. Translator step 7 consumes position directly; no Hilbert packing. Walking-skeleton releases of sw2102-bang emit 1.1.0-pre.0 to flag that content layers (ports, planets, nebulae, special locations) may be stubbed. |
1.3.4 |
Superseded | Adds Warp.is_latent (dormant/latent warp edges) and explicit capitalSector / Sector.isCapital fields. |
1.3.5 |
Superseded | Adds the additive optional Port.black_market: boolean (default false), set on a fraction of Frontier-zone ports (~4% provisional, seed-reproducible) per ../FEATURES/economy/black-market.md. The gameserver import-map reads this explicit flag → StationType.BLACK_MARKET, graceful-on-absent — so a bang universe below 1.3.5 simply produces no black-market venues, no import error. |
1.3.6 |
Superseded | LEG-12: additive optional Sector.resources (asteroid fields) and SpecialLocationType value cabal_hq; cluster-type content biases. See ../SYSTEMS/bang-import-pipeline.md Appendix D. |
1.3.7 |
Superseded | LEG-47: TRADE_HUB port-class weights and POPULATION_CENTER planet-type / habitability bias (wire format unchanged; version bump signals generation-output shift). |
1.3.8 |
Superseded | LEG-48: densityFor(regionType) supplies default portPercent/planetPercent when omitted (see CLI / resolveConfig above). Wire format unchanged. |
1.3.9 |
Superseded | LEG-50: minimum hop spacing between special-formation anchors (5 hops; 3 hops when totalSectors ≤ 300 per ADR-0051 SK34). Wire format unchanged. |
1.3.10 |
Superseded | LEG-148: non-Nexus FRONTIER_OUTPOST clusters emit isDiscovered: false (generation.md:101 qualitative lower starting-discovery; no invented percentage). Nexus clusters unchanged. Wire format unchanged. |
1.3.11 |
Current | LEG-265: additive optional Port.dockingSlips four-class inventory (transient / longTerm / construction / specializedConstruction) per ../FEATURES/economy/docking-slips.md. TradeDock Tier-A/B construction rows deferred until Bang assigns tradedock tiers. Matches tip SCHEMA_VERSION in sw2102-bang/src/types.ts (a17b9e4). |
Pre-release suffixes (1.1.0-pre.0, 1.1.0-pre.1, …) parse as >= 1.1.0 for the position-consumption rule but do not satisfy gameserver Phase 13 invariants that depend on content layers (e.g., #8 one TERRA at Capital, #9 two SpaceDocks). Pre-release imports are operator-only and require --allow-incomplete-content on the import endpoint (target).
BangGenerationJob lifecycle¶
Status: ✅ Shipped (Path A) — table
bang_generation_jobs(migrationa8d1f4e6c920), modelBangGenerationJob/ enumBangGenerationJobStatus, admin routes under/admin/galaxy/…, SSE log tail, startup orphan recovery. Documented from code 2026-08-05 (WO-CANON-DRAFT-BANG-GENERATION-JOB-LIFECYCLE).
Path A does not block the HTTP request on bang. The admin route inserts a job row, commits pre-created Region scaffolding, then schedules BangImportService.run_generation_job as a FastAPI background task. The row is the operator-visible source of truth for progress, logs, and failure.
States¶
| Status | Meaning |
|---|---|
PENDING |
Queued. Row committed; background task not yet flipped to RUNNING (advisory lock / bang subprocess not yet acquired). |
RUNNING |
Bang CLI subprocess(es) executing and/or translator writing. log_text is appended live; SSE clients poll/tail it. |
COMPLETE |
Transaction committed successfully. Galaxy is ready. Sets completed_at, duration_ms, warnings_json. |
FAILED |
Aborted — bang error, translator error, or orphan recovery. Sets completed_at + error_message. Pre-created Region rows named bang-{job_id}-{region_type} are reaped. |
Terminal states: COMPLETE, FAILED. No resume/retry-in-place — operator queues a new job.
Transitions (who writes)¶
PENDING ──(BangImportService._set_job_status)──► RUNNING
RUNNING ──(_mark_job_complete)─────────────────► COMPLETE
RUNNING ──(_mark_job_failed)───────────────────► FAILED
RUNNING ──(startup orphan sweep, age >5 min)───► FAILED (error_message="orphaned at startup")
- Create → PENDING:
POST /admin/galaxy/jobs(full 3-region bang),POST /admin/galaxy/{galaxy_id}/regions(additive player_owned), and related bang admin create routes inbang_galaxy.py. Always HTTP 202 with the job row. - PENDING → RUNNING / terminal: only
BangImportServicejob helpers (_set_job_status,_mark_job_complete,_mark_job_failed). - Orphan recovery: on gameserver startup (
main.py), anyRUNNINGrow withstarted_atolder than 5 minutes is force-failed. Indexix_bang_generation_jobs_status_started_atbacks that query.
Row payload (operator-facing)¶
| Column | Role |
|---|---|
params_json |
Serialized BangConfig — enough to re-run from history. |
warnings_json |
List of {category, code, message, data?} from bang / translator validators. |
log_text |
Concatenated bang stderr + translator progress; SSE endpoint streams this while RUNNING. |
duration_ms / error_message |
Set on terminal states. |
admin_user_id |
Operator who queued the job (ON DELETE RESTRICT). |
Observability endpoints¶
- List / get job: admin bang-galaxy job history routes (newest-first by
started_at). - Live log: SSE tail over
log_textwhile status isRUNNING(stops when the row leavesRUNNING).
Related¶
- The translator algorithm itself:
../SYSTEMS/bang-import-pipeline.md. Sixteen numbered steps, explicit JSONB defaults, invariants, failure modes, and full per-entity translation tables. - Universe data model on the gameserver side:
../DATA_MODELS/galaxy.md. - JSONB shapes the translator must produce:
../DATA_MODELS/jsonb-schema.md. - The admin endpoint that triggers Path A:
POST /admin/galaxy/jobs(and additive region routes — see live Swagger at<api-host>/docs). LegacyPOST /admin/galaxy/import-bang/ in-process generate paths are retired (HTTP 410 where still present). - Multi-region scaffolding the translator must establish:
./multi-regional.md. - Central Nexus cluster organization invoked by the translator on Nexus imports:
../SYSTEMS/central-nexus-clusters.md. - Broader generation pipeline that wraps this translator:
../SYSTEMS/galaxy-generation.md.