feat(schema): D-237 specialization columns + specialization_vocabulary table

Ticket #1011. system_economy gains economic_specialization +
cultural_specialization (TEXT, NULL = heuristic fallback); new
specialization_vocabulary table (specialization_id PK, commodity_id
FK->commodities, production_ubiquity_override, projected BulkClass +
ProductionUbiquity for D-233, description) + commodity index. Columns
mirrored into COLUMN_MIGRATIONS for idempotent migration; table rides
systems-schema.sql. dominant_faction already exists on system_factions
(populate-only). Validated: importer parses; schema applies to scratch DB;
idempotent migration ran 2x on a copy of live systems.db, 301 rows preserved.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-31 21:04:00 +02:00
co-authored by Claude Opus 4.8
parent a4541bde18
commit 4f53793755
5 changed files with 442 additions and 2 deletions
@@ -284,7 +284,8 @@ All confirmed by lore/GTTR verification from Miri (economic + cultural) and Paul
| Parallax | GJ-280A | `media_center` | `artistic` | `independent` |
| Gateway | GJ-71 | `transit_hub` | `cosmopolitan` | `mixed` |
| Wolf 359 | GJ-406 | `transit_hub` | `institutional` | `concord_assembly` |
| Vuurkloof | GJ-35 | `geothermal_hub` | `afrikaans_cape` | `concord_assembly` |
| Vuurkloof | GJ-35 | `geothermal_hub` | `afrikaans_cape` | `independent` | <!-- corrected 2026-05-31 (human): guild self-governance, no Assembly presence in GTTR; supersedes the hop-6 concord_assembly default -->
| Keid | GJ-166A | `research_station` | `scholarly` | `independent` |
| Bastion | GJ-570A | `military_industrial` | `military` | `concord_assembly` |
| Arbour | GJ-338B | `estate_farming` | `agrarian` | `concord_assembly` |
+18 -1
View File
@@ -98,7 +98,10 @@ CREATE TABLE IF NOT EXISTS system_economy (
economic_base_primary TEXT,
economic_base_secondary TEXT,
distribution_index TEXT,
imprint_access 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
@@ -269,6 +272,20 @@ CREATE TABLE IF NOT EXISTS commodities (
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 (
+2
View File
@@ -417,6 +417,8 @@ COLUMN_MIGRATIONS = [
("bodies", "body_radius_km", "REAL"), # D-204 — physical radius in km, nullable
("meta", "schema_sha", "TEXT"),
("atlas_city_names", "settlement_class", "TEXT"), # D-196 — NULL until placement (#37)
("system_economy", "economic_specialization", "TEXT"), # D-237 — authored specialization layer
("system_economy", "cultural_specialization", "TEXT"), # D-237 — authored specialization layer
]
@@ -0,0 +1,254 @@
# ==========================================================================
# Settled Reach — Economic Specialization Vocabulary (D-237)
# Source of truth. Compiled to systems.db specialization_vocabulary by
# import_economics.py.
#
# Each value names an economic-specialization identity and projects to the
# (BulkClass, ProductionUbiquity) pair D-233 consumes for block fill.
# SCALE is encoded in the value itself (breadbasket vs estate_farming vs
# terroir_agriculture) — there is no separate scale column.
#
# Fields per entry:
# commodity_id FK -> commodities.commodity_id (the anchor
# commodity; also drives body-level draws)
# production_ubiquity_override catalog-level term that overrides the
# commodity's global production_ubiquity for
# THIS specialization's local built form;
# "" = use the commodity's catalog default.
# (catalog scale: ubiquitous < common < regional
# < concentrated < monopolistic)
# bulk_class_projected D-233 BulkClass: BulkSolid | BulkLiquid |
# PrecisionDense | Perishable | NonPhysical
# production_ubiquity_projected D-233 ProductionUbiquity: Ubiquitous | Common |
# Specialist | MonopolySource (AUTHORITATIVE —
# the value D-233 reads; hand-set to lore intent)
# description one-line identity description
#
# OVERRIDE-vs-PROJECTED note (lead, 2026-05-31, #1012):
# The workshop's "equal-or-higher" rule (D-237: a local override may only be
# >= the commodity's global concentration) holds for production/extraction
# values. It does NOT fit HUB specializations, where being THE hub makes a
# good MORE COMMON locally than its global average — `shipbuilding`
# (freight_haulers is globally `regional`, but Cygni B's 7 competing combines
# read locally as Common) and `transit_hub` (commission_certification is
# globally `concentrated`, but a transit settlement reads Common). For these,
# `production_ubiquity_projected` is authoritative and intentionally lower
# than the catalog-derived value; `production_ubiquity_override` is left empty
# to signal "not a simple scale bump." FLAG for #1015: V-SES-03 must NOT hard-
# fail projected < catalog for hub values — only Miri's incoherent case
# (a monopolistic-global good claimed locally ubiquitous) should error.
# `gate_fabrication` was given an explicit `monopolistic` override (Gate Corp
# IS a monopoly — lore-consistent) so its MonopolySource projection derives
# cleanly.
#
# Decisions: D-237 (this vocabulary), D-233 (consumer), D-184 (commodity
# catalog). Workshop: docs/workshops/system-economic-specialization/
# workshop-outcomes.md §2.
# ==========================================================================
# -------------------------------------------------------------------------
# Agricultural (5)
# -------------------------------------------------------------------------
[estate_farming]
commodity_id = "agricultural_produce"
production_ubiquity_override = "" # catalog default (ubiquitous)
bulk_class_projected = "Perishable"
production_ubiquity_projected = "Ubiquitous"
description = "Estate / amenity agriculture — scattered, ornamental; produce secondary to luxury character (Arbour)."
[breadbasket]
commodity_id = "agricultural_produce"
production_ubiquity_override = "concentrated"
bulk_class_projected = "Perishable"
production_ubiquity_projected = "Specialist"
description = "Industrial-scale food surplus; the settlement IS the agricultural engine (Ran, Ostmark)."
[terroir_agriculture]
commodity_id = "agricultural_produce"
production_ubiquity_override = "monopolistic"
bulk_class_projected = "Perishable"
production_ubiquity_projected = "MonopolySource"
description = "Geographically locked agriculture; cannot be reproduced elsewhere (Confluent/VGV — F8V spectral lock, D-177)."
[terroir_spirits]
commodity_id = "processed_food"
production_ubiquity_override = "monopolistic"
bulk_class_projected = "BulkSolid"
production_ubiquity_projected = "MonopolySource"
description = "Terroir-locked distillery/spirits; aging pipeline + origin lock (Calloway Reach, D-177)."
[terroir_organics]
commodity_id = "organic_compounds"
production_ubiquity_override = "monopolistic"
bulk_class_projected = "BulkSolid"
production_ubiquity_projected = "MonopolySource"
description = "Biologically locked organics; herd/ecosystem origin monopoly (Braemar brach fiber, Dagat kelp/dye, D-177)."
# -------------------------------------------------------------------------
# Energy (2)
# -------------------------------------------------------------------------
[fuel_production]
commodity_id = "fusion_fuel"
production_ubiquity_override = "" # catalog default (common)
bulk_class_projected = "BulkLiquid"
production_ubiquity_projected = "Common"
description = "Generic fuel refinery world; fuel is produced but not the singular settlement identity."
[geothermal_hub]
commodity_id = "fusion_fuel"
production_ubiquity_override = "concentrated"
bulk_class_projected = "BulkLiquid"
production_ubiquity_projected = "Specialist"
description = "Geothermal extraction infrastructure IS the settlement; conduits + exchange stations dominate (Vuurkloof)."
# -------------------------------------------------------------------------
# Extraction (5)
# -------------------------------------------------------------------------
[ore_extraction]
commodity_id = "metallic_ore"
production_ubiquity_override = "" # catalog default (common)
bulk_class_projected = "BulkSolid"
production_ubiquity_projected = "Common"
description = "Generic mining world; ore among several local activities."
[company_mining]
commodity_id = "metallic_ore"
production_ubiquity_override = "concentrated"
bulk_class_projected = "BulkSolid"
production_ubiquity_projected = "Specialist"
description = "Company-town extraction; a corporation controls the seam and the settlement (Sindri / DSMC)."
[marble_monopoly]
commodity_id = "stone"
production_ubiquity_override = "monopolistic"
bulk_class_projected = "BulkSolid"
production_ubiquity_projected = "MonopolySource"
description = "Geological monopoly on a prestige stone; hard volume ceiling (Nyrheim / Kvitfjell, D-177)."
[rare_mineral_extraction]
commodity_id = "rare_minerals"
production_ubiquity_override = "" # catalog default (concentrated)
bulk_class_projected = "PrecisionDense"
production_ubiquity_projected = "Specialist"
description = "Specialist rare-mineral world; concentrated high-value extraction. (No confirmed hero pin; content-pass value.)"
[lattice_material_source]
commodity_id = "lattice_grade_material"
production_ubiquity_override = "" # catalog default (monopolistic)
bulk_class_projected = "PrecisionDense"
production_ubiquity_projected = "MonopolySource"
description = "Strategic lattice-grade material source; east-reach anchor. (Hero GJ pin TBD — content pass #1016.)"
# -------------------------------------------------------------------------
# Manufacturing (6)
# -------------------------------------------------------------------------
[general_industrial]
commodity_id = "refined_metals"
production_ubiquity_override = "" # catalog default (common)
bulk_class_projected = "BulkSolid"
production_ubiquity_projected = "Common"
description = "Generic manufacturing world; fabrication among several local activities."
[shipbuilding]
commodity_id = "freight_haulers"
production_ubiquity_override = "" # HUB: projected below catalog (regional) by intent — see header note
bulk_class_projected = "BulkSolid"
production_ubiquity_projected = "Common"
description = "Large-frame shipbuilding; multiple competing combines, not a monopoly (Cygni B — 7 combines)."
[vehicle_production]
commodity_id = "transport_vehicles"
production_ubiquity_override = "concentrated"
bulk_class_projected = "BulkSolid"
production_ubiquity_projected = "Specialist"
description = "Vehicle/rolling-stock manufacturing identity (Nova Roma / MVG)."
[consumer_goods_bazaar]
commodity_id = "consumer_goods"
production_ubiquity_override = "concentrated"
bulk_class_projected = "BulkSolid"
production_ubiquity_projected = "Specialist"
description = "Dense bazaar of many independent manufacturers (Lu Ban — 300 workshops)."
[gate_fabrication]
commodity_id = "gate_components"
production_ubiquity_override = "monopolistic" # Gate Corp monopoly (lore) — derives MonopolySource cleanly
bulk_class_projected = "BulkSolid"
production_ubiquity_projected = "MonopolySource"
description = "Span-gate component fabrication monopoly (Renaissance / Gate Corp)."
[military_industrial]
commodity_id = "heavy_equipment"
production_ubiquity_override = "concentrated"
bulk_class_projected = "BulkSolid"
production_ubiquity_projected = "Specialist"
description = "Fleet yards, depots, fortified installations; military-administered industry (Bastion). Merges former military_production + military_station."
# -------------------------------------------------------------------------
# High-tech (2)
# -------------------------------------------------------------------------
[precision_tech]
commodity_id = "electronics"
production_ubiquity_override = "concentrated"
bulk_class_projected = "PrecisionDense"
production_ubiquity_projected = "Specialist"
description = "Expertise-based precision components; concentrated technical advantage (Zenzele — EM hardening). Subsumes former specialist_manufacturing."
[marine_farming]
commodity_id = "organic_compounds"
production_ubiquity_override = "concentrated"
bulk_class_projected = "BulkSolid"
production_ubiquity_projected = "Specialist"
description = "Marine/aquaculture production at specialist scale (non-monopoly cases). (No confirmed hero pin; content-pass value — confirmed D-177 cases use terroir_organics.)"
# -------------------------------------------------------------------------
# Services (7) — all NonPhysical
# -------------------------------------------------------------------------
[financial_hub]
commodity_id = "financial_services"
production_ubiquity_override = "concentrated"
bulk_class_projected = "NonPhysical"
production_ubiquity_projected = "Specialist"
description = "Dense financial district (clearing, credit, actuarial); singular clearing-house landmark via D-222/D-232 (Groombridge / GSH)."
[governance_center]
commodity_id = "commission_certification"
production_ubiquity_override = "concentrated"
bulk_class_projected = "NonPhysical"
production_ubiquity_projected = "Specialist"
description = "Institutional/governance seat; commission offices, assembly halls (Sirius, ACB)."
[transit_hub]
commodity_id = "commission_certification"
production_ubiquity_override = "" # HUB: projected below catalog (concentrated) by intent — see header note
bulk_class_projected = "NonPhysical"
production_ubiquity_projected = "Common"
description = "Gate/transit throughput defines the economy; customs + flow infrastructure (Gateway, Wolf 359, Altmark, Dài Lộ)."
[research_station]
commodity_id = "commission_certification"
production_ubiquity_override = "concentrated"
bulk_class_projected = "NonPhysical"
production_ubiquity_projected = "Specialist"
description = "Research/conservation mandate; unique-environment access lock (Keid Conservancy)."
[legal_archive]
commodity_id = "legal_services"
production_ubiquity_override = "concentrated"
bulk_class_projected = "NonPhysical"
production_ubiquity_projected = "Specialist"
description = "Legal/archival institution; interpretive registry, document infrastructure (Tessera)."
[media_center]
commodity_id = "entertainment"
production_ubiquity_override = "concentrated"
bulk_class_projected = "NonPhysical"
production_ubiquity_projected = "Specialist"
description = "Narrative/cultural production; news syndicates, studios, content archives (Parallax)."
[longevity_monopoly]
commodity_id = "medical_services"
production_ubiquity_override = "monopolistic"
bulk_class_projected = "NonPhysical"
production_ubiquity_projected = "MonopolySource"
description = "The single licensed longevity/re-embodiment facility; access-controlled (Prometheus)."
+166
View File
@@ -0,0 +1,166 @@
# ==========================================================================
# Settled Reach — Authored System Specialization Layer (D-237)
# Source of truth. Compiled to systems.db via import_economics.py.
#
# Three authored, static (t=0), deterministic per-system fields. Authored
# lore WINS; a system absent from this file falls back to the heuristic
# (economic) / corridor default (cultural) / derivation (faction).
#
# economic_specialization value in specialization_vocabulary.specialization_id
# -> drives D-233 BulkClass x ProductionUbiquity
# cultural_specialization activity-type OR heritage-type value (heritage wins
# when both apply) -> drives D-232 template pool
# dominant_faction 8-value vocabulary -> D-214 PoliticalArchetype
# (concord_assembly | compact | compact_sympathetic |
# syndic_dominant | veil_institute | independent |
# disputed | mixed). Populated onto system_factions.
#
# Stanza key = star_systems.system_id (SPACE format, e.g. [GJ 144]).
#
# This file seeds the ~27 hero systems (the lore-confirmed must-pin set from
# the system-economic-specialization workshop, §7). The full ~300-system
# content pass (#1016) extends it.
#
# Decisions: D-237 (this layer), D-233 (consumer, re-amended), D-232 (cultural
# consumer), D-214 (faction consumer). Workshop: docs/workshops/
# system-economic-specialization/workshop-outcomes.md §7.
# ==========================================================================
["GJ 144"] # Ran — THE breadbasket
economic_specialization = "breadbasket"
cultural_specialization = "agrarian"
dominant_faction = "concord_assembly"
["GJ 820B"] # Cygni B — shipbuilding, 7 competing combines
economic_specialization = "shipbuilding"
cultural_specialization = "industrial_heritage"
dominant_faction = "concord_assembly"
["GJ 3522"] # Sindri — DSMC company-town mining
economic_specialization = "company_mining"
cultural_specialization = "industrial_heritage"
dominant_faction = "syndic_dominant"
["GJ 764"] # Nova Roma — MVG vehicle production
economic_specialization = "vehicle_production"
cultural_specialization = "italian_northern"
dominant_faction = "concord_assembly"
["GJ 251"] # Renaissance — Gate Corp fabrication
economic_specialization = "gate_fabrication"
cultural_specialization = "industrial_heritage"
dominant_faction = "syndic_dominant"
["GJ 380"] # Groombridge — financial cluster + GSH clearing-house landmark
economic_specialization = "financial_hub"
cultural_specialization = "financial_technocratic"
dominant_faction = "syndic_dominant"
["GJ 702B"] # Prometheus — longevity monopoly
economic_specialization = "longevity_monopoly"
cultural_specialization = "medical_elite"
dominant_faction = "independent"
["GJ 559B"] # ACB — Commission seat (governing faction = Assembly)
economic_specialization = "governance_center"
cultural_specialization = "institutional"
dominant_faction = "concord_assembly"
["GJ 3877"] # Tessera — Assembly Interpretive Registry
economic_specialization = "legal_archive"
cultural_specialization = "scholarly"
dominant_faction = "concord_assembly"
["GJ 244A"] # Sirius — the capital
economic_specialization = "governance_center"
cultural_specialization = "institutional"
dominant_faction = "concord_assembly"
["GJ 280A"] # Parallax — news syndicates / cultural production
economic_specialization = "media_center"
cultural_specialization = "artistic"
dominant_faction = "independent"
["GJ 71"] # Gateway — 5-aperture transit hub
economic_specialization = "transit_hub"
cultural_specialization = "cosmopolitan"
dominant_faction = "mixed"
["GJ 406"] # Wolf 359 — pure Assembly transit office
economic_specialization = "transit_hub"
cultural_specialization = "institutional"
dominant_faction = "concord_assembly"
["GJ 35"] # Vuurkloof — geothermal hub (Van Maanen's Star)
# faction = independent: Geothermal Engineers' Association + Hospitality
# Operators' Guild self-govern; no Assembly presence in the GTTR. Human
# decision 2026-05-31, overriding the workshop §7 hop-6 concord_assembly
# default (which was a pure distance heuristic this layer exists to beat).
economic_specialization = "geothermal_hub"
cultural_specialization = "afrikaans_cape"
dominant_faction = "independent"
["GJ 166A"] # Keid — Conservancy research station
economic_specialization = "research_station"
cultural_specialization = "scholarly"
dominant_faction = "independent"
["GJ 570A"] # Bastion — Assembly military administration
economic_specialization = "military_industrial"
cultural_specialization = "military"
dominant_faction = "concord_assembly"
["GJ 338B"] # Arbour — estate amenity agriculture
economic_specialization = "estate_farming"
cultural_specialization = "agrarian"
dominant_faction = "concord_assembly"
["GJ 15A"] # Lu Ban — consumer-goods bazaar, 300 workshops
economic_specialization = "consumer_goods_bazaar"
cultural_specialization = "chinese"
dominant_faction = "independent"
["GJ 3325"] # Calloway Reach — terroir distillery (D-177)
economic_specialization = "terroir_spirits"
cultural_specialization = "scottish"
dominant_faction = "independent"
["GJ 395"] # Confluent / VGV — terroir viticulture, F8V lock (D-177)
economic_specialization = "terroir_agriculture"
cultural_specialization = "french_provencal"
dominant_faction = "compact_sympathetic"
["GJ 475"] # Braemar — brach fiber biological monopoly (D-177)
economic_specialization = "terroir_organics"
cultural_specialization = "scottish"
dominant_faction = "independent"
["GJ 3737"] # Nyrheim — Kvitfjell marble (D-177)
economic_specialization = "marble_monopoly"
cultural_specialization = "norse_compact"
dominant_faction = "compact"
["GJ 601A"] # Ostmark — Compact founding member, 5c agricultural base
economic_specialization = "breadbasket"
cultural_specialization = "compact_cooperative"
dominant_faction = "compact"
["GJ 482A"] # Dagat — deep-ocean kelp / Blue dye monopoly (D-177)
economic_specialization = "terroir_organics"
cultural_specialization = "tagalog"
dominant_faction = "independent"
["GJ 357"] # Altmark — deliberately non-aligned commercial transit hub
economic_specialization = "transit_hub"
cultural_specialization = "cosmopolitan"
dominant_faction = "independent"
["GJ 136"] # Dài Lộ — Grand Road transit gateway
economic_specialization = "transit_hub"
cultural_specialization = "vietnamese"
dominant_faction = "independent"
["GJ 1111"] # Zenzele — electromagnetic-hardening precision tech
economic_specialization = "precision_tech"
cultural_specialization = "zulu"
dominant_faction = "independent"