feat(db): atlas data pipeline — schema, importers, and normalization (#901-#911)

New tables: atlas_body_heightmaps (D-202), atlas_city_names (D-207),
atlas_feature_names, atlas_province_boundaries (D-205), body_radius_km
column (D-204). Three new importers: heightmap BLOBs, city names from
wiki markers.json, province boundaries via D8 watershed analysis.
economic_role normalized to 7 canonical values (D-194). Stamp fix in
generate_atlas.py to hash all tracked source files. systems.db regenerated.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-02 18:40:33 +02:00
co-authored by Claude Opus 4.6
parent d57f0566d2
commit b6ca785f74
7 changed files with 1354 additions and 2 deletions
+57
View File
@@ -175,6 +175,11 @@ CREATE TABLE IF NOT EXISTS bodies (
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,
-- Rendering
-- terrain_reference: repo-root-relative path to the body's heightmap PNG.
-- Convention (enforced by populate_terrain_reference.py and assumed by
@@ -455,6 +460,58 @@ 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 — float32 LE, row-major (D-202, #901)
-- Only inhabited bodies receive rows at build time; uninhabited bodies are
-- generated on-demand by the runtime-background tier.
CREATE TABLE IF NOT EXISTS atlas_body_heightmaps (
body_id TEXT PRIMARY KEY REFERENCES bodies(body_id) ON DELETE CASCADE,
width INTEGER NOT NULL DEFAULT 512,
height INTEGER NOT NULL DEFAULT 256,
data BLOB NOT NULL, -- float32 LE, row-major, width×height values
sea_level REAL NOT NULL DEFAULT 0.0,
imported_at TEXT NOT NULL DEFAULT (datetime('now'))
);
-- 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,
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)
);
CREATE INDEX IF NOT EXISTS idx_atlas_body_heightmaps_body ON atlas_body_heightmaps(body_id);
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);
-- END ATLAS INDEX (D-191 §8, #832)
-- Indexes