Commit Graph
2245 Commits
Author SHA1 Message Date
jpmschweitzerandClaude Opus 4.8 8b1005221d docs(simulation): finish district→quarter doc residue in gen_queue (#950)
PR #151 review (Hoshe/Tyre): four doc comments in gen_queue.rs still said
"district" next to the renamed quarter_id field / generate_quarter_skeleton.
Pure comment update, no code change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 13:15:36 +02:00
jpmschweitzerandClaude Opus 4.8 c71c26a1a6 refactor(simulation): rename DistrictSkeleton→QuarterSkeleton per D-222 (#950)
D-222 renamed the 512m generation cell from District to Quarter (District
is now a new 2048m tier above it). Align the generation skeleton code to
the canonical vocabulary. Pure naming — no behavior change; all 1296 lib
tests + integration tests pass unchanged.

Renamed (spatial-cell identifiers):
- DistrictSkeleton → QuarterSkeleton, DistrictWorldState → QuarterWorldState
- DistrictId → QuarterId, DistrictContext/DistrictBoundaries → Quarter*
- field district_id → quarter_id, district_type → quarter_type
- BodyWorldState.districts map → .quarters
- generate_skeleton → generate_quarter_skeleton

Deliberately left as-is (these name functional ZONING, not the spatial
tier — orthogonal to D-222): DistrictType, DistrictLayoutMode, the
district_mix module (DistrictMix/compute_district_mix), and the
GenWorkItem::GenerateSkeleton / GenCompletion::SkeletonGenerated variants.

Also aligned the perception "sim tile" → "subtile" vocabulary (D-222:
Subtile = 0.5m) in decisions/perception.md and the generation-cascade code
comments. Historical D-066/D-094/D-201/D-220 decision bodies keep their
existing D-222 amendment notes (not rewritten in place); the public
max_offset_sim_tiles fn name is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 13:06:44 +02:00
jpmschweitzerandClaude Opus 4.8 f7a21c6b8d chore(meta): gitignore local agent tooling caches (.clide, .pql)
Per-machine tool dirs (.clide/settings.yaml, .pql/pql.db) that appeared as
untracked noise; not shared, should never be committed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 23:39:42 +02:00
jpmschweitzerandClaude Opus 4.8 f1d52944af fix(simulation): correct crate name in log10_floor doctest
The doctest imported `server::bps::log10_floor`, but the library crate is
`settled_reach_server` — so `cargo test --doc` failed to compile the
example (unresolved module `server`). Broken since the helper landed in
#145; it only surfaces under `--doc`, not `--lib`, so the pre-push gate
(which runs `--lib`) never caught it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 17:44:06 +02:00
jpmschweitzerandClaude Opus 4.8 2d8367d3bc docs(simulation): correct stale cascade docs and pin layer order (#955)
Address the doc/test-correctness items from PR #149 review:

- cascade.rs: Layer 3 is RNG-free (pure fn of attractors+cities); it does
  not consume the carried SeedChain. Corrected the "first RNG-using layer"
  claims on the module doc and the Settlement variant (Hoshe H3).
- cascade.rs: layers_are_ordered now also asserts Topography < Settlement,
  pinning the invariant the up_to >= Settlement guards rely on (Tyre T2).
- features.rs: strength is an integer 0-100 (quantized at extraction), not
  f32, and consumers that rank by it use the integer value (Hoshe H2).
- layer_proxy.rs: AtlasLayerRequest.up_to is not yet honored — run_work_item
  runs through Settlement unconditionally; per-request depth deferred to
  #1021 (Tyre T1).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 17:33:36 +02:00
jpmschweitzerandClaude Opus 4.8 9d8ff8b341 fix(simulation): fall back on unrecognized settlement_class (#955)
read_body_settlements propagated a parse error for any non-NULL but
unrecognized settlement_class, which the atlas proxy swallowed and then
enqueued the body with zero cities — one malformed row silently dropped
placement for the entire body. Treat an unknown variant like NULL: fall
back to PopulationBudget with a warning. parse_settlement_class stays
strict for the D-199 read_set path, which must abort on bad fields.

Found in PR #149 review (Hoshe H1). Adds a test covering the fallback.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 17:33:24 +02:00
jpmschweitzerandClaude Opus 4.8 9fa06f3401 chore(meta): update changelog
Mark Layer-3 settlement placement (#955) as running in-game now that the
B/E/F plumbing (per-body settlement read → work item → cache-miss proxy)
is wired.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 17:14:43 +02:00
jpmschweitzerandClaude Opus 4.8 e2787fbfb1 feat(simulation): run Layer-3 settlement placement in the runtime cascade (#955)
Wire the existing D-211 attractor-matching engine into the live
generation cascade so settlements are placed in-game, not just in tests.

- CityContextReader::read_body_settlements reads a body's settlements
  from atlas_city_names (ordered by id for determinism). NULL
  settlement_class defaults to PopulationBudget, not NameLocked: the
  class is NULL until placement runs, and NameLocked would force every
  settlement Tier-A in match_cities and collapse population tiering
  (D-211). NULL economic_role falls back to residential.
- The AnalyzeBody work item carries the body's Vec<CityRecord>, and
  run_work_item now runs up_to Settlement (was Topography). A body with
  no settlements yields empty placements at negligible cost.
- The atlas layer proxy reads settlements on a cache miss and pins them
  onto the work item, keeping the Rayon task DB-free (D-225). A read
  failure is non-fatal: log and place no cities (Layer 1 still runs).
  Threaded through a new CityContextReaderResource Bevy resource opened
  in main.rs, mirroring BodySourceResolverResource.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 17:14:18 +02:00
jpmschweitzerandClaude Opus 4.8 f748b017cb chore(meta): update changelog
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 16:31:35 +02:00
jpmschweitzerandClaude Opus 4.8 adce12035a fix(simulation): route atlas_response fixtures in the serialize test
all_fixtures_deserialize panicked with "unknown fixture naming
convention: atlas_response_ready" — the test reads every .msgpack in
client/tests/fixtures/msgpack but had no branch for the atlas_response
prefix (the AtlasLayerResponse fixtures gen_fixtures emits, #969). A
pre-existing gap (present on main; the suite isn't gated by the pre-push
hook, which runs cargo-deny/ruff/JSON/stamp, not cargo test).

Add an atlas_response branch deserializing AtlasLayerResponse, and
regenerate atlas_response_ready.msgpack so its bytes match the now-integer
GeographicAttractor types (#955).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 16:31:19 +02:00
jpmschweitzerandClaude Opus 4.8 ab084269f3 feat(simulation): integer-deterministic Layer-3 settlement placement (#955)
Wire the existing attractor-matching engine (#919/#925) into the
generation cascade as Layer 3, and make the whole placement-scoring path
integer-deterministic.

Layer 3 (D-211):
- CascadeLayer::Settlement + Layer3Output (placements) on the snapshot;
  BodyWorldState gains a `placements` field (the D-203 hot cache).
- run_layer3 runs the five-phase match_cities against Layer-1 attractors
  via the authored D-195 compatibility matrix; pure function of
  (attractors, cities) — no RNG. cities are passed in by the caller so the
  cascade stays DB-free and testable. A `// cache seam` marks where a
  persistent cache wraps it later (#1021).
- gen_queue passes &[] for now (Topography needs no cities); the runtime
  settlement read (gen_queue/layer_proxy) is the #955 follow-on.

Integer determinism (D-010 / D-227 — D-195 amended):
- Wiring match_cities into the deterministic cascade made its f32 scoring
  a live cross-platform divergence risk (a near-tie comparison or the
  Hungarian's f32 reductions can round differently per platform → a
  different world from the same seed). Converted the entire path to
  integers: CompatibilityMatrix is a 0-100 affinity table; attractor
  strength is 0-100 and terrain cost is a percent (100 = baseline),
  quantized once at the Layer-1 feature boundary; cell_score, the
  Hungarian, and CityPlacement.score are i64. No f32 in any placement or
  ranking decision.
- Layer-1 golden fixture rebaked: confirmed selection/positions are
  unchanged (same 256 attractors, 93 river cells) — only the strength/cost
  representation changed.

Tests: lib green (1292); new settlement_layer_places_cities_deterministically
covers placement + determinism + propagation into BodyWorldState.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 16:30:57 +02:00
jpmschweitzerandClaude Opus 4.8 a4727bf73e fix(economics): address PR #148 review — dry-run guard + pin validation
Review fixes (Hoshe/Tyre, both APPROVE):

- populate_trait_templates / populate_atlas_body_trait_bias: the table
  DELETEs ran unconditionally (safe only via transaction rollback on
  dry-run, and divergent from every other populate_* function). Restructured
  so validation + guardrails always run (dry-run now actually surfaces the
  would-bake counts and catches errors) but mutations happen only under
  `if not dry_run:`. Verified: --dry-run reports 28 templates, writes nothing.
- atlas_body_trait_bias: reject `pin` entries that carry a
  weight_multiplier_bps (pin is mandatory, no multiplier) — closes a silent-
  accept gap before #1017 authors ~30-40 real pins.

Deferred (noted on tickets): visual_bundle fallback-map completeness
(Phase-5/Araminta), pin-count-vs-K bake check (#1017 acceptance),
geographic_sector pool-narrowing semantics (#977).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 11:36:37 +02:00
jpmschweitzerandClaude Opus 4.8 298c37b1ee chore(meta): update changelog
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 11:05:26 +02:00
jpmschweitzerandClaude Opus 4.8 375d04a29d data(content): core architecture-flavor trait-template catalog (#1005)
The D-232 core hand-curated catalog (28 templates) the architecture-flavor
draw reads from, baked into trait_templates (#993):

- Cross-corridor pool (10): economic-function templates gated by BulkClass
  (extraction/industrial/cold-chain/precision/information/civic) + universal
  baselines + the foreign-import swerve. Guarantees the CI floor.
- Per-corridor baseline (8): each corridor's default cohesive look — core
  cosmopolitan, north anglo-frontier, south lusophone, west germanic +
  compact-cooperative, east dense-utilitarian, deep-frontier surname +
  hardscrabble.
- Heritage sub-pools (10): deep-history callbacks tied to the D-237 heritage
  taxonomy (scottish highland, west-african compound, iberian hacienda,
  atlantic creole, nordic timber, central-european blok, east-asian temple,
  vietnamese water village, afrikaans kraal, arab oasis).

Each template = holistic bundle: two-tier eligibility (hard gates
bulk_class/ubiquity/prosperity_bps + soft weight mods), zone_affinity over
the real DistrictType enum, allow/block tags from a shared ObjectTag
palette, and a D-235 visual_bundle with generic fallback parents. All
numerics integer basis-points (D-010).

Adds the D-232 CI guardrails to the baker (V-TT-01: >=5 templates eligible
per BulkClass; V-TT-02: no template >60% of pool weight) — both pass with
margin (23-24 eligible/class, 5% max share). Catalog can grow via the
bounded Gemma pass (#992); hero pins are #1017.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 11:04:43 +02:00
jpmschweitzerandClaude Opus 4.8 a133b6416e feat(schema): trait_templates + atlas_body_trait_bias tables + bake (#993)
D-232 architecture-flavor storage mechanism (content is #1005/#1017):

- trait_templates: shared catalog of holistic template bundles — two-tier
  eligibility (hard gates bulk_class/prosperity_bps/ubiquity + soft weight
  mods), zone_affinity, allow/block tags, visual_bundle. List/map fields
  are JSON; all numerics integer basis-points (D-010).
- atlas_body_trait_bias: sparse per-body hero pins — pin/boost/suppress
  with basis-point multiplier ranges (boost ≤3×, suppress ≥0.33× never 0).
- Baked at import (steps 14/15) from wiki/economics/architecture_trait_
  catalog.toml + architecture_trait_bias.toml. FK-validated (body_id →
  bodies, template_tag → trait_templates), enum + multiplier-range checks,
  graceful on absent source. Source location provisional pending Q-107;
  the baked tables are invariant per D-232. Retires the round-2
  atlas_body_culture tables.
- Catalog ships a 3-template bootstrap seed to prove the bake end-to-end;
  the full ~35-template catalog is #1005, hero pins #1017.
- Stamp sources updated (IMPORT_ECONOMICS_SOURCES + GENERATOR_SOURCES).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 10:47:35 +02:00
jpmschweitzerandClaude Opus 4.8 00c8574e11 data(economics): address PR #147 review — fused/activity pin fixes
Review fixes for the #1016 cultural pass (Hoshe/Paula/Miri):

- Kruger 60 (GJ 860A) xhosa -> cosmopolitan (Miri): GTTR describes an
  Afrikaner/Xhosa/Zulu founding "without mapping cleanly onto any of
  them" — the textbook genuinely-fused case, which taxonomy rule 4
  resolves to cosmopolitan rather than one of the three. Commented.
- Altmark (GJ 357) financial_technocratic -> cosmopolitan (Paula):
  reverts to the original shipped value; the GTTR reads as commercial
  non-alignment, not credential-based technocracy.
- Kampala Gate (GJ 667B) + Moyale (GJ 1292) keep swahili but add inline
  comments documenting that these are East-African-INTERIOR founders
  (Baganda; Kenyan/Ethiopian Borana-Oromo) for which the taxonomy has no
  dedicated token — swahili is the nearest available, NULL would fall to
  the wrong corridor default. Gap logged for a follow-up taxonomy value.
  Mwangaza (693) swahili is literally correct (coastal) — untouched.
- heritage-taxonomy-draft.md: stale "(38)" subheadings -> "(47)" to match
  the actual canonical count (Hoshe/Miri doc typo).

Retracted: Pedra Seca (GJ 421B) xhosa — reviewer thought it lacked
authored backing, but its gttr.md explicitly states "Afrikaans and Xhosa
heritage"; pin kept.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 10:23:42 +02:00
jpmschweitzerandClaude Opus 4.8 9e791240c5 chore(meta): update changelog
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 10:06:56 +02:00
jpmschweitzerandClaude Opus 4.8 21793c1a94 data(economics): #1016 cultural-write pass + canonical 47-value heritage migration
Completes the deferred cultural half of #1016 and migrates the heritage
vocabulary to the canonical 47-value taxonomy (D-237).

Migration (mechanical):
- _CULTURAL_HERITAGE replaced with the canonical 47-value set
  (docs/.../heritage-taxonomy-draft.md). Renamed the 4 shipped hero
  values to canonical: afrikaans_cape->afrikaans, french_provencal->
  french, italian_northern->italian, norse_compact->nordic.

Content pass (authored from GTTR/name heritage triage, 6-sector fan-out):
- +139 new cultural_specialization pins and 1 change (Altmark
  cosmopolitan->financial_technocratic), taking coverage 32 -> 171
  across 54 distinct values. Each pin is grounded in an explicit GTTR
  founding-community statement or system/feature name etymology, applied
  only where founding heritage DIVERGES from the corridor baseline
  (D-167/D-232); corridor-typical systems left NULL.

Distribution is now balanced and diverse — portuguese 15, german 12,
vietnamese 10, afrikaans 10 (no longer dominant post-#1019), then a long
tail filling the previously-missing slots (welsh, herero, czech, akan,
hungarian, konkan, afro_brazilian, cape_verdean, shona, arab/persian/
turkic, etc.).

Judgment calls (flagged for review):
- Kruger 60 + Pedra Seca -> xhosa (mixed SA founding; adds diversity).
  Pedra Seca has a Portuguese name but Afrikaans/Xhosa GTTR founding —
  name/heritage mismatch noted for a future content fix.
- Kampala Gate / Moyale / Mwangaza -> swahili as the nearest token for
  East-African-interior heritage; taxonomy may want a dedicated value.
- Kept hero pins Kensho=scholarly, Keid=scholarly, Nyrheim=nordic.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 10:06:23 +02:00
jpmschweitzerandClaude Opus 4.8 e1e1185cc3 fix(content): correct Golestan topology wording to match 2-aperture data
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>
2026-06-03 09:27:30 +02:00
jpmschweitzerandClaude Opus 4.8 8dc6c0ed42 data(content): address PR #146 review — Ghawr rename, faction pins, catalog
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>
2026-06-03 09:17:07 +02:00
jpmschweitzerandClaude Opus 4.8 36ae931997 chore(meta): update changelog
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 07:12:00 +02:00
jpmschweitzerandClaude Opus 4.8 03188de16d docs(workshops): record #1019 heritage rebalance batch
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>
2026-06-02 07:11:20 +02:00
jpmschweitzerandClaude Opus 4.8 8844bef139 data(content): rebalance 5 thin afrikaans systems to MENA heritage (#1019)
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>
2026-06-02 07:11:10 +02:00
jpmschweitzerandClaude Opus 4.8 01ba14ada9 docs(workshops): canonical D-237 heritage taxonomy (47 values, approved)
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>
2026-06-01 16:49:00 +02:00
jpmschweitzerandClaude Opus 4.8 8addf04835 data(economics): #1016 econ+faction content pass (143 systems, cultural deferred)
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>
2026-06-01 16:27:24 +02:00
jpmschweitzerandClaude Opus 4.8 0251c65b96 feat(wiki): surface D-237 specialization fields in the system infobox
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>
2026-06-01 14:29:37 +02:00
jpmschweitzerandClaude Opus 4.8 e0d796357f docs(decisions): document economic_base_primary vs economic_specialization seam (D-237)
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>
2026-06-01 13:42:38 +02:00
jpmschweitzerandClaude Opus 4.8 c6abff0f44 chore(db): regen systems.db — D-237 specialization layer populated
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>
2026-06-01 13:09:56 +02:00
jpmschweitzerandClaude Opus 4.8 9fe4ddfb04 fix(economics): restore dropped vocab_rows.append in import_system_specialization
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>
2026-06-01 13:09:49 +02:00
jpmschweitzerandClaude Opus 4.8 2f994c1795 feat(economics): D-237 specialization CI guardrails + coverage report (#1015)
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>
2026-06-01 12:44:03 +02:00
jpmschweitzerandClaude Opus 4.8 883c1ab0b1 feat(economics): import_system_specialization() — D-237 authored layer (#1013)
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>
2026-06-01 09:09:06 +02:00
jpmschweitzerandClaude Opus 4.8 4f53793755 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>
2026-05-31 21:04:00 +02:00
jpmschweitzerandClaude Opus 4.8 a4541bde18 chore(db): raise ticket WIP limit 3 → 5
Per maintainer call — 3 was too tight for the parallel Phase 4 work in
flight; 5 better matches how many tickets are genuinely active at once.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 19:33:42 +02:00
jpmschweitzerandClaude Opus 4.8 2e9622d7ed docs(decisions): amend D-199/D-214/D-232 for D-237 specialization layer
Completes ticket #1010. The D-237 record and D-233 re-amendment landed
earlier; this adds the three downstream amendments:

- D-199: read-set gains economic_specialization + cultural_specialization;
  dominant_faction now authored-sourced where present.
- D-214: dominant_faction is an authored 8-value vocabulary for named
  systems (heuristic fallback otherwise); lattice_commission is not a
  faction value (Commission is a regulator). Archetype mapping unchanged
  but now reads a trustworthy faction for the systems the heuristic got
  wrong (e.g. Groombridge → Syndic/Corporate, not Commission).
- D-232: template draw reads authored cultural_specialization to select/
  bias the pool when founding heritage diverges from the corridor baseline
  (Phase-4 correctness, not flavor); NULL = existing corridor algorithm.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 19:33:40 +02:00
jpmschweitzerandClaude Opus 4.8 1521182c72 docs(decisions): open Q-108 — subterranean/enclosed settlement morphology
The D-233/D-237 built-world fill model is implicitly a surface model
(roofed-coverage fraction, operations surface, scatter-vs-concentrate on
open ground), but bodies.settlement_pattern already carries enclosed
morphologies (underground_concentrated, cave, domed, underground_complex)
that nothing in the chain reads — not in the D-199 read-set, not in
city_context_reader, not in skeleton_gen. Engine z-level primitives exist
(D-110, D-106, UndergroundComplex) but no morphology switch connects them
at the built-world layer, so a body like Vuurkloof (GJ 35) would generate
as a surface town against its underground-concentrated lore.

Q-108 schedules the surface-vs-enclosed morphology debate before the
Phase 4 content pass authors built form for enclosed-habitat bodies.
Tracked by ticket #1018. Surfaced via Vuurkloof during the
system-economic-specialization workshop.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 19:09:17 +02:00
jpmschweitzerandClaude Opus 4.8 95121fa507 chore(meta): update changelog
Add the D-237 authored specialization layer (and D-233 re-amendment) under
[Unreleased].

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 18:41:22 +02:00
jpmschweitzerandClaude Opus 4.8 b9b39e84d0 chore(skills): log workshop-start improvements from this run
Running notes for a later workshop-start pass: read-only participant agents
can't self-write output files (lead-as-scribe relay needed); SI has no
round-1 task; create+assign tasks before spawning; TaskCreate is one-per-call;
decision claim is not idempotent (caused a stray duplicate ID); the optional
scout-critic idea and its guardrails; and background always-present teammates
can be slow to consume shutdown_request at wrap-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 18:40:15 +02:00
jpmschweitzerandClaude Opus 4.8 33c083f0ef docs(workshops): system-economic-specialization rounds + outcomes
Three-round design workshop (Miri, Burnelli-Sheldon, Paula; documented by
Qatux, ticketed by SI) that produced D-237. Includes per-agent round
outputs, round notes, the independent scout critique, and the final
workshop-outcomes.md with the consolidated schema, 27-value economic
vocabulary, cultural + faction vocabularies, deterministic-varied fallback
spec, must-pin table, and CI guardrails.

Clerk-Skip: workshop discussion docs, no D-record surface (D-237 filed separately)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 18:40:08 +02:00
jpmschweitzerandClaude Opus 4.8 f13216f5af docs(decisions): file D-237 authored specialization layer + re-amend D-233
Add D-237: each inhabited system carries three authored, static (t=0),
deterministic per-system identity fields sourced from
wiki/economics/system_specialization.toml — economic_specialization
(27-value vocabulary, scale encoded in the value), cultural_specialization
(unified activity + heritage vocabulary), and dominant_faction (populate
the existing system_factions column, 8 values, lattice_commission dropped).
Authored lore wins; a deterministic-varied seed-hashed weighted draw is the
fallback for unnamed systems so they don't read identically.

Re-amend D-233 to source dominant_bulk_class x dominant_production_ubiquity
from this authored layer (heuristic becomes fallback). Groombridge encodes
as a financial_hub Specialist district with the GSH clearing house as a
D-222/D-232 landmark rather than a composite vocabulary value.

Add the specialization-layer d2 diagram (3 fields -> D-233/D-232/D-214
consumers). Produced by the system-economic-specialization workshop.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 18:39:57 +02:00
jpmschweitzerandClaude Opus 4.8 edc28d5cdb chore(config): allow read-only file access for teammates + system-economic-specialization workshop brief
- settings.json: add Read(repo/**), Read(/tmp/**), Grep, Glob to the
  allowlist. Teammates inherit settings.json (not settings.local.json),
  which had no Read rule — so every teammate file read escalated to the
  lead as a per-file prompt. This closes that gap.
- Add the system-economic-specialization workshop brief (lore-authored
  per-system dominant-commodity field + within-system weighted variation;
  Q5 covers adding a small identity field set in the same 300-system pass).

Note: agent memory-strip (6c93b698f) + this read-allow reach teammates
only after a Claude Code restart (settings/agent-def snapshot is taken at
lead startup).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 15:52:48 +02:00
jpmschweitzer 06d9708dbb Merge PR #145: wire D-199 economic read-set into generation context (#954)
Layer 2 clean half. Prosperity in integer basis points (D-010).
Reviewed-by: Hoshe (code quality), Tyre (architecture) — both APPROVE.
2026-05-31 14:34:57 +02:00
jpmschweitzerandClaude Opus 4.8 d6e37c0c0e fix(simulation): prosperity in basis points + shared log10_floor helper (#954)
Address PR #145 review. Convert prosperity from f32 to integer basis
points (matching the existing prosperity_bps, D-010 integer-only),
removing both float-determinism bugs by construction:

- New server/src/bps.rs: log10_floor (integer order-of-magnitude) +
  bps_to_f32 edge helper, with boundary tests.
- city_context_reader: prosperity_baseline_bps (u32, 0-10000). role base
  + pop bonus (400*log10_floor, cap 1200) + symmetric noise via integer
  modulo (fixes the always-negative bug) + clamp [1000,9500]. No floats.
- CityGenerationContext.prosperity_baseline -> prosperity_baseline_bps;
  updated the two test context builders. Not serialized — no wire break.
- district_mix population_tier now uses log10_floor (same determinism
  bug class as the comment claimed to avoid).
- Tests in bps + assert positive noise is achievable (the case the old
  test hid).

cargo check/clippy --all-targets -D warnings clean; 1291 lib tests pass;
fmt clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 14:31:27 +02:00
jpmschweitzerandClaude Opus 4.8 6c93b698f5 chore(agents): strip memory: project from one-shot agents
Only Qatux (the librarian — cross-session recall is its job) keeps
project memory. Removed memory: project from the 20 ephemeral
implementer/reviewer/design agents that are spawned per-task and die:
they have no curation discipline and already use decisions/ + briefings/
as shared memory, so an uncurated per-agent store only invited rot.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 13:54:33 +02:00
jpmschweitzerandClaude Opus 4.8 a854b89aa0 feat(simulation): wire D-199 economic read-set into generation context (#954)
Layer 2 clean half. GenerateSkeleton now builds a CityGenerationContext
from a body's real economic read-set instead of stub defaults.

- New CityContextReader (server/src/atlas/city_context_reader.rs): reads
  the 6-field D-199 set (economic_role, prosperity_baseline, population,
  dominant_faction, founding_age_years, settlement_class) via one JOIN;
  prosperity_baseline derived per D-197.
- GenWorkItem::GenerateSkeleton carries the resolved context; run_work_item
  builds the real context instead of DistrictWorldState::default().
- Left at defaults (deferred, documented): dominant_bulk_class /
  dominant_production_ubiquity (#982, design-blocked), trait_selection
  (#1005), morphology_zone + Layer-3 fields (attractor placement / D-204 /
  D-214).

16 new tests; cargo check/clippy --all-targets -D warnings clean; 1279
lib tests pass; fmt clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 13:46:24 +02:00
jpmschweitzerandClaude Opus 4.8 e98a55de5f docs(skills): default post-merge worktree/branch cleanup
- pr-review §7a: after a PR merges, recommend tearing down the worktree
  and deleting the merged topic branch (local + origin) by default —
  state the action, let the user decline; never touch protected branches;
  git branch -d as the unmerged-work safety net.
- whats-next §3c: document the worktree lifecycle — created at activation,
  removed by pr-review §7a at merge; prune stale worktrees before creating.

Closes the gap that left empty worktrees parked at main's HEAD.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 22:56:13 +02:00
jpmschweitzer 273db192b9 Merge PR #144: backfill founding_age_years for inhabited bodies (#1000)
Reviewed-by: Hoshe (data QA), Tyre (pipeline) — both APPROVE.
2026-05-30 22:50:17 +02:00
jpmschweitzer dfd91923e7 Merge PR #143: foundation shared types + struct plumbing (#1006)
Reviewed-by: Hoshe (code quality), Tyre (architecture) — both APPROVE.
2026-05-30 22:49:55 +02:00
jpmschweitzerandClaude Opus 4.8 9f4b1bf02c fix(db): address PR #144 review (#1000)
- Update D-216 amendment text to match the implemented decision:
  events-first uses event_type='colonial_charter' (9 systems, 11 bodies,
  5 diverging from wave) — not the stale founding/first_settlement/
  colonization scaffolding vocabulary.
- Add ORDER BY sort_order ASC to the colonial_charter subquery for a
  deterministic pick if a system ever has two charter rows.
- Add explicit ELSE NULL to the wave-fallback CASE so an unexpected
  settlement_wave leaves a trace instead of silently nulling.

Data unchanged: 269/273 set, 4 Sol NULL; stamp fresh.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 22:07:06 +02:00
jpmschweitzerandClaude Opus 4.8 99da796cde fix(simulation): address PR #143 review (#1006)
- Add D-230 skeleton: DistrictSkeleton field to DistrictWorldState;
  cascade Default to DistrictSkeleton + contained enums/structs. Box the
  GenCompletion::SkeletonGenerated state to avoid large_enum_variant.
- Derive PartialEq on FloorExtent/FloorHeightProfile/DistrictWorldState/
  CityGenerationContext (+ minimal cascade) for downstream assert_eq tests.
- Add 4 unit tests for floor_at_voxel_z / voxel_range_for_floor (uniform,
  basement, variable heights, boundary) — the Q-104 deliverable.
- Drop unused smallvec direct dep (stays transitive via bevy_ecs).
- Key districts insert by skeleton.district_id, sharpen TODO(#957).

clippy --all-targets -D warnings clean; 1263 lib tests pass; fmt clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 22:06:57 +02:00
jpmschweitzerandClaude Opus 4.8 899f447eed fix(simulation): review follow-ups on foundation types (#1006)
- Derive MorphologyZone Default (#[default] AlluvialPlain), drop manual
  impl — clears the clippy --all-targets warning (pre-push gate).
- Fix floor_at_voxel_z doc (described the inverse function).
- Document floor_at_voxel_z / voxel_range_for_floor voxel-z as
  building-relative (base_floor = z:0) for #982-985 callers.
- TODO(#957): districts keyed by city_id is a stub; use district_id.

clippy --all-targets clean; 1259 lib tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 19:16:03 +02:00