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).
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).
## 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.
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>
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>
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:
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.)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
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
DrainageBasin) — who controlsthe province, mapped from the system's authored
dominant_faction.Industrial, from TerritorialStatus + economic role (status wins).
perimeter / hub-and-spoke. Derived + stored only; block-adjacency enforcement
stays with the quarter generator (#957).
Freebearing is seed-varied (0–359) so grids differ per seed.Design decisions (with the user)
dominant_faction → TerritorialStatusmapping replaces D-212's numericfaction_influencethresholds (not present in the data). Grounded inwiki/factions/:concord_assembly/veil_institute→ CommissionControlled,syndic_dominant→ CorpTerritory,compact/compact_sympathetic→AutonomistHeld (new),
disputed/mixed→ ContestedZone,independent/NULL → FrontierUnclaimed.AutonomistHeldvariant — the Compact of Westphalia is a self-governingbloc 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/Derelictremain unreachable fromdominant_factionalone —deferred (documented).
Wiring (DB-free, D-225)
CityContextReader::read_body_dominant_faction→ atlas proxy reads it oncache-miss →
AnalyzeBodywork item →run_cascade→run_layer3/match_cities.Enrichment stored on
CityPlacement; TerritorialStatus stamped on eachDrainageBasin(uniform per body for now —dominant_factionis 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 --checkclean,cargo clippy --all-targets -- -D warningsclean.archetype precedence, arrangement mapping, seed-varied
Freebearing, andend-to-end enrichment propagation through the cascade (a
concord_assemblybody → CommissionControlled basins + Commission/RadialCore placements).
territorial_statusonly; selectionunchanged);
atlas_response_ready.msgpackregenerated. Unrelated snapshotfixtures left untouched.
Closes #956.
Review: layer3-enrichment → main (type: code)
Reviewers: Hoshe (QA) + Tyre (architecture). Gate: clippy
--all-targets -D warningsclean; 1300+ lib + integration tests pass.Hoshe (QA / correctness): APPROVE (after fix)
Derivation logic correct, D-212/213/214/215 spec-compliant.
AutonomistHeldcovered in every
TerritorialStatusmatch;political_archetypeexhaustive; nof32 in any decision path;
splitmix64(seed ^ city_id) % 360is deterministic andcity-unique; the LEFT JOIN handles NULL faction / missing body. One test-coverage
gap, now fixed:
attractor_matching.rs(territorial_status_faction_mapping)"mixed"(grouped with"disputed") unasserted21544cbb4Tyre (architecture): APPROVE
Sound implementation pass; all five architectural questions resolve cleanly.
derivation-source correction, not a new concept).
AutonomistHeldisfaction-canon-grounded;
veil_institute → CommissionControlleddefensible;IndigenousHeld/Derelictdocumented-deferred is honest.dominant_factionpre-resolved on the mainthread at enqueue, Rayon item stays pure. Two-query split (settlements + faction)
is cleaner than merging; negligible on a cache-miss path.
per-province-ready).
match_citiesseam acceptable — the matchedattractor_typeis an input toFoundingOrientation, so deriving at match-time is natural;
city_characterhelper is a clean private extraction.
seed-varied
Freebearing satisfies D-215's per-seed angular variation at thedata level.
Verdict: APPROVED
(Hoshe's sole comment fixed; both reviewers approve.)
Pull request closed