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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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 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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
- 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>
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>
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>
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>
- 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>
- 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>
- 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>
Define the type-definition layer the Phase-4 fill-seam tickets depend on
(D-229/D-230/D-231/D-232/D-233), compiling with stubs/defaults; behavior
logic lands in #982-985/#998.
- New types in generator.rs: BuildingPropertyTag, FloorExtent +
FloorHeightProfile (floor_at_voxel_z/voxel_range_for_floor, resolves
Q-104), BuildingEntryClass, ConstructionEra, ZoneTypeId, MorphologyZone,
BulkClass(5), ProductionUbiquity, DoorSpec, InteriorDescriptor,
DistrictWorldState.
- Rename spatial AccessTier -> ZoneAccessTier to free the name for the new
per-building BuildingEntryClass.
- CityGenerationContext: +morphology_zone, +trait_selection,
+dominant_bulk_class, +dominant_production_ubiquity.
- BodyWorldState: +districts (DistrictWorldState w/ block_tags).
- GenCompletion::SkeletonGenerated carries body_id + DistrictWorldState;
plugin handler inserts into BodyWorldState.districts.
- Add smallvec as a direct dep (DoorSpec list stays Vec for now, TODO).
cargo check --all-targets / clippy clean; 1259 lib tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Anchors the events-first / wave-fallback COALESCE that #1000 will write into import_economics.py MIGRATION_SQL. Founding-edge values from systems-framework-final-miri.md: wave_1=600, wave_2=500, wave_3=300, wave_4=100, wave_5=40, origin=NULL (Sol excluded per D-236). historical_events is currently empty so events-first is forward-compatible scaffolding; wave-fallback is the practical default for all 273 inhabited bodies today.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Formalises what was previously implicit in D-223's naming exemption and GJ-0's wiki frontmatter into a single canonical scope rule. (a) Phase-4+ generation pipelines exclude Sol bodies (settlement_wave='origin' gate); (b) Atlas renders Sol at system level only -- no zoom; (c) deeper Sol treatment is reserved for a future DLC. Cross-refs D-145 (DLC precedent), D-191 (Atlas Phase-3), D-223.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>