ADR 0009 — Realm Scope and PolityRank Orthogonal to Settlement.Stage
Context
Valenar's polity ladder is committed at
../../systems/gd-realm-ranks-and-polity.md:
Settlement -> Banner Network -> Province -> Crown, with later
reclamation projects operating at realm scale. That doc also commits
the rule that there is no single Realm-birth moment — polity emerges
through a ladder of expanding holdings, routes, obligations,
authority, and administration. What is not committed is the runtime
shape of the polity ladder: which SECS scope owns the player's polity
identity, which channel carries the current ladder rung, and how
"settlement size" (the per-Settlement six-tier 0..VII population stage
already authored in gd-settlements-and-outposts.md) relates to
"polity rank" (the player's Realm-scale authority).
The drift problem is real. Three current docs use the word "Stage"
for two different things: the per-Settlement size stage (population
gates from Outpost to Capital) and the Act-progression stage (the
seven Act-Arc tiers from Act 0 to Act 7). The
../../acts/README.md tree commits the Act-progression form;
[../../systems/gd-settlements-and-outposts.md] commits the
population form. Forcing the Realm rank onto either of those Stage
fields would collapse three different concerns (population size,
polity authority, Act ladder) into one overloaded field. CK3
separates Title tier (Barony / County / Duchy / Kingdom / Empire) from
Holding development; EU4 / EU5 separates Country tier from province
development; Victoria 3 separates country type from state buildings.
Polity rank and settlement development are independent in every
shipped reference, and Valenar has the same need.
The Foundation Hardening needs the polity-rank primitive
committed before the Wave 3a state-machine row for the
faction-polity cross-act lane can land, before DefenseZones (Act 5)
and Fronts (Act 6) can declare their unlock gates against a typed
scope, and before
./ad-0008-pressure-to-front-emergence-scope-state-machine.md's
FrontCandidate scope has a root to walk to.
Decision
A new scope Realm is committed as the singleton root of the player's
polity. The Realm scope's lifecycle is one row per game (created at
campaign start, retired at campaign end). The Realm scope is the walk
target for FrontCandidate, for the existing Front scope, for
ProvinceDefensePlan ownership, for Crown-scale Activity authority, and
for any later authored scope that needs a Realm-scale root.
A PolityRank enum is committed with the values Outpost,
BannerNetwork, Province, and Crown. The current PolityRank
value is carried as a Base channel on the Realm scope. The exact
channel name is PolityRank and follows the FrontStatus / OperationStatus
precedent of state expressed as a typed enum channel on a scope.
The Realm scope's PolityRank is orthogonal to the per-Settlement
Stage field. Settlement.Stage continues to carry the per-Settlement
population size on the existing 0..VII ladder; that field is per
Settlement, not per Realm. PolityRank is one channel on the
singleton Realm scope, not a per-Settlement field. Composition:
Settlement.Stage gates SettlementRole eligibility (which roles a
Settlement of a given size can host); PolityRank gates Realm-scale
capability (DefenseZones, Fronts, ProvinceDefensePlans).
PolityRank ladder transitions are driven by Realm-scale triggers, not by any single Settlement crossing a population threshold:
Outpost->BannerNetworkwhen the Realm covers at least two Settlements connected via Route coverage (the network condition is authored in../../systems/gd-realm-ranks-and-polity.mdas the "Banner Network" rung; the exact Route-coverage predicate is authored in Wave 3a).BannerNetwork->Provincewhen at least one Settlement under the Realm is designatedProvinceCapital. The Province rank introduces ProvinceDefensePlans and DefenseZones per../../systems/gd-defense-zones.md.Province->Crownwhen at least two Provinces under the Realm have ProvinceCapitals. The Crown rank introduces Fronts per../../systems/gd-fronts.md.
Capability gates are declared against Realm.PolityRank:
- DefenseZones unlock at
Realm.PolityRank >= Province. - Fronts unlock at
Realm.PolityRank == Crown. - The FrontCandidate scope committed in
./ad-0008walks to Realm (or, equivalently, to Crown — they refer to the same scope row whenPolityRank == Crown).
The Stage-vocabulary overload is acknowledged as a follow-up rename
concern but is NOT executed in this ADR. Per the no-fallback
redesign-propagation rule and the file-rename stop in
.claude/rules/orchestrator-mode.md, a rename of Settlement.Stage
or of the Act-progression "stage" wording requires a separate
deliberate migration prompt naming exact source and destination
paths. This ADR commits the orthogonality decision and flags the
rename as a follow-up; it does not perform the rename.
Alternatives Considered
Reuse Settlement.Stage as the polity-rank carrier (promote the
first Settlement's Stage to the Realm's PolityRank). Rejected because
the cardinality is wrong: many Settlements exist, but the Realm is a
singleton. Trying to read PolityRank from "the Realm's first
Settlement's Stage" overloads the Settlement Stage field with two
unrelated meanings (population size and polity authority), creates a
silent dependency on which Settlement was founded first, and produces
a Realm rank that drops when that first Settlement is destroyed — none
of which matches the design intent. The AAA precedent (CK3 / EU4 /
Vic3) explicitly separates polity tier from holding development.
Tag-based polity rank on a player-polity entity (e.g.,
Tag(Realm.Rank=Crown) applied to a shared entity). Rejected because
tags are bind-time predicates, not typed primitives. There is no
transition history, no hysteresis support for ladder-down events, and
no place to attach Realm-scale per-tick state. The same arguments that
rule out tag-set as the Quest Thread carrier in
./ad-0007
apply here.
Tenets Applied
- "Research before designing." The AAA precedent (CK3 Title tier vs Holding development; EU4 / EU5 Country tier vs province development; Victoria 3 country type vs state buildings) was consulted before committing the orthogonality decision.
- "Future-proofed solutions only." A singleton Realm scope with a typed PolityRank channel leaves room for later authored Realm-scale channels (e.g., Realm-wide reclamation pressure, Crown-scale supply ratings, Front aggregate severity) without reshape.
- "No backwards compatibility." Neither the reuse-Settlement-Stage fallback nor the tag-based fallback is preserved. The Realm scope is the polity-rank carrier, full stop.
- "Templates are data." Realm.PolityRank is per-instance scope state; PolityRank ladder triggers are authored as channel sources / modifiers / systems against the Realm scope, not as hidden host code.
Runtime Backing Status
Status at this ADR's acceptance time: contract-only.
- Host/runtime owner: a new
legacy/v1/examples/valenar/Host/Data/RealmData.cscarries the singleton Realm host data; a newlegacy/v1/examples/valenar/Host/Systems/RealmRankSystem.csreads the ladder predicates and drives PolityRank transitions. Both are authored in the Wave 5a runtime-backing wave. - Generated/.secs owner:
legacy/v1/examples/valenar/Content/realm/scopes.secsdeclaresscope Realm;legacy/v1/examples/valenar/Content/realm/channels.secsdeclaresPolityRankand any derived Realm-scale channels; matched by the parallel Generated stand-in tree. - Read-model/UI owner: the Crown-scale strategic map and the existing Realm-scale UI surfaces in the Valenar React client gain a Realm.PolityRank display; the per-Settlement Stage display remains unchanged.
- Tests: deferred to the Wave 5a runtime-backing wave.
- Known gaps: the exact Route-coverage predicate for the Outpost ->
BannerNetwork transition; the exact ProvinceCapital designation
ceremony / Activity that fires the BannerNetwork -> Province
transition; the exact second-Province predicate for Province ->
Crown; the on_action labels (working names
PolityRankAdvanced(newRank)andPolityRankRegressed(newRank)— promotion to committed metadata is deferred to Wave 5a). - Illegal fallback behavior: no
Settlement.Stagevalue may stand in forRealm.PolityRankeven temporarily. No tag-set may stand in for the PolityRank enum. No DefenseZone or Front authoring path may unlock withoutRealm.PolityRankreading the correct value through the 6-phase channel pipeline. - Next closure wave: Wave 5a runtime-backing wave authors the host data, the scope, the channels, the host system, the on_action transition labels, and the matching Generated stand-ins.
Glossary Propagation
The following terms MUST land in gd-glossary.md, gd-canon.md, and
README.md:
Realm(scope primitive — singleton, root of player polity).PolityRank(enum carrying the polity ladder values).Outpost(PolityRank value — distinguished in the glossary from the per-Settlement Outpost-size value where the existingSettlement.Stageladder names the smallest rung).BannerNetwork(PolityRank value).Province(PolityRank value — distinguished in the glossary from the existing geographic Province scope; both terms remain committed and the glossary must call out the dual meaning).Crown(PolityRank value).
Consequences
For
../../systems/gd-realm-ranks-and-polity.md,
the doc gains a follow-up authoring obligation in Wave 3a: extend the
existing ladder section with the PolityRank enum, the four ladder
transition predicates (Outpost -> BannerNetwork etc.), and the
capability-gate section (DefenseZones at Province, Fronts at Crown).
This ADR does not edit that doc.
For
../../systems/gd-defense-zones.md
and
../../systems/gd-fronts.md, the unlock
phrasing "becomes available at Act 5 / Act 6" gains a runtime-backed
form: the unlock is gated by Realm.PolityRank >= Province and
Realm.PolityRank == Crown respectively. The Act-progression form
remains in those docs as the design-pacing description; the
runtime-backing form is the PolityRank gate. Both forms must agree.
For the Stage-vocabulary overload: a follow-up rename wave is required
to disambiguate Settlement.Stage (population size) from the
Act-progression "stage" wording in the
../../acts/README.md tree. This ADR flags the rename as a
necessary follow-up but does not perform it. The follow-up rename
prompt must name the exact source paths
(gd-settlements-and-outposts.md, the ../../acts/gd-act-*.md
docs, the Settlement.Stage Generated declarations, the React client
UI labels) and the exact destination wording. Until the follow-up
rename lands, Settlement.Stage remains the per-Settlement population
field and Act ladder docs continue to use "act" rather than "stage" as
the canonical ladder noun.
For the verifier, any future doc that conflates Settlement.Stage
with Realm.PolityRank, that introduces a polity-rank tag-set, or
that introduces a third polity-rank carrier shape is a layering FAIL.
Any doc that introduces a fifth PolityRank value beyond the four
committed here requires superseding this ADR.
References
./ad-0007-quest-thread-and-mission-scope-primitives.md./ad-0008-pressure-to-front-emergence-scope-state-machine.md./ad-0010-act-progression-actstate-scope.md./ad-0013-scope-state-channel-template-archetype-pattern.md../../systems/gd-realm-ranks-and-polity.md../../systems/gd-fronts.md../../systems/gd-defense-zones.md.claude/rules/secs-concepts.md.claude/rules/orchestrator-mode.md § Source freshness and no-fallback redesign propagation.claude/rules/valenar-contract-backing.md