Commit Graph
9 Commits
Author SHA1 Message Date
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.7 edbc0f4ff1 feat(simulation): atlas layer-proxy handler — cache hit/miss -> queue (#969, D-225)
handle_atlas_request: cache hit -> serialize Layer1Output, reply Ready; miss ->
resolve the source heightmap (BodySourceResolver) + enqueue an Immediate
AnalyzeBody on the #968 background queue, reply Pending (client re-requests; the
drain system populates the cache so a later request hits); unknown/no-terrain ->
NotFound. Adds the AtlasLayerRequest/Response/Status wire types (+ Serialize on
CascadeLayer). Pure handler; the bridge routing is the proxy's other half.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 11:41:28 +02:00
jpmschweitzerandClaude Opus 4.7 0097fd5027 feat(simulation): mod-first BodySourceResolver (#969, D-225)
First piece of the layer-stream proxy. Resolves body_id -> source heightmap.png
read-only from systems.db (terrain_reference, mirroring CultureResolver's
pattern), searching roots mod-first over the base install. Explicit errors
(UnknownBody / NoTerrainReference / SourceMissing). v1 callers pass the base
root only; the search-order logic is proven with synthetic mod roots so the
mod-first seam is ready (Q-099 covers registering a mod's new bodies).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 11:36:18 +02:00
jpmschweitzerandClaude Opus 4.7 8cedf670f0 feat(simulation): activate background generation tier end-to-end (#968, D-206/D-225)
The D-206 queue (#924) and D-203 cache (#917) were built but never connected to
the running app — the whole background tier was inert. This closes the loop:
submit -> Rayon -> cascade -> completion -> drain -> cache.

- gen_queue.rs: GenWorkItem::AnalyzeBody now carries enqueuer-resolved inputs
  { body_id, heightmap_path, sea_level, body_seed: SeedChain } (D-225 boundary —
  run_work_item stays pure compute, no path/DB resolution). run_work_item runs
  the real cascade: load heightmap.png -> downsample to GRID_W×GRID_H working
  grid (D-202) -> run_layer1 -> BodyWorldState; load failure -> Failed.
  GenCompletion::BodyAnalyzed carries the computed BodyWorldState.
- cascade.rs: CascadeSnapshot::into_body_world_state() conversion.
- plugin.rs (new): GenerationPlugin registers GenerationQueue +
  BodyWorldStateCache and adds a PreInput drain system that inserts BodyAnalyzed
  states into the cache (off the Rayon workers — a cheap channel drain, never
  the ~45ms cascade). Wired into both the production and test app setups.

Tests run the real cascade on a tiny temp heightmap PNG (no committed fixture);
the plugin test proves the full submit->...->cache loop. The proxy (#969) is the
production submitter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 10:47:59 +02:00
jpmschweitzerandClaude Opus 4.7 9bc2ed28f2 feat(simulation): extensible generation cascade harness (#952, D-200)
server/src/atlas/cascade.rs — run_cascade(body_seed, body_id, path,
default_sea_level, up_to) loads Layer 0 (heightmap.png) and runs every layer up
to the requested CascadeLayer, returning a CascadeSnapshot. The pure core
run_cascade_from_heightmap orchestrates the layers without file I/O (testable);
run_cascade is the thin path-loading wrapper.

CascadeSnapshot is extensible — each layer's artifact is an Option that becomes
Some once it runs (Layer 0 heightmap always present, Layer 1 topography next;
#954+ append their fields). The carried SeedChain is unused by the RNG-free
Layers 0-1 and feeds the RNG-using layers later (D-224). CascadeLayer is an
append-only ordered enum.

Tests: layer-gating, same-heightmap determinism, layer ordering. The golden-seed
regression fixture (the #952 deliverable) builds on this next.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 12:09:49 +02:00
jpmschweitzerandClaude Opus 4.7 de9142ce37 feat(simulation): SeedChain seed-derivation primitive in server/src/seed.rs (#952, D-224)
New top-level seed module that owns every deterministic-RNG primitive:
- splitmix64 — the one canonical mixer (was duplicated as a private fn in
  simulation/rng.rs; EntityRng now imports the shared one, no behavior change)
- AtlasRng — moved here from atlas/rng.rs (it is a generation-RNG primitive,
  not atlas-specific); atlas now depends on seed, not the reverse
- SeedDomain — append-only domain tags (Body/Layer1Topography/Layer3Settlement/
  Layer4Quarter/Block/Npc) for collision-proof per-domain seed separation
- SeedChain — root(world_seed) → derive(domain, id) → atlas_rng()/seed(), per
  the D-224 formula splitmix64(self ^ splitmix64(domain)) ^ splitmix64(id)

Structural move only — SeedChain is not yet threaded through the cascade
callers (skeleton_gen still uses ad-hoc wrapping_add pre-mixing); that is the
next step. Unit tests cover the splitmix64 known-vector, avalanche,
determinism, domain/id separation, and chain composition.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 11:51:09 +02:00
jpmschweitzerandClaude Opus 4.7 d418eba8bb feat(simulation): Layer-1 topography pipeline — features, sub-biome, orchestrator (#953)
Wire the empty-world topography cascade (D-208/209/210):
- generator.rs: add SubBiomeVariant (11 variants, D-210) + sub_biome and
  terrain_modification_cost fields on GeographicAttractor; AttractorType
  is now Copy.
- features.rs (new, D-209): extract the 7 attractor tags from heightmap +
  drainage. Coast/lake derived from the heightmap (D-209/D-223
  reconciliation — markers are names-only now, no polygons). Deterministic
  (sorted seeds, integer keys, bucket-grid thinning); strength-capped at
  MAX_ATTRACTORS preserving type diversity. Shared TerrainAnalysis
  (masks/slope/moisture/percentile) feeds both extraction and sub-biome.
- subbiome.rs (new, D-210): classify sub-biome + terrain_modification_cost
  from elevation/slope/moisture/latitude. Volcanic stays in the enum but
  is not emitted (no heightmap signal).
- layer1.rs (new): run_layer1 orchestrator + attach_feature_names (D-223
  pool names to largest rivers / Alpine peaks).
- attractor_matching constructors updated for the new fields.

76 atlas tests pass; run_layer1 determinism verified.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 00:35:39 +02:00
jpmschweitzerandClaude Opus 4.6 332b9404be fix(simulation): address PR #142 review — 11 issues resolved
Rust fixes: D-218 Backwater complexity (moved to Full arm), priority
queue dispatch gated on thread saturation, panic→soft-fail in
name_index, duplicated LCG unified into atlas::rng module, misleading
Safety comment removed, D-210 SubBiomeVariant deferred to #948.

Schema/data fixes: atlas_city_positions table (D-211 persistence),
settlement_class column on atlas_city_names, per-body transaction
boundaries in import_province_boundaries, import_city_names.py added
to GENERATOR_SOURCES, Python perf documented.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-03 15:30:50 +02:00
jpmschweitzerandClaude Sonnet 4.6 b9fd7a3fc8 feat(simulation): add server/src/atlas/ — full Phase 1 generation pipeline
Ten-module atlas package implementing the D-194–D-218 district generation
stack: heightmap loader, BodyWorldState LRU cache, D8 drainage routing,
background generation queue, five-phase attractor-matching, three-component
district mix, block irregularity, tile condition thresholds, and the Phase 1
skeleton generator that wires them into DistrictSkeleton.

Closes #916 #917 #918 #919 #920 #922 #923 #924 #899.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 18:11:13 +02:00