feat(economics): D-237 authored specialization layer (#1013–1019) #146

Closed
jpmschweitzer wants to merge 0 commits from specialization-schema-toml into main
Owner

Summary

Implements the D-237 authored per-system specialization layer end-to-end and
rebalances the corridor's cultural distribution on top of it.

Each inhabited system gains three authored, deterministic identity fields that feed
world generation:

  • economic_specialization — 27-value vocabulary with scale baked in (breadbasket
    vs estate_farm vs terroir), each mapped to a D-233 BulkClass × ProductionUbiquity
    projection via specialization_vocabulary
  • cultural_specialization — activity or founding-heritage value (heritage wins)
  • dominant_faction — D-214 PoliticalArchetype

Authored lore wins; unnamed systems fall back to the generator heuristic (NULL).

What's in the branch

Area Commits
Schema + vocabulary table 4f53793 (#schema)
Importer import_system_specialization() 883c1ab (#1013), 9fe4ddf (fix)
CI guardrails + coverage report 2f994c1 (#1015)
Infobox surfacing (Specialization / Cultural Register rows) 0251c65
economic_base_primary vs economic_specialization seam note e0d7963 (D-237)
Econ + faction content pass (143 systems) 8addf04 (#1016, cultural deferred)
Canonical 47-value heritage taxonomy 01ba14a
Heritage rebalance — 5 systems refounded 8844bef (#1019)
Workshop record + changelog 03188de, 36ae931

Heritage rebalance (#1019)

The corridor over-represented southern-African heritage (afrikaans on 15 systems;
arab=2, persian/turkic=0). Five genuinely-thin afrikaans systems — whose distinctive
threads are heritage-agnostic — are refounded with new cultures:

Droëland  (914A)  -> Marib    (arab)
Stilwater (508A)  -> Sawad    (arab)
Koeberg   (1245B) -> Akhgar   (persian)
Skuilplek (722)   -> Sığınak  (turkic)
Carnarvon (680)   -> Golestan (persian; Mostert dynasty -> Farahani)

Result: afrikaans 15→10; arab 0→2, persian 0→2, turkic 0→1. Full narrative
retouch (gttr + index prose, body/station names, gttr_hook, atlas_city_names), the
4 brand-corps named after the converted systems renamed (corp IDs kept stable), and
all cross-references (neighbours, catalog, aggregate drifter guides, atlas proposals)
updated to match. Load-bearing mystery systems (Eerste Wacht, Helderoog, Brandpunt)
left untouched. Also fixes a pre-existing canon bug: Sawad no longer claims GJ 914A
is "unsettled" — it is Marib, a three-century settlement.

Notes / follow-ups

  • _CULTURAL_HERITAGE gained arab/persian/turkic here so the rebalance values
    validate. The full canonical 47-value migration (renaming the 4 hero values,
    normalizing all sectors) remains #1016 — taxonomy doc records the rest.
  • --strict-specialization completeness gates stay off-by-default until #1014 /
    #1016 land.

Verification

make regen-db clean · meta stamp fresh · DB + file + corp-source stale-name sweeps
all clean · ruff clean · pre-push gates (cargo-deny, ruff, JSON, systems.db stamp) green.

🤖 Generated with Claude Code

## Summary Implements the **D-237 authored per-system specialization layer** end-to-end and rebalances the corridor's cultural distribution on top of it. Each inhabited system gains three authored, deterministic identity fields that feed world generation: - `economic_specialization` — 27-value vocabulary with scale baked in (breadbasket vs estate_farm vs terroir), each mapped to a D-233 BulkClass × ProductionUbiquity projection via `specialization_vocabulary` - `cultural_specialization` — activity **or** founding-heritage value (heritage wins) - `dominant_faction` — D-214 PoliticalArchetype Authored lore wins; unnamed systems fall back to the generator heuristic (NULL). ## What's in the branch | Area | Commits | |---|---| | Schema + vocabulary table | `4f53793` (#schema) | | Importer `import_system_specialization()` | `883c1ab` (#1013), `9fe4ddf` (fix) | | CI guardrails + coverage report | `2f994c1` (#1015) | | Infobox surfacing (Specialization / Cultural Register rows) | `0251c65` | | economic_base_primary vs economic_specialization seam note | `e0d7963` (D-237) | | Econ + faction content pass (143 systems) | `8addf04` (#1016, cultural deferred) | | Canonical 47-value heritage taxonomy | `01ba14a` | | **Heritage rebalance — 5 systems refounded** | `8844bef` (#1019) | | Workshop record + changelog | `03188de`, `36ae931` | ## Heritage rebalance (#1019) The corridor over-represented southern-African heritage (afrikaans on 15 systems; arab=2, persian/turkic=0). Five genuinely-thin afrikaans systems — whose distinctive threads are heritage-agnostic — are refounded with new cultures: ``` Droëland (914A) -> Marib (arab) Stilwater (508A) -> Sawad (arab) Koeberg (1245B) -> Akhgar (persian) Skuilplek (722) -> Sığınak (turkic) Carnarvon (680) -> Golestan (persian; Mostert dynasty -> Farahani) ``` Result: **afrikaans 15→10; arab 0→2, persian 0→2, turkic 0→1.** Full narrative retouch (gttr + index prose, body/station names, gttr_hook, atlas_city_names), the 4 brand-corps named after the converted systems renamed (corp IDs kept stable), and all cross-references (neighbours, catalog, aggregate drifter guides, atlas proposals) updated to match. Load-bearing mystery systems (Eerste Wacht, Helderoog, Brandpunt) left untouched. Also fixes a pre-existing canon bug: Sawad no longer claims GJ 914A is "unsettled" — it is Marib, a three-century settlement. ## Notes / follow-ups - `_CULTURAL_HERITAGE` gained `arab`/`persian`/`turkic` here so the rebalance values validate. The **full canonical 47-value migration** (renaming the 4 hero values, normalizing all sectors) remains **#1016** — taxonomy doc records the rest. - `--strict-specialization` completeness gates stay off-by-default until #1014 / #1016 land. ## Verification `make regen-db` clean · meta stamp fresh · DB + file + corp-source stale-name sweeps all clean · ruff clean · pre-push gates (cargo-deny, ruff, JSON, systems.db stamp) green. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
jpmschweitzer added 12 commits 2026-06-02 07:14:11 +02:00
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>
Wires the D-237 authored specialization layer into import_economics.py:

- import_system_specialization(): reads specialization_vocabulary.toml
  (FK-validated against commodities; repopulates specialization_vocabulary)
  and system_specialization.toml (UPSERTs economic_specialization +
  cultural_specialization onto system_economy, dominant_faction onto
  system_factions for authored systems only). Hard errors on bad commodity
  FK / projected enum / unknown system_id abort the transaction; prints a
  coverage report + missing-row warnings.
- Called as step 4b in main() (after commodities so the FK resolves, before
  currency zones). economic/cultural columns are importer-owned and cleared
  to NULL first for idempotency; dominant_faction only overwritten for
  authored systems (never globally cleared — shared with other derivation).
- specialization_vocabulary added to MIGRATION_SQL (after commodities for FK)
  so the migration path on existing DBs creates the table, not just fresh
  systems-schema.sql builds — this is what #1011 missed. Also cleared before
  commodities in the FK-safe clear block.
- Both source TOMLs added to IMPORT_ECONOMICS_SOURCES and mirrored in
  check-systems-db-stamp GENERATOR_SOURCES so editing them flips the stamp.

Validated: full non-dry-run import on a copy of the live systems.db exits 0;
27 vocab rows, 27/27/27 economic/cultural/faction set, no missing rows;
spot checks Ran=breadbasket/agrarian, Vuurkloof=independent,
financial_hub=NonPhysical/Specialist. Dry-run also exits 0.

V-SES CI guardrail suite remains #1015; code note flags that V-SES-03
(equal-or-higher) must not hard-fail HUB specializations.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds the V-SES / V-FAC guardrail suite to import_system_specialization():

Always-on hard errors (abort the import transaction): V-SES-01 economic
value in vocabulary; V-SES-03 production_ubiquity_override >= commodity
catalog concentration (HUB values with empty override exempt — they
intentionally project lower); V-SES-04 cultural value in the combined
activity+heritage vocabulary; V-SES-05 faction in 8-value vocab; V-SES-06
vocab commodity FK; plus unknown system_id.

Completeness gates — V-SES-02 (every inhabited system resolves a non-null
economic value) and V-FAC-01 (every inhabited named system has authored
faction) — are HARD only under --strict-specialization (default off). Their
preconditions are the #1014 heuristic fallback (blocked by #982) and the
#1016 content pass; until those land they print as warnings so regen-db
stays green.

Soft warnings (always print): W-SES-01 MonopolySource D-177 review list,
W-SES-02 single-value concentration, W-SES-08 estate_farming + large pop,
W-FAC-01 compact + TRACTUS currency, W-FAC-02 compact + MonopolySource
(terroir/marble exempt), W-FAC-03 syndic_dominant w/o corp HQ, W-FAC-04
compact_sympathetic + MARK currency. Coverage report always prints
economic/cultural/faction counts + BulkClass/ProductionUbiquity dists.

Cultural vocabulary is _CULTURAL_ACTIVITY | _CULTURAL_HERITAGE module
constants — #1016 adds heritage values there in one place.

Validated on a copy of the live DB: default exits 0 (gates as warnings, real
W-SES-08 hit on Arbour); strict exits 1 on V-SES-02 (Sol, Struve) and rolls
back cleanly; dry-run exits 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The #1015 V-SES-03 edit replaced the vocabulary validation loop body and
dropped the trailing vocab_rows.append(), so specialization_vocabulary was
inserted with 0 rows even though per-system UPSERTs (which read the dict
directly via valid_spec_ids) still succeeded. regen-db reported
'vocab 0 | economic 27 | ...'. Restored the append at the end of the loop.

Verified: regen-db now writes 27 vocab rows + 27/27 economic/cultural;
spot checks financial_hub=NonPhysical/Specialist, Ran=breadbasket.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
make regen-db with the D-237 authored layer live: 27-row
specialization_vocabulary, economic_specialization + cultural_specialization
on 27 hero systems, dominant_faction on the authored set. Meta stamp fresh
(check-systems-db OK). Unauthored systems remain NULL pending the #1014
fallback and #1016 content pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Records that the two are a deliberate parallel representation, not a
duplicate: economic_base_primary is uncomputable GTTR prose flavor rendered
to the wiki infobox; economic_specialization is the higher-fidelity enum the
D-233 generator consumes. Notes they must stay mutually consistent (#1016
authors the enum from the same lore; W-SES-03 flags divergence), that
unification was considered and rejected (each carries info the other can't),
and clarifies the DB-canonical / index.md-projection data flow (only the
prose sections are authored in-place). Surfaced when the content-pass review
questioned the redundancy.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
generate_infobox() now renders economic_specialization (Specialization) and
cultural_specialization (Cultural Register) as read-only infobox rows when
authored (NULL = omitted, falls to heuristic). dominant_faction already
showed via Governance. Makes the authored generator-input values visible on
the wiki face so the #1016 content pass output renders. Verified: Ran shows
'breadbasket'/'agrarian'; unauthored systems omit the rows.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The 6-sector content pass (core pilot + deep_frontier/north/east/south/west,
~260 systems read from both index.md and gttr.md) authored economic_
specialization + dominant_faction for the systems whose lore makes those
identities distinct. Conservative pin bar: corridor-typical systems left NULL
for the heuristic/derivation fallback.

Totals now: economic 170 (27 hero + 143), faction 76 (27 hero + 49),
cultural still 27 (DEFERRED — the culture pass needs a canonical heritage
vocabulary first; the agents surfaced ~30 real heritages from the names plus a
genuine Middle-East/Arabic gap, to be reconciled into one taxonomy before
writing cultural_specialization).

regen-db green, stamp fresh, all CI guardrails pass. Soft warnings are the
expected D-177 MonopolySource review list, the known Arbour estate/breadbasket
question, and sparse-corp_presence W-FAC-03 advisories — none blocking.

Notable pins: Haodu financial_hub/syndic_dominant, Matamba legal_archive,
Inhambane/Sonnwend/etc breadbasket, the terroir cluster, the west_reach
Compact zone, Aurelius governance_center/veil_institute. FLAGs left NULL
pending human calls (ISPI=veil_institute?, Gate-Corp-as-faction).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reconciles the ~30 inconsistent heritage proposals from the 6-sector #1016
content pass into one canonical cultural_specialization heritage vocabulary
(47 values). Key reconciliations: norse_compact->nordic (un-fuses people from
faction), spanish_iberian+spanish_hispanic->spanish, brazilian_portuguese+
lusophone_frontier->brazilian, italian_northern->italian, afrikaans_cape->
afrikaans, french_provencal+french_canadian->french. No compound values; one
token per system (blends take dominant heritage or the cosmopolitan activity
value).

Maintainer decisions (2026-06-01): keep ALL values distinct (no lumping —
welsh/afro_brazilian/cape_malay/xhosa/luxembourgish/konkan all retained);
keep empty-but-complete slots (yoruba/hausa/hungarian/persian/turkic). Fills
the Middle-East gap the pass exposed: arab/persian/turkic added even at near-
zero current usage so the canon is complete.

Logs the southern-African overrepresentation (~25/300, afrikaans=15) as a DLC
content-rewrite rebalancing task (#1019) rather than lumping the taxonomy.

Migration note included: 4 already-shipped hero cultural values use old suffix
forms (afrikaans_cape, french_provencal, italian_northern, norse_compact) and
will be renamed in the culture-write pass when _CULTURAL_HERITAGE is replaced.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The corridor over-represented southern-African heritage (afrikaans on 15
systems; arab=2, persian/turkic=0) as an artifact of the earlier
name-balancing overcorrecting. Convert five genuinely-thin afrikaans
systems — whose distinctive threads are heritage-agnostic — into
Arab/Persian/Turkic founders so the cultural cascade is built on a
balanced set. Load-bearing mystery systems (Eerste Wacht / Helderoog /
Brandpunt etc.) are left untouched.

  Droëland  (GJ 914A)  -> Marib    (arab)
  Stilwater (GJ 508A)  -> Sawad    (arab)
  Koeberg   (GJ 1245B) -> Akhgar   (persian)
  Skuilplek (GJ 722)   -> Siginak  (turkic)
  Carnarvon (GJ 680)   -> Golestan (persian; Mostert dynasty -> Farahani)

Result: afrikaans 15->10; arab 0->2, persian 0->2, turkic 0->1.

Full narrative retouch (not just names): gttr.md + index.md prose,
body/station proper_names, cultural_specialization, gttr_hook,
atlas_city_names, and the four brand-corps named after the converted
systems (corp IDs kept stable; only display names + products renamed).
Cross-references in neighbour systems, the catalog, the aggregate
drifter guides, and the atlas proposals are updated to match.

arab/persian/turkic added to _CULTURAL_HERITAGE so the values validate;
the full canonical 47-value migration remains #1016.

Also fixes a pre-existing canon bug: Sawad (GJ 508A) no longer claims
GJ 914A is "unsettled" — it is Marib, a three-century settlement.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The pre-execution conversion plan and shipped-state addendum for the
South-African heritage rebalance: per-system field maps, the worked
gttr rewrites, the cross-reference cleanup list, and the rationale for
keeping load-bearing mystery systems out of scope.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jpmschweitzer added 1 commit 2026-06-03 09:17:24 +02:00
Review fixes for the #1019 heritage rebalance:

- Marib's farm world Ghouta -> Ghawr (Miri): "Ghouta" carries strong
  modern associations (2013 Damascus attack); Ghawr (the Jordan Rift
  Valley, an irrigated lowland farming region) keeps the water-fed-
  drylands sense without the resonance.
- Add dominant_faction = "independent" to GJ 914A / 508A / 1245B (Hoshe)
  — all five rebalanced systems are self-governing independent
  communities; uniform with siblings GJ 722 / 680 and clears V-FAC-01.
- catalog.md: fill GJ 914A -> Marib and GJ 722 -> Sığınak (Hoshe) — the
  two anchor systems still showed em-dash placeholders.
- Marib gttr: name the second aperture neighbour Sığınak instead of the
  bare "GJ 722" (Miri).

Pre-existing Golestan aperture/spur wording (reviewers split on whether
it is even wrong) is left for a separate content pass — not introduced
by this rename.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Author
Owner

Review — PR #146 (copy: wiki/docs content)

Multi-agent review (Hoshe / Paula / Miri) of the D-237 specialization layer + #1019 heritage rebalance.

Reviewer Focus Verdict
Hoshe QA / integrity REQUEST_CHANGES
Paula Narrative depth APPROVE
Miri World consistency REQUEST_CHANGES

Initial verdict: CHANGES REQUESTED. All actionable findings have now been addressed in 8dc6c0ed4.

Findings & resolutions

# Reviewer Finding Resolution
1 Hoshe system_specialization.toml — GJ 914A/508A/1245B lacked dominant_faction while siblings 722/680 had it; fires V-FAC-01 Fixed — added dominant_faction = "independent" to all three (all five are self-governing independent communities); V-FAC-01 cleared
2 Hoshe catalog.md — GJ 914A & GJ 722 still showed in the name column Fixed — filled in Marib / Sığınak
3 Miri Marib gttr named its 2nd aperture by bare ID "GJ 722" Fixed — now "Sawad and Sığınak"
4 Miri Body name Ghouta carries modern (2013) connotations Fixed — renamed Ghouta → Ghawr (Jordan Rift Valley; keeps the irrigated-drylands etymology without the resonance). Maintainer-confirmed
5 Hoshe Golestan gttr "one aperture connecting to Enugu and Athabasca" vs infobox "2 aperture" Deferred (not introduced here). Inherited verbatim from the original Carnarvon page; reviewers split (Miri reads it as the setting's normal single-gate-spur framing). A proper fix needs a topology decision — tracked for a separate content pass, not this rename

Paula refinements (non-blocking, acknowledged)

  • Landbou Raad gloss ("external Cape-heritage corridor institution") is in Sawad's gttr but not its index prose — minor, left for a future polish pass.
  • "Helderoog" column placement in the Brandpunt naming-convention sentence is debatable but defensible as written.

Verified after fixes

make regen-db clean · stale-name sweep CLEAN across wiki/docs/client · dominant_faction applied to all 5 · Ghawr persisted (atlas_city_names clean) · meta stamp fresh · pre-push gates (cargo-deny, ruff, JSON, systems.db stamp) green.

Paula's standout note: the Golestan opening ("…the irony of naming the place after a walled garden one family tends has occurred to no one as worth commenting on") lands the Drifter's Guide voice well, and the Sawad canon-bug fix (GJ 914A no longer called "unsettled") is confirmed correct.

🤖 Generated with Claude Code

## Review — PR #146 (copy: wiki/docs content) Multi-agent review (Hoshe / Paula / Miri) of the D-237 specialization layer + #1019 heritage rebalance. | Reviewer | Focus | Verdict | |---|---|---| | Hoshe | QA / integrity | REQUEST_CHANGES | | Paula | Narrative depth | APPROVE | | Miri | World consistency | REQUEST_CHANGES | **Initial verdict: CHANGES REQUESTED.** All actionable findings have now been addressed in `8dc6c0ed4`. ### Findings & resolutions | # | Reviewer | Finding | Resolution | |---|----------|---------|------------| | 1 | Hoshe | `system_specialization.toml` — GJ 914A/508A/1245B lacked `dominant_faction` while siblings 722/680 had it; fires V-FAC-01 | **Fixed** — added `dominant_faction = "independent"` to all three (all five are self-governing independent communities); V-FAC-01 cleared | | 2 | Hoshe | `catalog.md` — GJ 914A & GJ 722 still showed `—` in the name column | **Fixed** — filled in **Marib** / **Sığınak** | | 3 | Miri | Marib gttr named its 2nd aperture by bare ID "GJ 722" | **Fixed** — now "Sawad and Sığınak" | | 4 | Miri | Body name **Ghouta** carries modern (2013) connotations | **Fixed** — renamed **Ghouta → Ghawr** (Jordan Rift Valley; keeps the irrigated-drylands etymology without the resonance). Maintainer-confirmed | | 5 | Hoshe | Golestan gttr "one aperture connecting to Enugu and Athabasca" vs infobox "2 aperture" | **Deferred (not introduced here).** Inherited verbatim from the original Carnarvon page; reviewers split (Miri reads it as the setting's normal single-gate-spur framing). A proper fix needs a topology decision — tracked for a separate content pass, not this rename | ### Paula refinements (non-blocking, acknowledged) - Landbou Raad gloss ("external Cape-heritage corridor institution") is in Sawad's gttr but not its index prose — minor, left for a future polish pass. - "Helderoog" column placement in the Brandpunt naming-convention sentence is debatable but defensible as written. ### Verified after fixes `make regen-db` clean · stale-name sweep CLEAN across wiki/docs/client · `dominant_faction` applied to all 5 · Ghawr persisted (atlas_city_names clean) · meta stamp fresh · pre-push gates (cargo-deny, ruff, JSON, systems.db stamp) green. Paula's standout note: the Golestan opening ("…the irony of naming the place after a walled garden one family tends has occurred to no one as worth commenting on") lands the Drifter's Guide voice well, and the Sawad canon-bug fix (GJ 914A no longer called "unsettled") is confirmed correct. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
jpmschweitzer added 1 commit 2026-06-03 09:27:37 +02:00
GJ 680 has aperture_count=2 / gate_connections=2, linking two distinct
systems (Athabasca GJ 1289 and Enugu GJ 75) — but the prose, inherited
verbatim from the original Carnarvon page, described "one gate in, one
gate out, both the same gate" and "one aperture connecting to Enugu and
Athabasca" (self-contradictory). Reword the gttr and index to two gates
while keeping the system's low-through-traffic spur character (the
spur_end topology label and "nobody routes through here" identity are
unchanged). Resolves the deferred PR #146 review finding.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jpmschweitzer closed this pull request 2026-06-03 09:28:35 +02:00

Pull request closed

This pull request cannot be reopened because the branch was deleted.
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: jpmschweitzer/settled-reach#146