First foundation slice of the Atlas-to-tile derivation model (epic T-974), building the carrier layer ahead of its T-1027+ consumers. T-1026 — Anti-squaring domain warp (D-239 §4): stateless pure fn(seed,body_id,pos)->(f64,f64), ±8m, f64 to the final voxel then as-i32 truncation for IEEE-754 cross-target determinism. New domain_warp.rs, SeedDomain::DomainWarp; golden-vector + cross-thread tests. Position math only — D-010 integer discipline preserved downstream. Marked dead_code until the T-1028 VoxelColumn pipeline consumes it. T-1023 — RegionProfile carrier (D-239 §1,§10): new RegionProfile + TectonicClass/GlaciationGrade/PrecipitationClass enums + BodyParams; derived per-region river_threshold replacing the global 200 for tile consumers. regions: BTreeMap on BodyWorldState, populated via the cascade's new RegionProfile layer (runs when body_params is Some, else falls back to Settlement). D-010 integer discipline, BTree ordering. T-1024 — District climate primitives (D-239 §2): nullable temperature_c + moisture on RegionProfile, mean-annual scalar (no clock dep; dynamic branch deferred to Q-105). Hybrid inputs — new bodies.axial_tilt_deg column imported from planet-gen body-defs (populate_axial_tilt_deg, 2611 bodies), luminosity and orbital distance derived at runtime; greenhouse + diurnal-swing tables in source-canonical climate_constants.toml. D-239 implementation note added. cargo test: 1498 passed, 0 failed. clippy clean (pre-existing large_enum_variant only). make check-systems-db: stamp fresh. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
648 lines
32 KiB
SQL
648 lines
32 KiB
SQL
-- Star Systems Database Schema — server/data/systems.db
|
||
-- Source of truth for all structured star system data.
|
||
-- Authored via tooling pipeline; wiki pages are generated views.
|
||
-- Shipped with the game — read-only from the server's perspective.
|
||
--
|
||
-- Rebuild: tooling/process-wiki-system-changes --rebuild-db
|
||
|
||
PRAGMA journal_mode=WAL;
|
||
PRAGMA foreign_keys=ON;
|
||
|
||
-- Core identity, physical character, political character
|
||
CREATE TABLE IF NOT EXISTS star_systems (
|
||
system_id TEXT PRIMARY KEY, -- GJ catalog number (e.g., "GJ 244A")
|
||
proper_name TEXT,
|
||
system_name TEXT,
|
||
star_type TEXT,
|
||
spectral_class TEXT,
|
||
dist_ly REAL,
|
||
geographic_sector TEXT,
|
||
geographic_band TEXT,
|
||
political_zone TEXT,
|
||
|
||
-- Physical character
|
||
habitable_planet_count INTEGER,
|
||
inhabited_planet_count INTEGER,
|
||
asteroid_belt INTEGER, -- boolean 0/1
|
||
gas_giant INTEGER, -- boolean 0/1
|
||
habitability_profile TEXT,
|
||
|
||
-- Political character
|
||
earth_alignment TEXT,
|
||
earth_proximity TEXT,
|
||
earth_tension TEXT,
|
||
|
||
-- Content notes
|
||
stability_index INTEGER,
|
||
system_volatility TEXT,
|
||
cultural_corridor TEXT,
|
||
generation_priority TEXT,
|
||
|
||
-- Short narrative hook extracted from the wiki's gttr.md file — the
|
||
-- first characterisation paragraph ("where the rules live", "forty
|
||
-- years old and still in the draft", etc). Populated by
|
||
-- tooling/db/populate_gttr_hook.py from wiki/star-systems/<slug>/gttr.md.
|
||
-- Used as compact cultural context in the Gemma 2 naming pipeline
|
||
-- (#833) so per-system feel is grounded in the canonical identity
|
||
-- rather than generic corridor labels.
|
||
gttr_hook TEXT,
|
||
|
||
-- Economics (D-172)
|
||
currency_zone TEXT DEFAULT 'TRACTUS_PRIMARY', -- TRACTUS_PRIMARY | MARK_PRIMARY | MIXED
|
||
|
||
-- Energy-over-gate (D-186)
|
||
-- Gate Corp energy service: on-grid nodes get ~0.3× fusion_fuel utility demand.
|
||
-- MARK_PRIMARY zones default false (Compact refused Gate Corp dependency).
|
||
gate_energy_connected INTEGER DEFAULT 1, -- boolean 0/1
|
||
|
||
updated_at TEXT DEFAULT (datetime('now'))
|
||
);
|
||
|
||
-- Gate infrastructure — queried independently for pathfinding/topology
|
||
CREATE TABLE IF NOT EXISTS system_gates (
|
||
system_id TEXT PRIMARY KEY REFERENCES star_systems(system_id),
|
||
horizon_station INTEGER, -- boolean 0/1
|
||
aperture_count INTEGER,
|
||
gate_connections INTEGER,
|
||
gate_topology TEXT,
|
||
hop_distance_from_gateway INTEGER,
|
||
span_gate_network TEXT
|
||
);
|
||
|
||
-- Settlement history
|
||
CREATE TABLE IF NOT EXISTS system_history (
|
||
system_id TEXT PRIMARY KEY REFERENCES star_systems(system_id),
|
||
settlement_wave TEXT,
|
||
founding_motivation TEXT,
|
||
founding_culture_primary TEXT,
|
||
founding_culture_secondary TEXT,
|
||
cultural_persistence TEXT,
|
||
religious_status TEXT,
|
||
religious_generation_count INTEGER
|
||
);
|
||
|
||
-- Historical events — proper 1:N child table
|
||
CREATE TABLE IF NOT EXISTS historical_events (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
system_id TEXT NOT NULL REFERENCES star_systems(system_id),
|
||
event_type TEXT NOT NULL,
|
||
age_years INTEGER,
|
||
sort_order INTEGER NOT NULL DEFAULT 0 -- 0 = most recent
|
||
);
|
||
|
||
-- Economic life
|
||
CREATE TABLE IF NOT EXISTS system_economy (
|
||
system_id TEXT PRIMARY KEY REFERENCES star_systems(system_id),
|
||
economic_tier INTEGER,
|
||
population INTEGER,
|
||
economic_base_primary TEXT,
|
||
economic_base_secondary TEXT,
|
||
distribution_index TEXT,
|
||
imprint_access TEXT,
|
||
-- D-237 authored specialization layer (build-time; NULL = heuristic fallback)
|
||
economic_specialization TEXT, -- value in specialization_vocabulary.specialization_id
|
||
cultural_specialization TEXT -- activity- or heritage-type value; drives D-232 template pool (distinct from system_culture.cultural_register)
|
||
);
|
||
|
||
-- Faction presence
|
||
CREATE TABLE IF NOT EXISTS system_factions (
|
||
system_id TEXT PRIMARY KEY REFERENCES star_systems(system_id),
|
||
governance_type TEXT,
|
||
dominant_faction TEXT,
|
||
primary_fault_line TEXT,
|
||
secondary_fault_line TEXT,
|
||
assembly_presence TEXT,
|
||
commission_presence TEXT,
|
||
syndic_presence TEXT,
|
||
syndic_type TEXT,
|
||
separatist_presence TEXT,
|
||
separatist_type TEXT,
|
||
institute_presence TEXT,
|
||
guardians_presence TEXT
|
||
);
|
||
|
||
-- Cultural voice
|
||
CREATE TABLE IF NOT EXISTS system_culture (
|
||
system_id TEXT PRIMARY KEY REFERENCES star_systems(system_id),
|
||
cultural_register TEXT,
|
||
cultural_register_secondary TEXT,
|
||
ambient_anxiety TEXT,
|
||
local_pride TEXT,
|
||
atmospheric_tone TEXT,
|
||
atmospheric_tone_secondary TEXT,
|
||
active_situation TEXT,
|
||
silence_threshold TEXT,
|
||
primary_archetype TEXT,
|
||
secondary_archetype TEXT,
|
||
narrative_notable INTEGER -- boolean 0/1
|
||
);
|
||
|
||
-- Authored prose (supply_dependency, faction_notes, silence_topic,
|
||
-- narrative_hook, calibration_note) lives in wiki markdown files only.
|
||
-- No DB mirror — read the file if you need the text.
|
||
|
||
-- Celestial bodies — planets, moons, gas giants, asteroid belts, oort clouds
|
||
-- Naming convention:
|
||
-- GJ-{n}b/c/d... — planets (innermost first)
|
||
-- GJ-{n}Ab/c/d... — planets orbiting primary (binary systems)
|
||
-- GJ-{n}d-1 — first moon of third planet
|
||
-- GJ-{n}-oort — oort cloud region
|
||
-- GJ-{n}-belt — asteroid belt
|
||
CREATE TABLE IF NOT EXISTS bodies (
|
||
body_id TEXT PRIMARY KEY,
|
||
system_id TEXT NOT NULL REFERENCES star_systems(system_id),
|
||
parent_body_id TEXT REFERENCES bodies(body_id), -- NULL for planets; parent planet for moons
|
||
|
||
-- Classification
|
||
body_type TEXT NOT NULL, -- planet, moon, gas_giant, asteroid_belt, oort_cloud
|
||
orbit_index INTEGER, -- innermost = 1 (planets around star, moons around planet)
|
||
proper_name TEXT, -- "Xin Chengdu", NULL for unnamed
|
||
|
||
-- Physical
|
||
mass_class TEXT, -- terrestrial, super_earth, ice_giant, gas_giant, dwarf
|
||
atmosphere TEXT, -- breathable, thin, toxic, none, dense
|
||
surface_gravity REAL, -- in g (Earth = 1.0), NULL for gas giants
|
||
orbital_period_days REAL, -- orbital period in Earth days, NULL for oort/belt
|
||
rotation_period_hours REAL, -- rotation period in Earth hours (Earth = 24), NULL for tidally locked/gas giants
|
||
planet_class TEXT, -- temperate, arid, frozen, oceanic, volcanic, barren, etc.
|
||
hydrosphere TEXT, -- ocean, ice, rivers, none, subsurface
|
||
|
||
-- Settlement
|
||
inhabited INTEGER NOT NULL DEFAULT 0,
|
||
population INTEGER DEFAULT 0,
|
||
economic_role TEXT, -- manufacturing, agricultural, extraction, research, transit
|
||
founding_age_years INTEGER,
|
||
settlement_pattern TEXT, -- urban_concentrated, dispersed_rural, orbital_only, domed, cave
|
||
|
||
-- Cultural (inherited from system, can override)
|
||
cultural_corridor TEXT, -- override system corridor if different
|
||
industrial_corridor TEXT, -- MVG, Gate_Corp, DSMC, Prometheus, Agricultural_Syndic
|
||
|
||
-- Physical dimensions (D-204, #905)
|
||
-- Mean radius in km. NULL until authoritative data is available; fallback
|
||
-- derivation from planet_class is applied at query time by the generator.
|
||
body_radius_km REAL,
|
||
|
||
-- Axial tilt in degrees (T-1024, D-239 §2). Sourced from planet-gen body-def
|
||
-- frontmatter (wiki/star-systems/*/bodies/*/index.md, orbit.axial_tilt_deg).
|
||
-- NULL until populate_axial_tilt_deg runs. Used by district temperature
|
||
-- derivation: tilt determines latitude-band insolation gradient.
|
||
axial_tilt_deg REAL,
|
||
|
||
-- Rendering
|
||
-- terrain_reference: repo-root-relative path to the body's heightmap PNG.
|
||
-- Convention (enforced by populate_terrain_reference.py and assumed by
|
||
-- the atlas importers and the Godot client's atlas scene loader):
|
||
-- wiki/star-systems/<system_slug>/bodies/<body_id>/heightmap.png
|
||
-- where <system_slug> = system_id with spaces replaced by hyphens
|
||
-- (e.g. "GJ 244A" → "GJ-244A"). NULL means no heightmap has been
|
||
-- generated for this body yet. The three downstream pipelines
|
||
-- (populate, atlas generator, client loader) all assume this format —
|
||
-- changing it requires updating all three sites together.
|
||
terrain_reference TEXT,
|
||
screenshot_path TEXT, -- planetary shader screenshot path
|
||
|
||
updated_at TEXT DEFAULT (datetime('now'))
|
||
);
|
||
|
||
-- Stations and orbital facilities
|
||
-- Naming: GJ-{n}b-S1 (first station orbiting planet b), GJ-{n}-oort-S1 (horizon station)
|
||
CREATE TABLE IF NOT EXISTS stations (
|
||
station_id TEXT PRIMARY KEY,
|
||
system_id TEXT NOT NULL REFERENCES star_systems(system_id),
|
||
orbits_body_id TEXT REFERENCES bodies(body_id),
|
||
|
||
-- Classification
|
||
station_type TEXT NOT NULL, -- horizon, commercial, military, research, industrial, agricultural, transit
|
||
proper_name TEXT, -- "Chengdu Orbital", "Horizon Station"
|
||
|
||
-- Settlement
|
||
population INTEGER DEFAULT 0,
|
||
economic_role TEXT,
|
||
governance_type TEXT, -- can differ from system governance
|
||
|
||
-- Infrastructure
|
||
docking_class TEXT, -- major, standard, restricted, none
|
||
has_gate_infrastructure INTEGER DEFAULT 0,
|
||
district_count INTEGER DEFAULT 1,
|
||
|
||
updated_at TEXT DEFAULT (datetime('now'))
|
||
);
|
||
|
||
-- Corporations, combines, and major economic entities
|
||
-- Source: wiki/corporations/ pages (canonical)
|
||
CREATE TABLE IF NOT EXISTS corporations (
|
||
corp_id TEXT PRIMARY KEY, -- slug from wiki (e.g., "gate-corporation", "vethara")
|
||
proper_name TEXT NOT NULL, -- display name
|
||
corp_type TEXT NOT NULL, -- corporation, combine, syndic, institution, independent
|
||
scope TEXT, -- reach-wide, sector, system, local
|
||
headquarters_system TEXT REFERENCES star_systems(system_id),
|
||
headquarters_body TEXT, -- body_id or station_id
|
||
specialization TEXT, -- primary product/service
|
||
parent_corp TEXT REFERENCES corporations(corp_id),
|
||
notes TEXT,
|
||
|
||
-- Economics (D-175)
|
||
behavioral_archetype TEXT, -- Monopolist|Distributor|Producer|Specialist|Cooperative|Intermediary
|
||
supply_chain_role TEXT,
|
||
shadow_economy_access INTEGER DEFAULT 0,
|
||
|
||
updated_at TEXT DEFAULT (datetime('now'))
|
||
);
|
||
|
||
-- Gate adjacency graph — bidirectional edges from star-map.json (D-178)
|
||
-- Transport cost computation: 5–12% per hop (gate edge), 1–3% (orbital edge)
|
||
CREATE TABLE IF NOT EXISTS gate_links (
|
||
from_system_id TEXT NOT NULL REFERENCES star_systems(system_id),
|
||
to_system_id TEXT NOT NULL REFERENCES star_systems(system_id),
|
||
PRIMARY KEY (from_system_id, to_system_id)
|
||
);
|
||
|
||
-- Commodity catalog — 36 types (D-184)
|
||
-- Source: wiki/economics/commodities.toml
|
||
CREATE TABLE IF NOT EXISTS commodities (
|
||
commodity_id TEXT PRIMARY KEY,
|
||
name TEXT NOT NULL,
|
||
tier TEXT NOT NULL, -- raw|intermediate|final|service_professional|service_luxury
|
||
elasticity TEXT NOT NULL, -- perfectly_inelastic|inelastic|unit_elastic|elastic
|
||
base_price REAL NOT NULL,
|
||
bulk_class TEXT, -- bulk|liquid|perishable|standard|compact|precision|oversized|non_physical
|
||
unit TEXT, -- tonnes|units|contracts
|
||
production_ubiquity TEXT, -- ubiquitous|common|regional|concentrated|monopolistic
|
||
demand_model TEXT, -- market|utility|compliance
|
||
commission_certifiable INTEGER DEFAULT 0, -- subject to certification in TRACTUS_PRIMARY zones
|
||
compact_contested INTEGER DEFAULT 0,
|
||
shadow_viable INTEGER DEFAULT 0,
|
||
panic_threshold_weeks INTEGER DEFAULT 0,
|
||
description TEXT,
|
||
updated_at TEXT DEFAULT (datetime('now'))
|
||
);
|
||
|
||
-- D-237 authored specialization layer: economic-specialization vocabulary.
|
||
-- Each value maps to a commodity + projected (BulkClass, ProductionUbiquity) for D-233.
|
||
-- Scale is encoded in the value (breadbasket vs estate_farming); no separate scale column.
|
||
-- Compiled from wiki/economics/specialization_vocabulary.toml by import_economics.py.
|
||
CREATE TABLE IF NOT EXISTS specialization_vocabulary (
|
||
specialization_id TEXT PRIMARY KEY,
|
||
commodity_id TEXT NOT NULL REFERENCES commodities(commodity_id),
|
||
production_ubiquity_override TEXT, -- NULL = use the commodity's catalog default
|
||
bulk_class_projected TEXT NOT NULL, -- pre-computed BulkClass for D-233
|
||
production_ubiquity_projected TEXT NOT NULL, -- pre-computed ProductionUbiquity for D-233
|
||
description TEXT NOT NULL
|
||
);
|
||
CREATE INDEX IF NOT EXISTS idx_spec_vocab_commodity ON specialization_vocabulary(commodity_id);
|
||
|
||
-- Leontief production chain recipes (D-178)
|
||
-- Source: wiki/economics/production_chains.toml
|
||
CREATE TABLE IF NOT EXISTS production_chains (
|
||
chain_id TEXT PRIMARY KEY,
|
||
output_commodity_id TEXT NOT NULL REFERENCES commodities(commodity_id),
|
||
output_quantity REAL NOT NULL DEFAULT 1.0,
|
||
location_bound INTEGER DEFAULT 0,
|
||
description TEXT,
|
||
updated_at TEXT DEFAULT (datetime('now'))
|
||
);
|
||
|
||
-- Input requirements per production chain
|
||
CREATE TABLE IF NOT EXISTS chain_inputs (
|
||
chain_id TEXT NOT NULL REFERENCES production_chains(chain_id),
|
||
input_commodity_id TEXT NOT NULL REFERENCES commodities(commodity_id),
|
||
quantity REAL NOT NULL,
|
||
PRIMARY KEY (chain_id, input_commodity_id)
|
||
);
|
||
|
||
-- Corporation operating locations (D-175)
|
||
-- Populated by corporation assignment pipeline, not by initial import
|
||
CREATE TABLE IF NOT EXISTS corp_presence (
|
||
corp_id TEXT NOT NULL REFERENCES corporations(corp_id),
|
||
location_id TEXT NOT NULL, -- body_id or station_id
|
||
location_type TEXT NOT NULL, -- body|station
|
||
primary_operation TEXT,
|
||
updated_at TEXT DEFAULT (datetime('now')),
|
||
PRIMARY KEY (corp_id, location_id)
|
||
);
|
||
|
||
-- Brand layer (D-189) — administered-price layer above commodity tâtonnement.
|
||
-- Brands consume commodities as demand nodes; they are NOT commodities (D-185).
|
||
|
||
CREATE TABLE IF NOT EXISTS brand_products (
|
||
brand_product_id TEXT PRIMARY KEY,
|
||
corp_id TEXT NOT NULL REFERENCES corporations(corp_id),
|
||
product_name TEXT NOT NULL,
|
||
brand_category TEXT NOT NULL, -- terroir|heritage_craft|tech_premium|cultural|service_premium|commodity_branded|design_heritage|platform_catalogue
|
||
value_trajectory TEXT NOT NULL, -- appreciating|depreciating|timeless
|
||
scarcity_class TEXT NOT NULL, -- capped|constrained|scalable|unlimited
|
||
product_subcategory TEXT,
|
||
base_premium_multiplier REAL NOT NULL DEFAULT 1.0,
|
||
premium_floor REAL NOT NULL DEFAULT 0.0,
|
||
origin_system TEXT REFERENCES star_systems(system_id),
|
||
terroir_locked INTEGER NOT NULL DEFAULT 0, -- boolean: production bound to origin_system
|
||
currency_denomination TEXT NOT NULL DEFAULT 'tractus', -- tractus|mark|mixed|sol_adjacent
|
||
shadow_viable INTEGER NOT NULL DEFAULT 0, -- boolean: circulates in shadow economy
|
||
brand_tier TEXT NOT NULL, -- halo|volume
|
||
halo_brand_id TEXT REFERENCES brand_products(brand_product_id), -- NULL for halo tier
|
||
updated_at TEXT DEFAULT (datetime('now'))
|
||
);
|
||
|
||
CREATE TABLE IF NOT EXISTS brand_inputs (
|
||
brand_product_id TEXT NOT NULL REFERENCES brand_products(brand_product_id),
|
||
commodity_id TEXT NOT NULL REFERENCES commodities(commodity_id),
|
||
quantity REAL NOT NULL,
|
||
PRIMARY KEY (brand_product_id, commodity_id)
|
||
);
|
||
|
||
-- Fiscal parameters per star system (D-189 section 5 + section 6)
|
||
CREATE TABLE IF NOT EXISTS system_fiscal (
|
||
system_id TEXT PRIMARY KEY REFERENCES star_systems(system_id),
|
||
corp_tax_rate REAL NOT NULL DEFAULT 0.22, -- 0.0–1.0
|
||
collection_efficiency REAL NOT NULL DEFAULT 1.0, -- derived: 1.0 - shadow_intensity × 0.6
|
||
updated_at TEXT DEFAULT (datetime('now'))
|
||
);
|
||
|
||
-- Phase 2: passive corp health tracking (D-189 section 8)
|
||
CREATE TABLE IF NOT EXISTS corp_financial_state (
|
||
corp_id TEXT PRIMARY KEY REFERENCES corporations(corp_id),
|
||
health_metric REAL NOT NULL DEFAULT 1.0, -- 0.0 (distressed) to 1.0 (healthy)
|
||
updated_at TEXT DEFAULT (datetime('now'))
|
||
);
|
||
|
||
-- Phase 3 lifecycle state machine stub (D-189 section 8) — schema correct, not driven yet
|
||
CREATE TABLE IF NOT EXISTS corp_lifecycle_events (
|
||
event_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
corp_id TEXT NOT NULL REFERENCES corporations(corp_id),
|
||
event_type TEXT NOT NULL, -- Founded|Growing|Active|Distressed|Acquired|Dissolved
|
||
event_tick INTEGER NOT NULL DEFAULT 0,
|
||
event_data TEXT, -- JSON blob for future lifecycle detail
|
||
created_at TEXT DEFAULT (datetime('now'))
|
||
);
|
||
|
||
-- BEGIN ATLAS INDEX (D-191 §8, #832) -- DO NOT EDIT THE MARKER COMMENTS
|
||
-- Atlas index — scalar metadata mirror of markers.json files.
|
||
-- Source of truth is wiki/star-systems/.../markers.json (next to the heightmap);
|
||
-- these tables exist so the atlas implant app and development queries don't
|
||
-- have to scan hundreds of JSON files. Polyline geometry stays in the files —
|
||
-- the DB only stores scalar/filterable fields + `point_count` as a rough length
|
||
-- proxy. The geometry tables are populated by the server-side generation
|
||
-- cascade (Phase 4, D-223) and start empty; tooling/economy-db/import_economics.py
|
||
-- extracts this entire block (between BEGIN/END ATLAS INDEX markers) from this
|
||
-- file at runtime and empties the geometry tables on regen, so the DDL lives in
|
||
-- exactly one place.
|
||
|
||
-- Per-body grid dimensions (one row per body that has a markers.json).
|
||
-- Lets any query interpret the pixel coordinates below without touching disk.
|
||
CREATE TABLE IF NOT EXISTS atlas_body_grids (
|
||
body_id TEXT PRIMARY KEY REFERENCES bodies(body_id) ON DELETE CASCADE,
|
||
grid_w INTEGER NOT NULL,
|
||
grid_h INTEGER NOT NULL,
|
||
updated_at TEXT DEFAULT (datetime('now'))
|
||
);
|
||
|
||
CREATE TABLE IF NOT EXISTS atlas_cities (
|
||
city_id TEXT PRIMARY KEY, -- "<body_id>/<local_id>" e.g. "GJ380c/city_0"
|
||
body_id TEXT NOT NULL REFERENCES bodies(body_id) ON DELETE CASCADE,
|
||
local_id TEXT NOT NULL, -- "city_0", "city_1" — matches markers.json id
|
||
name TEXT NOT NULL DEFAULT '',
|
||
kind TEXT NOT NULL, -- capital|city
|
||
center_row INTEGER NOT NULL,
|
||
center_col INTEGER NOT NULL,
|
||
population INTEGER NOT NULL DEFAULT 0,
|
||
updated_at TEXT DEFAULT (datetime('now'))
|
||
);
|
||
|
||
CREATE TABLE IF NOT EXISTS atlas_roads (
|
||
road_id TEXT PRIMARY KEY, -- "<body_id>/<local_id>"
|
||
body_id TEXT NOT NULL REFERENCES bodies(body_id) ON DELETE CASCADE,
|
||
local_id TEXT NOT NULL,
|
||
name TEXT NOT NULL DEFAULT '',
|
||
kind TEXT NOT NULL, -- commercial|highway|rural|...
|
||
point_count INTEGER NOT NULL, -- path length proxy (full geometry in markers.json)
|
||
updated_at TEXT DEFAULT (datetime('now'))
|
||
);
|
||
|
||
CREATE TABLE IF NOT EXISTS atlas_railroads (
|
||
railroad_id TEXT PRIMARY KEY, -- "<body_id>/<local_id>"
|
||
body_id TEXT NOT NULL REFERENCES bodies(body_id) ON DELETE CASCADE,
|
||
local_id TEXT NOT NULL,
|
||
name TEXT NOT NULL DEFAULT '',
|
||
kind TEXT NOT NULL, -- passenger_freight|freight|maglev|...
|
||
point_count INTEGER NOT NULL,
|
||
updated_at TEXT DEFAULT (datetime('now'))
|
||
);
|
||
|
||
CREATE TABLE IF NOT EXISTS atlas_pois (
|
||
poi_id TEXT PRIMARY KEY, -- "<body_id>/<local_id>"
|
||
body_id TEXT NOT NULL REFERENCES bodies(body_id) ON DELETE CASCADE,
|
||
local_id TEXT NOT NULL,
|
||
name TEXT NOT NULL DEFAULT '',
|
||
kind TEXT NOT NULL, -- transit|institutional|cultural|...
|
||
center_row INTEGER NOT NULL,
|
||
center_col INTEGER NOT NULL,
|
||
updated_at TEXT DEFAULT (datetime('now'))
|
||
);
|
||
|
||
CREATE TABLE IF NOT EXISTS atlas_rivers (
|
||
river_id TEXT PRIMARY KEY, -- "<body_id>/<local_id>"
|
||
body_id TEXT NOT NULL REFERENCES bodies(body_id) ON DELETE CASCADE,
|
||
local_id TEXT NOT NULL,
|
||
name TEXT NOT NULL DEFAULT '', -- empty for untitled procedural rivers
|
||
point_count INTEGER NOT NULL,
|
||
updated_at TEXT DEFAULT (datetime('now'))
|
||
);
|
||
|
||
CREATE TABLE IF NOT EXISTS atlas_oceans (
|
||
water_id TEXT PRIMARY KEY, -- "<body_id>/<local_id>"
|
||
body_id TEXT NOT NULL REFERENCES bodies(body_id) ON DELETE CASCADE,
|
||
local_id TEXT NOT NULL,
|
||
name TEXT NOT NULL DEFAULT '',
|
||
kind TEXT NOT NULL, -- lake|sea|ocean
|
||
center_row INTEGER NOT NULL,
|
||
center_col INTEGER NOT NULL,
|
||
area_fraction REAL NOT NULL DEFAULT 0.0, -- fraction of heightmap area covered
|
||
updated_at TEXT DEFAULT (datetime('now'))
|
||
);
|
||
|
||
CREATE TABLE IF NOT EXISTS atlas_mountain_ranges (
|
||
range_id TEXT PRIMARY KEY, -- "<body_id>/<local_id>"
|
||
body_id TEXT NOT NULL REFERENCES bodies(body_id) ON DELETE CASCADE,
|
||
local_id TEXT NOT NULL,
|
||
name TEXT NOT NULL DEFAULT '',
|
||
center_row INTEGER NOT NULL,
|
||
center_col INTEGER NOT NULL,
|
||
peak_row INTEGER NOT NULL,
|
||
peak_col INTEGER NOT NULL,
|
||
area_cells INTEGER NOT NULL DEFAULT 0,
|
||
updated_at TEXT DEFAULT (datetime('now'))
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_atlas_cities_body ON atlas_cities(body_id);
|
||
CREATE INDEX IF NOT EXISTS idx_atlas_cities_kind ON atlas_cities(kind);
|
||
CREATE INDEX IF NOT EXISTS idx_atlas_cities_population ON atlas_cities(population);
|
||
CREATE INDEX IF NOT EXISTS idx_atlas_cities_name ON atlas_cities(name);
|
||
CREATE INDEX IF NOT EXISTS idx_atlas_roads_body ON atlas_roads(body_id);
|
||
CREATE INDEX IF NOT EXISTS idx_atlas_railroads_body ON atlas_railroads(body_id);
|
||
CREATE INDEX IF NOT EXISTS idx_atlas_pois_body ON atlas_pois(body_id);
|
||
CREATE INDEX IF NOT EXISTS idx_atlas_pois_kind ON atlas_pois(kind);
|
||
CREATE INDEX IF NOT EXISTS idx_atlas_rivers_body ON atlas_rivers(body_id);
|
||
CREATE INDEX IF NOT EXISTS idx_atlas_oceans_body ON atlas_oceans(body_id);
|
||
CREATE INDEX IF NOT EXISTS idx_atlas_mountain_ranges_body ON atlas_mountain_ranges(body_id);
|
||
-- Heightmap BLOB storage REMOVED (D-202 amended, #963): canonical elevation is
|
||
-- now a per-body 16-bit grayscale heightmap.png file (sea_level in a tEXt
|
||
-- chunk), not a systems.db BLOB. The atlas_body_heightmaps table is dropped via
|
||
-- MIGRATION_SQL in import_economics.py.
|
||
|
||
-- City name reservations — replaces authored city positions in markers.json (D-207, #902)
|
||
-- Position is generated by the city placement algorithm; name is authored or LLM-generated.
|
||
CREATE TABLE IF NOT EXISTS atlas_city_names (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
body_id TEXT NOT NULL REFERENCES bodies(body_id) ON DELETE CASCADE,
|
||
name TEXT NOT NULL,
|
||
kind TEXT NOT NULL DEFAULT 'city', -- 'capital' | 'city'
|
||
economic_role TEXT NOT NULL,
|
||
population INTEGER NOT NULL,
|
||
settlement_class TEXT, -- D-196 SettlementClass variant; NULL until placement
|
||
corp_id TEXT REFERENCES corporations(corp_id), -- nullable, corp HQ if applicable
|
||
reserved INTEGER NOT NULL DEFAULT 0, -- 1 = reserved for authored scenario use
|
||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||
);
|
||
|
||
-- Geographic feature name reservations — rivers, mountains, passes (D-207 adjacent, #903)
|
||
CREATE TABLE IF NOT EXISTS atlas_feature_names (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
body_id TEXT NOT NULL REFERENCES bodies(body_id) ON DELETE CASCADE,
|
||
name TEXT NOT NULL,
|
||
feature_type TEXT NOT NULL, -- 'river' | 'mountain' | 'pass' | 'ocean' | 'region'
|
||
priority INTEGER NOT NULL DEFAULT 0, -- higher = applied first during naming
|
||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||
);
|
||
|
||
-- Province boundaries — watershed drainage basin polylines (D-205, #904)
|
||
-- Pre-computed at build time from D8 drainage analysis.
|
||
CREATE TABLE IF NOT EXISTS atlas_province_boundaries (
|
||
body_id TEXT NOT NULL REFERENCES bodies(body_id) ON DELETE CASCADE,
|
||
basin_id INTEGER NOT NULL,
|
||
path TEXT NOT NULL, -- JSON array [[row, col], ...] pixel-space polyline
|
||
area_pct REAL NOT NULL, -- fraction of body surface area in this basin
|
||
PRIMARY KEY (body_id, basin_id)
|
||
);
|
||
|
||
-- City positions — attractor-matched placement output (D-211, #34)
|
||
-- Written at build time by the attractor-matching pipeline. Each row maps one
|
||
-- atlas_city_names entry to its terrain position and the attractor that placed it.
|
||
CREATE TABLE IF NOT EXISTS atlas_city_positions (
|
||
city_names_id INTEGER PRIMARY KEY REFERENCES atlas_city_names(id) ON DELETE CASCADE,
|
||
body_id TEXT NOT NULL REFERENCES bodies(body_id) ON DELETE CASCADE,
|
||
row INTEGER NOT NULL, -- pixel row in heightmap grid [0, GRID_H)
|
||
col INTEGER NOT NULL, -- pixel col in heightmap grid [0, GRID_W)
|
||
attractor_type TEXT NOT NULL, -- AttractorType variant name
|
||
score REAL NOT NULL -- match quality [0.0, 1.0]
|
||
);
|
||
|
||
CREATE INDEX IF NOT EXISTS idx_atlas_city_names_body ON atlas_city_names(body_id);
|
||
CREATE INDEX IF NOT EXISTS idx_atlas_city_names_kind ON atlas_city_names(kind);
|
||
CREATE INDEX IF NOT EXISTS idx_atlas_city_names_corp ON atlas_city_names(corp_id);
|
||
CREATE INDEX IF NOT EXISTS idx_atlas_feature_names_body ON atlas_feature_names(body_id);
|
||
CREATE INDEX IF NOT EXISTS idx_atlas_province_boundaries_body ON atlas_province_boundaries(body_id);
|
||
CREATE INDEX IF NOT EXISTS idx_atlas_city_positions_body ON atlas_city_positions(body_id);
|
||
-- END ATLAS INDEX (D-191 §8, #832)
|
||
|
||
-- ── Architecture-flavor trait templates (D-232, #993) ──────────────────────
|
||
-- trait_templates: the shared catalog of holistic architecture-flavor template
|
||
-- bundles (NOT per-axis traits). Baked from
|
||
-- wiki/economics/architecture_trait_catalog.toml. List/map fields are JSON text
|
||
-- (the generator parses). All numerics are integer basis-points (D-010).
|
||
-- Catalog content is authored in #1005; this table is the mechanism (#993).
|
||
CREATE TABLE IF NOT EXISTS trait_templates (
|
||
tag TEXT PRIMARY KEY,
|
||
label TEXT NOT NULL,
|
||
cultural_description TEXT,
|
||
corridor_pool TEXT NOT NULL DEFAULT 'baseline', -- baseline | heritage | cross_corridor
|
||
geographic_sector TEXT, -- corridor; NULL = shared/cross-corridor
|
||
bulk_class_gate TEXT, -- JSON list of eligible BulkClass; NULL/[] = any
|
||
production_ubiquity_gate TEXT, -- JSON list; NULL/[] = any
|
||
min_prosperity_bps INTEGER NOT NULL DEFAULT 0, -- hard gate (basis points)
|
||
base_weight INTEGER NOT NULL DEFAULT 10000, -- basis points
|
||
weight_mods TEXT, -- JSON {dimension: {value: multiplier_bps}}
|
||
zone_affinity TEXT, -- JSON {DistrictType: weight_bps}
|
||
allow_tags TEXT, -- JSON list of ObjectTag
|
||
block_tags TEXT, -- JSON list of ObjectTag
|
||
era_scope TEXT,
|
||
visual_bundle TEXT, -- JSON (D-235 bundle + fallback parents)
|
||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||
);
|
||
CREATE INDEX IF NOT EXISTS idx_trait_templates_pool ON trait_templates(corridor_pool);
|
||
CREATE INDEX IF NOT EXISTS idx_trait_templates_sector ON trait_templates(geographic_sector);
|
||
|
||
-- atlas_body_trait_bias: sparse per-body bias on the catalog draw (hero bodies
|
||
-- only, ~30-40). pin = mandatory (counts toward K); boost = weight up (<=3x);
|
||
-- suppress = weight down (>=0.33x, never 0). Hero-pin content authored in #1017.
|
||
CREATE TABLE IF NOT EXISTS atlas_body_trait_bias (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
body_id TEXT NOT NULL REFERENCES bodies(body_id) ON DELETE CASCADE,
|
||
template_tag TEXT NOT NULL REFERENCES trait_templates(tag) ON DELETE CASCADE,
|
||
bias_kind TEXT NOT NULL, -- pin | boost | suppress
|
||
weight_multiplier_bps INTEGER, -- boost 10001..30000; suppress 3300..9999; pin NULL
|
||
note TEXT,
|
||
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||
UNIQUE (body_id, template_tag)
|
||
);
|
||
CREATE INDEX IF NOT EXISTS idx_atlas_body_trait_bias_body ON atlas_body_trait_bias(body_id);
|
||
CREATE INDEX IF NOT EXISTS idx_atlas_body_trait_bias_tag ON atlas_body_trait_bias(template_tag);
|
||
-- END TRAIT TEMPLATES (D-232, #993)
|
||
|
||
-- Indexes
|
||
-- astronomical_id removed: system_id IS the GJ catalog number
|
||
CREATE INDEX IF NOT EXISTS idx_star_systems_sector ON star_systems(geographic_sector);
|
||
CREATE INDEX IF NOT EXISTS idx_star_systems_wave ON system_history(settlement_wave);
|
||
CREATE INDEX IF NOT EXISTS idx_star_systems_topology ON system_gates(gate_topology);
|
||
CREATE INDEX IF NOT EXISTS idx_star_systems_star_type ON star_systems(star_type);
|
||
CREATE INDEX IF NOT EXISTS idx_star_systems_volatility ON star_systems(system_volatility);
|
||
CREATE INDEX IF NOT EXISTS idx_historical_events_system ON historical_events(system_id);
|
||
CREATE INDEX IF NOT EXISTS idx_system_factions_dominant ON system_factions(dominant_faction);
|
||
CREATE INDEX IF NOT EXISTS idx_system_economy_tier ON system_economy(economic_tier);
|
||
CREATE INDEX IF NOT EXISTS idx_system_culture_archetype ON system_culture(primary_archetype);
|
||
CREATE INDEX IF NOT EXISTS idx_bodies_system ON bodies(system_id);
|
||
CREATE INDEX IF NOT EXISTS idx_bodies_parent ON bodies(parent_body_id);
|
||
CREATE INDEX IF NOT EXISTS idx_bodies_type ON bodies(body_type);
|
||
CREATE INDEX IF NOT EXISTS idx_bodies_inhabited ON bodies(inhabited);
|
||
CREATE INDEX IF NOT EXISTS idx_stations_system ON stations(system_id);
|
||
CREATE INDEX IF NOT EXISTS idx_stations_orbits ON stations(orbits_body_id);
|
||
CREATE INDEX IF NOT EXISTS idx_stations_type ON stations(station_type);
|
||
CREATE INDEX IF NOT EXISTS idx_corps_system ON corporations(headquarters_system);
|
||
CREATE INDEX IF NOT EXISTS idx_corps_type ON corporations(corp_type);
|
||
CREATE INDEX IF NOT EXISTS idx_star_systems_currency ON star_systems(currency_zone);
|
||
CREATE INDEX IF NOT EXISTS idx_gate_links_from ON gate_links(from_system_id);
|
||
CREATE INDEX IF NOT EXISTS idx_gate_links_to ON gate_links(to_system_id);
|
||
|
||
-- Generator metadata stamp (#855, #856, #888)
|
||
-- One row per generator, updated on each successful non-dry-run.
|
||
-- schema_version: monotonic semver string (e.g. "1.0.0") — bump on backwards-incompatible changes.
|
||
-- Orderable, enabling savegame migration lineage (Phase 5+).
|
||
-- Defined as SCHEMA_VERSION constant in tooling/schema_version.py.
|
||
-- schema_sha: SHA-1 hex of systems-schema.sql content at generation time (tamper detection).
|
||
-- generator_sha: SHA-1 hex of the generator source file(s) content
|
||
-- generated_at: ISO-8601 UTC timestamp of the run
|
||
--
|
||
-- Used by:
|
||
-- tooling/check-systems-db-stamp — verifies freshness before push (#857)
|
||
-- .config/hooks/pre-push — rejects pushes with stale DB (#857)
|
||
-- /pr-push skill — triggers make regen-db if stale (#858)
|
||
CREATE TABLE IF NOT EXISTS meta (
|
||
generator_name TEXT PRIMARY KEY, -- 'import_economics' (generate_atlas retired #951)
|
||
schema_version TEXT NOT NULL, -- monotonic semver string (e.g. "1.0.0") — see #888
|
||
schema_sha TEXT, -- SHA-1 hex of systems-schema.sql content (tamper detection)
|
||
generator_sha TEXT NOT NULL, -- SHA-1 hex of generator source file(s) content
|
||
generated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||
);
|
||
CREATE INDEX IF NOT EXISTS idx_commodities_tier ON commodities(tier);
|
||
CREATE INDEX IF NOT EXISTS idx_production_chains_output ON production_chains(output_commodity_id);
|
||
CREATE INDEX IF NOT EXISTS idx_chain_inputs_commodity ON chain_inputs(input_commodity_id);
|
||
CREATE INDEX IF NOT EXISTS idx_corp_presence_corp ON corp_presence(corp_id);
|
||
CREATE INDEX IF NOT EXISTS idx_corp_presence_location ON corp_presence(location_id);
|
||
-- Brand layer indexes (D-189 section 5 — composite for UI queries)
|
||
CREATE INDEX IF NOT EXISTS idx_brand_products_corp_category ON brand_products(corp_id, brand_category);
|
||
CREATE INDEX IF NOT EXISTS idx_brand_products_origin ON brand_products(origin_system);
|
||
CREATE INDEX IF NOT EXISTS idx_brand_products_tier ON brand_products(brand_tier);
|
||
CREATE INDEX IF NOT EXISTS idx_brand_inputs_commodity ON brand_inputs(commodity_id);
|
||
CREATE INDEX IF NOT EXISTS idx_corp_lifecycle_events_corp ON corp_lifecycle_events(corp_id);
|
||
-- Atlas index (D-191 §8, #832) — see BEGIN/END ATLAS INDEX block above.
|