feat(simulation): Layer-3 settlement political character (#956) #152

Closed
jpmschweitzer wants to merge 0 commits from layer3-enrichment into main
Owner

Summary

Layer 3 already places settlements (#955). This adds their spatial
character
— derived deterministically and stored per settlement, so the
quarter generator (#957) has what it needs to lay out streets. Implements
D-212/213/214/215. Cascade stays DB-free (D-225); all derivation is
integer-deterministic (D-010).

What each settlement / province now gets

  • TerritorialStatus (D-212, per-province on DrainageBasin) — who controls
    the province, mapped from the system's authored dominant_faction.
  • PoliticalArchetype (D-214) — Commission/Corporate/Pioneer/Military/Academic/
    Industrial, from TerritorialStatus + economic role (status wins).
  • ArrangementPattern (D-215) — radial core / campus grid / ribbon / fortified
    perimeter / hub-and-spoke. Derived + stored only; block-adjacency enforcement
    stays with the quarter generator (#957).
  • FoundingOrientation (D-213) — coast/river/contour/cardinal/free; the pioneer
    Free bearing is seed-varied (0–359) so grids differ per seed.

Design decisions (with the user)

  • dominant_faction → TerritorialStatus mapping replaces D-212's numeric
    faction_influence thresholds (not present in the data). Grounded in
    wiki/factions/: concord_assembly/veil_institute → CommissionControlled,
    syndic_dominant → CorpTerritory, compact/compact_sympathetic
    AutonomistHeld (new), disputed/mixed → ContestedZone,
    independent/NULL → FrontierUnclaimed.
  • New AutonomistHeld variant — the Compact of Westphalia is a self-governing
    bloc that rejects Assembly authority; it fits none of the existing buckets, so
    D-212 is amended to add it (its own political-overlay colour).
  • IndigenousHeld/Derelict remain unreachable from dominant_faction alone —
    deferred (documented).

Wiring (DB-free, D-225)

CityContextReader::read_body_dominant_faction → atlas proxy reads it on
cache-miss → AnalyzeBody work item → run_cascaderun_layer3/match_cities.
Enrichment stored on CityPlacement; TerritorialStatus stamped on each
DrainageBasin (uniform per body for now — dominant_faction is system-level —
but per-province field is forward-compatible).

Records

D-212 amended (AutonomistHeld + mapping + rationale); D-214/D-215 implementation
notes added.

Test plan

  • cargo fmt --check clean, cargo clippy --all-targets -- -D warnings clean.
  • 1300+ lib tests + all integration tests pass. New: faction→status mapping,
    archetype precedence, arrangement mapping, seed-varied Free bearing, and
    end-to-end enrichment propagation through the cascade (a concord_assembly
    body → CommissionControlled basins + Commission/RadialCore placements).
  • Layer-1 golden rebaked (additive territorial_status only; selection
    unchanged); atlas_response_ready.msgpack regenerated. Unrelated snapshot
    fixtures left untouched.

Closes #956.

## Summary Layer 3 already *places* settlements (#955). This adds their **spatial character** — derived deterministically and stored per settlement, so the quarter generator (#957) has what it needs to lay out streets. Implements D-212/213/214/215. Cascade stays DB-free (D-225); all derivation is integer-deterministic (D-010). ## What each settlement / province now gets - **TerritorialStatus** (D-212, per-province on `DrainageBasin`) — who controls the province, mapped from the system's authored `dominant_faction`. - **PoliticalArchetype** (D-214) — Commission/Corporate/Pioneer/Military/Academic/ Industrial, from TerritorialStatus + economic role (status wins). - **ArrangementPattern** (D-215) — radial core / campus grid / ribbon / fortified perimeter / hub-and-spoke. *Derived + stored only*; block-adjacency enforcement stays with the quarter generator (#957). - **FoundingOrientation** (D-213) — coast/river/contour/cardinal/free; the pioneer `Free` bearing is seed-varied (0–359) so grids differ per seed. ## Design decisions (with the user) - **`dominant_faction → TerritorialStatus`** mapping replaces D-212's numeric `faction_influence` thresholds (not present in the data). Grounded in `wiki/factions/`: `concord_assembly`/`veil_institute` → CommissionControlled, `syndic_dominant` → CorpTerritory, `compact`/`compact_sympathetic` → **AutonomistHeld** (new), `disputed`/`mixed` → ContestedZone, `independent`/NULL → FrontierUnclaimed. - **New `AutonomistHeld` variant** — the Compact of Westphalia is a self-governing bloc that rejects Assembly authority; it fits none of the existing buckets, so D-212 is amended to add it (its own political-overlay colour). - `IndigenousHeld`/`Derelict` remain unreachable from `dominant_faction` alone — deferred (documented). ## Wiring (DB-free, D-225) `CityContextReader::read_body_dominant_faction` → atlas proxy reads it on cache-miss → `AnalyzeBody` work item → `run_cascade` → `run_layer3`/`match_cities`. Enrichment stored on `CityPlacement`; TerritorialStatus stamped on each `DrainageBasin` (uniform per body for now — `dominant_faction` is system-level — but per-province field is forward-compatible). ## Records D-212 amended (AutonomistHeld + mapping + rationale); D-214/D-215 implementation notes added. ## Test plan - `cargo fmt --check` clean, `cargo clippy --all-targets -- -D warnings` clean. - **1300+ lib tests + all integration tests pass.** New: faction→status mapping, archetype precedence, arrangement mapping, seed-varied `Free` bearing, and end-to-end enrichment propagation through the cascade (a `concord_assembly` body → CommissionControlled basins + Commission/RadialCore placements). - Layer-1 golden rebaked (additive `territorial_status` only; selection unchanged); `atlas_response_ready.msgpack` regenerated. Unrelated snapshot fixtures left untouched. Closes #956.
jpmschweitzer added 4 commits 2026-06-05 14:58:43 +02:00
Derive and store each placed settlement's spatial character on top of the
#955 placement (D-212/213/214/215). Derivation is pure + integer-deterministic
(D-010); the cascade stays DB-free (D-225) — the enqueuer pre-resolves the
body's system faction onto the work item, like #955's settlements.

- TerritorialStatus (D-212): mapped from the authored dominant_faction
  (territorial_status_from_faction). Adds an AutonomistHeld variant for the
  Compact of Westphalia (self-governing bloc that rejects Assembly authority —
  neither Commission, Corp, Contested, nor truly Frontier). Grounded in
  wiki/factions/. Stored per-province on DrainageBasin.territorial_status
  (uniform per body for now; forward-compatible for per-province faction data).
- PoliticalArchetype (D-214): political_archetype(status, role), status takes
  precedence over economic_role.
- ArrangementPattern (D-215): new 5-variant enum + arrangement_pattern(); the
  block-adjacency *enforcement* stays deferred to the Quarter-skeleton gen (#957)
  — this only derives + stores which pattern applies.
- FoundingOrientation (D-213): existing fn extended with a seed-derived Free
  bearing so pioneer/open-terrain grids vary per seed.

Wiring: dominant_faction threaded through CityContextReader
(read_body_dominant_faction) → atlas proxy (cache-miss read) → AnalyzeBody work
item → run_cascade → run_layer3/match_cities. Enrichment stored on CityPlacement
(political_archetype, arrangement_pattern, founding_orientation).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DrainageBasin gained a territorial_status field, so the Layer-1 golden and the
atlas_response msgpack fixture pick it up. Both changes are additive/
representational — basin/attractor/river selection is unchanged.

- cascade_golden.rs: pass None dominant_faction; golden rebaked (only
  "territorial_status": "FrontierUnclaimed" added per basin).
- gen_fixtures.rs: set the new field in the atlas_response generator; fixture
  regenerated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- D-212: add the AutonomistHeld variant (Compact of Westphalia) and record the
  dominant_faction → TerritorialStatus mapping used in place of the
  numeric faction-influence thresholds (which aren't in the data). Grounded in
  wiki/factions/. IndigenousHeld/Derelict noted as deferred.
- D-214: note the political_archetype derivation + per-settlement storage.
- D-215: note the ArrangementPattern enum + derivation land here; block-adjacency
  enforcement stays with the Quarter-skeleton generator (#957).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add Layer-3 settlement political character (#956).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jpmschweitzer added 1 commit 2026-06-05 15:05:55 +02:00
PR #152 review (Hoshe): the faction→TerritorialStatus mapping test covered 7 of
the 8 D-237 values; add the missing "mixed" assertion (grouped with "disputed",
behavior already correct).

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

Review: layer3-enrichment → main (type: code)

Reviewers: Hoshe (QA) + Tyre (architecture). Gate: clippy --all-targets -D warnings clean; 1300+ lib + integration tests pass.

Hoshe (QA / correctness): APPROVE (after fix)

Derivation logic correct, D-212/213/214/215 spec-compliant. AutonomistHeld
covered in every TerritorialStatus match; political_archetype exhaustive; no
f32 in any decision path; splitmix64(seed ^ city_id) % 360 is deterministic and
city-unique; the LEFT JOIN handles NULL faction / missing body. One test-coverage
gap, now fixed:

# File Issue Status
1 attractor_matching.rs (territorial_status_faction_mapping) Test asserted 7 of 8 D-237 faction values; "mixed" (grouped with "disputed") unasserted Fixed in 21544cbb4

Tyre (architecture): APPROVE

Sound implementation pass; all five architectural questions resolve cleanly.

  • D-212 amendment is the right call (inline, not a new D-record — it's a
    derivation-source correction, not a new concept). AutonomistHeld is
    faction-canon-grounded; veil_institute → CommissionControlled defensible;
    IndigenousHeld/Derelict documented-deferred is honest.
  • DB-free contract (D-225) holds — dominant_faction pre-resolved on the main
    thread at enqueue, Rayon item stays pure. Two-query split (settlements + faction)
    is cleaner than merging; negligible on a cache-miss path.
  • Per-basin storage is the right forward-compatible home (uniform now,
    per-province-ready).
  • match_cities seam acceptable — the matched attractor_type is an input to
    FoundingOrientation, so deriving at match-time is natural; city_character
    helper is a clean private extraction.
  • Scope correct — derive+store here, D-215 enforcement deferred to #957; the
    seed-varied Free bearing satisfies D-215's per-seed angular variation at the
    data level.

Verdict: APPROVED

(Hoshe's sole comment fixed; both reviewers approve.)

## Review: layer3-enrichment → main (type: code) Reviewers: Hoshe (QA) + Tyre (architecture). Gate: clippy `--all-targets -D warnings` clean; 1300+ lib + integration tests pass. ### Hoshe (QA / correctness): APPROVE (after fix) Derivation logic correct, D-212/213/214/215 spec-compliant. `AutonomistHeld` covered in every `TerritorialStatus` match; `political_archetype` exhaustive; no f32 in any decision path; `splitmix64(seed ^ city_id) % 360` is deterministic and city-unique; the LEFT JOIN handles NULL faction / missing body. One test-coverage gap, now fixed: | # | File | Issue | Status | |---|------|-------|--------| | 1 | `attractor_matching.rs` (`territorial_status_faction_mapping`) | Test asserted 7 of 8 D-237 faction values; `"mixed"` (grouped with `"disputed"`) unasserted | **Fixed** in `21544cbb4` | ### Tyre (architecture): APPROVE Sound implementation pass; all five architectural questions resolve cleanly. - **D-212 amendment** is the right call (inline, not a new D-record — it's a derivation-source correction, not a new concept). `AutonomistHeld` is faction-canon-grounded; `veil_institute → CommissionControlled` defensible; `IndigenousHeld`/`Derelict` documented-deferred is honest. - **DB-free contract (D-225)** holds — `dominant_faction` pre-resolved on the main thread at enqueue, Rayon item stays pure. Two-query split (settlements + faction) is cleaner than merging; negligible on a cache-miss path. - **Per-basin storage** is the right forward-compatible home (uniform now, per-province-ready). - **`match_cities` seam** acceptable — the matched `attractor_type` is an input to FoundingOrientation, so deriving at match-time is natural; `city_character` helper is a clean private extraction. - **Scope** correct — derive+store here, D-215 enforcement deferred to #957; the seed-varied `Free` bearing satisfies D-215's per-seed angular variation at the data level. ### Verdict: APPROVED (Hoshe's sole comment fixed; both reviewers approve.)
jpmschweitzer closed this pull request 2026-06-05 15:14:32 +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#152