Skip to main content

Valenar - Feature Generation Contract

This document is the authoritative contract for generating, revealing, and using Features inside Valenar Territories.

Status: authoritative contract with a current runtime implementation for the prototype map. Valenar derives deterministic TerritoryFacts, evaluates Feature.EvaluatePlacement(Territory, FeaturePlacementInput) through generated typed profile/query data, applies budgets/spacing/conflicts, and spawns selected Feature entities through generated templates. Future compiler work is to emit the current hand-written Generated/ shape directly from .secs.

The runtime implementation evaluates the multiplicative `score = hardGate

  • suitability * rarityModifier * seededNoise * spacingPenalty * storyBiasformula authored in this doc. Static factors (hardGate, suitability, seededNoise) are computed byFeaturePlacementQuery.Evaluate; dynamic factors (rarityModifier = clamp(1 - used/budget, 0, 1), spacingPenalty = clamp(distance / minSpacing, 0, 1)) are applied by FeaturePlacementSelectorat selection time.FeatureFamilycovers all 14 families listed below; seven of those families (Water, Food, Forest, Travel, Shelter, Corruption, Nexus) have no committed templates yet.AvoidanceWeightswas folded intoSuitabilityWeightsas negated entries; the avoidance dictionary is no longer a separate profile field.MinScore thresholds and per-template budget values remain open for a future balance-pass wave (see [../implementation/pr-code-sync-audit.md` "Feature placement balance pass"](/secs/valenar/implementation/pr-code-sync-audit/)).

storyBias is deferred. The current runtime implementation must throw an explicit `NotImplementedException("StoryBias requires labor signals (gd-labor-and-capacity.md), pressure signals (gd-corruption- reclamation.md), ActState (ad-0010), and Quest Thread lane state (ad-0007) — deferred to Wave 5a (parallel with ad-0008 labor + pressure

  • storyBias formula authoring).")against the placement formula. The historical constant-1.0 stub is the canonical silent-fallback violation per.claude/rules/valenar-contract-backing.md` gate item 4 and is to be removed in Wave 5a — see "storyBias Runtime Contract" below for the closure spec.

Scope

This contract covers:

  • Feature families.
  • Feature record shape.
  • Existence versus discovery.
  • Placement formulas.
  • Density, rarity, spacing, and budgets.
  • Compatibility and exclusion rules.
  • Starting Nexus exception.
  • Gates, taint, and threat-linked Features.
  • Activity generation.
  • Causal rewards.
  • Site conversion.
  • UX query contract.
  • Validation.

It does not define:

  • final numeric balance
  • individual story scripts
  • MC combat resolution
  • final art or icon treatment
  • district development internals after a Feature becomes a developed Site

Core Rule

Feature existence is generated world state. Discovery state controls what the player sees.

A Territory can contain several Features, but most Territories should contain no explicit notable Feature. Do not model a Territory as "one thing". The Territory is the land unit; Features are notable contents, signs, or facts inside it.

Sites are first-class places inside the Territory once content becomes discovered, enterable, exploitable, or developed. Threat is danger, pressure, or hostile presence attached to a Territory, Feature, or Site; it is not a second place ontology.

Territory facts
-> Feature template eligibility
-> suitability score
-> regional budget
-> spacing and conflict resolution
-> Feature entity
-> discovery state
-> activities and effects

Inputs

Feature generation consumes:

worldSeed
worldDataContentHash
Territory records
derived Territory classes and tags
pressure fields
route and topology facts
settlement/start constraints
Feature template registry
regional density budgets
story placement rules

The generator must use real Territory facts. It must not place Features by independent flat chance per Territory.

Outputs

Feature generation outputs Feature records:

Feature
featureId
templateId
territoryId
category
placementReasonTags
generatedStrength
quality
discoveryState
handledState
progress
risk
blockers
available interactions
effectIds
siteConversionState

Names and labels can vary by discovery state:

Hidden:
no label

Hinted:
damp reeds

Discovered:
spring

Surveyed:
clean spring, reliable water

Developed:
secured spring site

Feature Families

Feature families and the surrounding category vocabulary are NOT tags in the valenar:tag/<name> sense. The tag layer and its modifier-vs-structural-predicate split, including how tags relate to Feature categories, are documented in ../systems/gd-tags-and-classification.md; the committed tag list lives in ../catalogs/gd-tag-catalog.md.

These are generation families for Feature records, not separate player-facing place ontologies. A hostile or pressure-bearing record can stay a Feature sign, or later feed a Threat Site or a Site with linked threats.

Feature families:

NaturalResource
Water
Food
Forest
Mineral
Travel
Shelter
Ruin
Threat
Corruption
Landmark
Nexus
SettlementOpportunity
Story

Examples:

NaturalResource:
WildGrainPatch, HerbMeadow, GrazingGround

Water:
HiddenSpring, SeasonalStream, ShallowPond, ReedPool

Forest:
ForestStand, OldGrowthGrove, GameTrail, HiddenCopse

Mineral:
OreVein, QuarryFace, ClayBank, CollapsedMine

Travel:
RoadTrace, Ford, OldBridge, CaravanCamp, MountainPass

Ruin:
RuinedMill, StandingStones, FallenWatchtower, ArchiveRuin

Threat:
BanditCamp, AmbushSite, PredatorTrail, DemonNest

Corruption:
BlackAshPatch, BlightedField, MinorFissure, TaintedRunoff

Nexus:
DormantNexus, DamagedWardheart, LeylineAnchor

Corruption family lore link: (See lore exposure: lh-game1-world-hooks.md — Gate scarring/taint fields row)

Nexus family lore link: (See lore exposure: lh-game1-world-hooks.md — Nexus manifestation row, Damaged Nexus row)

Feature Template Shape

Every Feature template should define:

id
family
rarity
minSpacing
maxPerTerritory
maxPerProvince
maxPerArea
maxPerRegion
hardRequirements
suitabilityWeights
conflictTags
synergyTags
discoveryDifficulty
surveyDifficulty
interactionDifficulty
defaultDiscoveryState
possibleStates
available interactions
effects
modifiers
rewards
siteConversion

Template data answers:

  • where the Feature can exist
  • how rare it is
  • what it conflicts with
  • what it synergizes with
  • how it is discovered
  • which activities it creates
  • which scopes it can affect
  • whether it can become a Site

Existence Versus Discovery

The full ladder of state labels — FeatureDiscoveryState enum values plus their target intensity ranges — is documented in ../systems/gd-state-axes-and-thresholds.md under "Feature Discovery Axis". This section introduces the ladder informally; the state-axes doc is the normative reference for label ordering and intensity thresholds.

Existence is not knowledge.

exists:
the Feature entity is present in world state

hinted:
the player has a clue, but not the real identity

discovered:
the player knows the Feature category or name

surveyed:
quality, risk, blockers, and main outputs are known

handled:
threat or obstacle is resolved, but site may not be developed

developed:
owned or used as an ongoing Site/improvement

A dungeon, ruin interior, or resource node can begin in this ladder as a clue, Feature, or threat sign. Once it becomes enterable, exploitable, or developed, it should convert to a Site entry.

The Territory UI must not show nonexistent Features. It must not show hidden Features as known rows. It may show clues when discovery state permits.

Placement Formula

Use score-and-budget placement:

score(territory, template) =
hardGate(territory, template)
* suitability(territory, template)
* rarityModifier(template)
* seededNoise(worldSeed, territoryId, templateId)
* spacingPenalty(territory, template)
* storyBias(territory, template)

Where:

hardGate:
0 or 1. Required conditions must pass.

suitability:
weighted match between Territory facts and template preferences.

rarityModifier:
global, regional, family, and template budget pressure.

seededNoise:
deterministic variation without losing coherence.

spacingPenalty:
prevents unnatural clusters.

storyBias:
DEFERRED. The closed formula reads labor signals
(gd-labor-and-capacity.md), pressure signals
(gd-corruption-reclamation.md), ActState (ad-0010), Quest Thread
lane state (ad-0007), and starting-Nexus distance. The current
runtime must throw NotImplementedException against the placement
formula until Wave 5a (parallel with ad-0008 labor + pressure +
storyBias formula authoring) commits the inputs and the formula
body. See "storyBias Runtime Contract" below.

storyBias Runtime Contract

storyBias(territory, template) is the multiplicative bias factor in the placement formula that encourages or suppresses Feature placement based on narrative state. The closed contract is:

Committed inputs. The future storyBias formula reads from five input families:

  • Labor signals from ../systems/gd-labor-and-capacity.md: LaborShortageSignal, CriticalShortageSignal, and Province-level ProvinceLaborShortage. A Province raising sustained shortage may suppress placement of high-throughput Features (rich ore veins, complex craft sites) whose discovery would compound the labor gap, and may encourage placement of relief-oriented Features (refugee groves, abandoned-camp salvage sites).
  • Pressure signals from ../systems/gd-corruption-reclamation.md: Province-level ProvinceThreatPressure, ProvinceWardIntegrity, ProvinceRouteSafety. High pressure regions bias toward threat- linked Features (gate scarring, taint clusters) and away from pristine-landscape Features.
  • ActState (the current Act) per ../lore/adr/ad-0010-act-progression-actstate-scope.md. Act 0 / Act 1 placement biases toward starting-survival resources near the starting Nexus; Act 4+ placement opens up to Banner- Network-scale narrative geography (ancient roads, leyline anchors).
  • Quest Thread lane state per ../lore/adr/ad-0007-quest-thread-and-mission-scope-primitives.md. Active Quest Threads bias placement toward Features that surface thread-aligned hooks (a thread on Crownrot favors gate-scarring Features; a thread on ward-line restoration favors ward-anchor sites).
  • Starting-Nexus distance. A boost factor for Features anchored at or near the starting Nexus (initial Wardheart, first-Outpost candidate Territories, leyline-anchor sites required for early- game survival).

Output range. The storyBias output is a multiplicative factor in [0, k] where k = Config.Generation.StoryBiasMaxFactor is a world-size-parameterized configuration field (Discipline 14 — numeric thresholds become UI-exposed Config fields with world-size- parameterized defaults, not hardcoded constants). A storyBias of 0 suppresses placement entirely (the formula collapses to zero); a storyBias of 1 leaves the score unchanged; values above 1 amplify narrative-favored placement up to the configured ceiling.

Current behavior. The closed runtime is throw new NotImplementedException("StoryBias requires labor signals (gd-labor-and-capacity.md), pressure signals (gd-corruption-reclamation.md), ActState (ad-0010), and Quest Thread lane state (ad-0007) — deferred to Wave 5a (parallel with ad-0008 labor + pressure + storyBias formula authoring)."). The historical => 1.0 constant in legacy/v1/examples/valenar/Generated/Territories/FeaturePlacement/FeaturePlacementQuery.cs line 190 is the canonical silent-fallback violation per .claude/rules/valenar-contract-backing.md gate item 4 and is replaced in Wave 5a.

Next closure wave. Wave 5a (parallel with ad-0008 labor + pressure runtime backing per resolver R17). The wave authors the five input families on their owner docs simultaneously (P1 labor channels, P2 pressure channels, ad-0010 ActState scope binding, ad-0007 Quest Thread lane state) and lands the storyBias formula body that consumes them. Until Wave 5a completes, any placement run that requires storyBias must fail loud rather than silently default to 1.0.

Runtime Backing Status

Status at this section's acceptance time: deferred (closure plan committed; runtime backing pending).

  • Host/runtime owner: legacy/v1/examples/valenar/Generated/Territories/FeaturePlacement/FeaturePlacementQuery.cs line 190 (ComputeStoryBias) is the closure site; the formula replaces the constant return with reads against the five input families. Config.Generation.StoryBiasMaxFactor is the new UI- exposed config field authored alongside.
  • Generated/.secs owner: storyBias has no committed source-keyword shape; the formula lives as a C# method on FeaturePlacementQuery. The labor and pressure channels storyBias reads are authored under the P1 and P2 owner docs' Wave 5a closure.
  • Read-model/UI owner: not applicable directly; storyBias surfaces only through Feature placement outcomes.
  • Tests: deferred to Wave 5a alongside the formula body authoring.
  • Known gaps: the formula body (how the five input families weight against each other); the per-feature-family bias coefficients; the StoryBiasMaxFactor world-size defaults table.
  • Illegal fallback behavior: returning a constant value, returning 1.0, returning a placeholder, or silently coercing missing inputs to neutral defaults is forbidden. Any storyBias evaluation that cannot read its committed inputs must throw NotImplementedException with the canonical message above. The constant-1.0 stub is the canonical silent-fallback the closure removes.
  • Next closure wave: Wave 5a (parallel with ad-0008 labor + pressure
    • storyBias formula authoring per resolver R17).

AAA Precedent for storyBias

The storyBias primitive draws on three AAA references:

  • RimWorld Storyteller (primary) — Cassandra Classic, Phoebe Chillax, and Randy Random read colony state and bias the event selector toward story-shaped challenges. RimWorld's Storyteller is the closest realization of "named bias term reading world state to shape placement / event flow" — the term story bias in the formula here is the same semantic noun as RimWorld's Storyteller output multiplier.
  • Civ VI map-script bias tables (secondary) — Civ VI's worldgen scripts carry per-resource and per-feature bias tables read at placement time. The bias row matches the SECS storyBias multiplicative factor: a positive bias amplifies placement, a negative bias suppresses it, and the bias is read from world state (continent type, latitude, adjacent features).
  • CK3 Legend system (tertiary) — Crusader Kings 3's Legend feature biases narrative event chains by reading character / dynasty / region state. CK3 Legends are the closest realization of "narrative-state-driven bias on emergent content" outside the worldgen-placement context.

TerritoryFacts and IsWater

The TerritoryFacts consumed by FeaturePlacementQuery.Evaluate include the IsWater field, wired through the host data layer:

  • Host-side declaration at legacy/v1/examples/valenar/Host/Data/TerritoryData.cs line 16 (public int IsWater { get; set; }).
  • HostBridge read/write/snapshot paths at legacy/v1/examples/valenar/Host/Bridge/HostBridge.cs lines 459, 774, and 1237.
  • Generated hash entry at legacy/v1/examples/valenar/Generated/Hashes.cs line 41 (H.IsWater).
  • FeaturePlacementTypes.cs lines 109-112 declare the R-4 wiring that flows IsWater into the placement profile.

IsWater reports 1 for water Territories and 0 for land Territories. It is consumed by the hard-gate suitability layer: water Features (springs, lake-anchored sites) require IsWater = 1 for hardGate to evaluate to 1; land Features require IsWater = 0. The field is implemented; no closure wave is needed.

Runtime Backing Status (IsWater)

Status at this section's acceptance time: implemented.

  • Host/runtime owner: legacy/v1/examples/valenar/Host/Data/TerritoryData.cs line 16.
  • Generated/.secs owner: legacy/v1/examples/valenar/Generated/Hashes.cs line 41 carries H.IsWater; the .secs source authoring side lives under legacy/v1/examples/valenar/Content/territories/.
  • Read-model/UI owner: the per-Territory dossier and Feature placement UI both read IsWater.
  • Tests: covered by existing world-import validation tests in ValenarWorldValidator.
  • Known gaps: none.
  • Illegal fallback behavior: no inference of IsWater from biome string or polygon adjacency; the host field is the source of truth.
  • Next closure wave: not applicable; field is shipped.

Candidate selection:

for each region:
for each Feature family:
apply family density budget
for each template in family:
collect eligible candidates
score candidates
sort by score descending
select candidates while budget remains
enforce min spacing
enforce max Features per Territory
enforce conflict rules
record placement reason tags

Do not do this:

for each Territory:
roll 5 percent chance for hidden dungeon clue
roll 5 percent chance for ore
roll 5 percent chance for spring

Independent rolls create incoherent worlds at large scale.

Density And Capacity

Most Territories have zero explicit Features.

Suggested capacity:

ordinary Territory: 0 Features
mildly interesting Territory: 1 Feature
rich, dangerous, strategic Territory: 2 Features
rare landmark Territory: 3 Features
story Territory: 4 Features by override

Capacity formula:

capacityScore =
max(resourceRichness, threat, ancientness, routeImportance, settlementSuitability)
+ landmarkBias
+ seededNoise

Budget layers:

global budget:
maximum count across the whole world

region budget:
keeps macro distribution readable

area budget:
prevents one area from absorbing every rare Feature

province budget:
keeps local play varied

Territory capacity:
prevents clutter inside one Territory

Compatibility And Exclusion

Conflict examples:

DormantNexus conflicts with duplicate Nexus/Wardheart anchor placement
PristineSpring conflicts with SevereTaintSource unless explicitly corrupted
OpenMarketCrossroads conflicts with DeepWildernessOnly
LargeMineSite requires enough orePotential and terrain support
DenseForestFeature requires enough forestCoverage

Synergy examples:

AncientRoadSegment increases chance of RuinedWatchtower nearby.
RiverMeadow increases chance of GoodFarmland and OldMill.
DemonGate increases chance of DemonTracks, BlightedField, and RefugeeCamp nearby.
OreBearingUpland increases chance of OreVein and CollapsedMine.
ForestEdge increases chance of GameTrail, HiddenCopse, and AmbushGrass.

DemonGate synergy lore link: (See lore exposure: lh-game1-world-hooks.md — Demon gates row, gate scarring/taint fields row)

Synergy must be budgeted and deterministic. It must not create unbounded chains.

Starting Nexus Exception

The starting Nexus is a constrained story Feature, not ordinary random ruin placement.

Rules:

starting Territory must contain a dormant or damaged Nexus Feature
starting Nexus starts hidden, dormant, damaged, buried, or unidentified
starting Nexus is revealed through the starting ruin chain
only the starting ruin chain has this guarantee
not every ruin is a Nexus
generic site suitability never unlocks founding by itself

Correct founding path:

find ruin clue
investigate ruin
identify dormant Nexus / Wardheart
stabilize Nexus
unlock Establish the Core
establish the Core once
remove founding activity forever

Gates, Taint, And Pressure Features

Some Features are pressure sources, not rewards.

The pressure itself is the Threat. The Feature record is the sign, hazard source, or partial place information carrying that Threat until a full Site exists.

Examples:

MinorFissure
LesserGate
DemonGate
BlackAshPatch
BlightedField
DemonTracks
CorruptedLeylineTrace

Pressure Features can:

  • spread taint
  • increase threat
  • lower route safety
  • block rest
  • block claim or designation
  • make local activities risky
  • spawn nearby clues
  • escalate if ignored
  • unlock cleansing, assault, containment, or sealing activities

Gate and taint Features must align with World Pressure and Nexus.

Feature State

Recommended state ladder:

Hidden
Hinted
Discovered
Surveyed
Handled
Secured
Developed
Depleted
Destroyed

Not every Feature uses every state. The contract requires enough states to support mystery, partial knowledge, local activity, cleanup, ownership, and development.

Site-facing wording, once a Feature converts, should use explicit place states: wild, discovered, secured, active, owned, developed, depleted, sealed, destroyed.

Quest Hooks from Feature Transitions

Feature state changes are a primary input to the dynamic quest pressure system. The mapping of specific transitions to quest artifacts (clues, objective updates, mission candidates, urgency escalations) is owned by ../systems/gd-dynamic-quest-pressure-model.md under "Feature-Transition Trigger Table". This contract defines what features can transition into; the generator contract defines what those transitions cause for the planning layer.

Activity Generation

Activities are generated from Feature state plus broader state:

availableActivity(feature, actor, territory) =
feature exists
required Feature state passes
Territory knowledge state passes
actor is present or has valid remote access
required tools/resources/act pass
threat blockers pass or the activity handles the threat
route/control requirements pass

Activity families:

Survey
Investigate
Clear
Secure
Harvest
Excavate
Consecrate
Cleanse
Build Outpost
Develop Site
Study
Patrol
Seal
Exploit
Establish the Core

If the MC is not at the Territory, local activities require travel or must state why they are unavailable.

Causal Rewards

Feature rewards must come from Feature identity.

Good examples:

RuinedMill:
tools, blueprint, local workshop unlock, restored production site

AncientForgeRuin:
forge upgrade, metalworking recipe, Forge Core clue

CollapsedMine:
ore vein reveal, mining site, stone or metal salvage

WardRuin:
shield knowledge, ward repair project, taint suppression, Nexus clue

ArchiveRuin:
map fragment, lore, research topic, quest chain

DemonFissure:
shard, taint reduction, gate warning, danger escalation if ignored

Bad pattern:

completed Feature -> random global production bonus

Do not replace Feature identity with generic pseudo-channels such as Research Bonus, Morale Bonus, Mineral Bonus, or Defense Bonus.

Prefer explicit feature-local values or explicit target modifiers instead. Examples only: DiscoveryDifficulty, SurveyDifficulty, InteractionDifficulty, Progress, ThreatLevel, LootValue, or named causal effects on the actually affected scope.

Effects And Modifiers

Apply effects to the scope that is actually affected.

Examples:

WildGrainPatch discovered:
reveals food potential and forage activity

WildGrainPatch secured:
adds local FoodOutput or FarmingSuitability modifier

OreVein surveyed:
reveals ore quality and mining activity

OreVein developed:
adds MetalOutput to owning Territory, outpost, district, or settlement
through the proper scope

DemonNest active:
increases ThreatLevel
lowers RouteSafety and RestSafety
blocks safe work

DemonNest handled:
removes local threat modifier
may reveal salvage, shard, route safety, or taint source information

Use Territory-scoped modifiers first. Promote effects to settlement, province, or region only when ownership, route connection, designation, site development, or story state justifies it.

Site Conversion

Sites and buildings are first-class place content. They are not the same category as generated wild Features, even when a Feature is the discovery path that leads to them.

Resource nodes, ruins, and dungeon leads can begin as Features and convert into Sites when they become enterable, exploitable, defensible, or developed. Threat-heavy places follow the same rule: they become Threat Sites or Sites with linked threats once the place itself is part of play.

Examples:

HiddenSpring -> WaterSite
OreVein -> MineSite
RuinedMill -> RestoredWorkshopSite
WardRuin -> WardSite
DemonFissure -> SealedRiftSite or CleansingSite

Conversion requirements can include:

  • discovery state
  • survey result
  • threat cleared
  • ownership or outpost access
  • workers
  • resources
  • route connection
  • act unlock
  • designation compatibility

Plains Feature Examples

Plains are about food, grazing, visibility, roads, exposure, old travel routes, and pressure.

Possible plains Features:

Food/resource:
WildGrainPatch
GrazingHerd
GoodFarmland
ForagingGround
HerbMeadow

Water:
SeasonalStream
ShallowPond
ReedPool
HiddenSpring

Travel:
RoadTrace
CaravanCamp
MarketCrossroads
OldBoundaryStones

Shelter/defense:
LoneHill
WindbreakCopse
EarthenRise
ExposedApproach

Threat:
AmbushGrass
PredatorTrail
BanditCamp
DemonTracks
BlightedField

History:
StandingStones
BattlefieldRemnant
BuriedRuins
AncientRoadSegment
FallenWatchtower
SealedBarrow

Example WildGrainPatch:

eligible if:
plainsCoverage >= 35
fertility >= 55
corruption <= 50

score =
plainsCoverage * 0.30
+ fertility * 0.45
+ moisture * 0.15
- forestCoverage * 0.10
- corruption * 0.25
+ noise * 0.10

Example RoadTrace:

eligible if:
slopeAvg <= 35
tinyWaterCoverage <= 35
routeImportance >= 40

score =
routeImportance * 0.45
+ plainsCoverage * 0.20
+ roadSuitability * 0.25
- wetlandCoverage * 0.20
- roughness * 0.15
+ noise * 0.10

Example DemonTracks:

eligible if:
demonPressure >= 35
knowledgeState >= Sighted

score =
demonPressure * 0.45
+ corruption * 0.25
+ visibility * 0.10
+ routeImportance * 0.10
+ noise * 0.10

Other Terrain Examples

Deep Forest:

high forestCoverage
medium cover
lower visibility
possible Features:
ForestStand
GameTrail
HiddenCopse
OldShrine
AmbushSigns
WitchPath

Rocky Upland:

high slope and rockyCoverage
lower fertility
higher defensibility
possible Features:
OreVein
QuarryFace
CollapsedMine
WatchHill
CaveMouth
FallenTower

Wet Meadow:

high moisture and fertility
moderate tinyWaterCoverage or water adjacency
possible Features:
SeasonalStream
ReedPool
GoodFarmland
OldMillRace
SoftGround
TaintedRunoff

Blighted Field:

high corruption or corruptedCoverage
lower rest safety
possible Features:
BlackAshPatch
DemonTracks
BlightedCrop
MinorFissure
DeadGrove
CleansingSite

Land-Coastal:

land Territory adjacent to water Territory
possible Features:
FishingCamp
LandingBeach
CliffPath
OldPier
SmugglerCove
StormWreck

Water-Coast or Water-Inland-Lake:

water Territory, not settlement land by default
possible Features:
FishingGround
ShallowReef
FerryRoute
LakeIsland
SunkenRuin
DangerousCurrent

UX Query Contract

The Territory UI consumes generated Feature state.

Rules:

  • Do not show nonexistent Features.
  • Do not show hidden Features as known rows.
  • Show hints only when discovery state permits.
  • Group activities by source: Territory, Feature, Approach, Threat, Site.
  • Use site-first wording for enterable, exploitable, or developable places.
  • Dungeons surface through Site entries once discovered or enterable; before then only clues, Features, or threat signs show.
  • Feature panels open inside the Territory workspace.
  • Feature detail panels show status, known facts, unknowns, progress, risks, blockers, available activities, possible outcomes, and effects on Territory.

Validation

Feature validation must check:

every Feature has a valid Territory
every Feature template id exists
every selected Feature passes hard requirements
Feature count does not exceed Territory capacity
rare Features respect spacing
family and regional budgets hold
incompatible Features do not coexist
synergy placements are deterministic and bounded
story-required Features exist
starting Nexus Feature exists
no visible Feature is Hidden
no activity references a missing Feature, Site, or Territory
all modifiers target valid scopes
all rewards are causal to Feature identity

Feature-validation predicates above are registered as named ValidationPredicate rows into the shared ValidationRegistry defined by gd-generation-validation.md; a failed predicate produces a ValidationViolation carried by ValidationReport and fails world load loudly rather than silently degrading. The fail-loud contract is the host-runtime expression of gate item 4 of .claude/rules/valenar-contract-backing.md.

Runtime Migration Direction

Required direction:

1. Extend FeatureData beyond binary discovered/cleared/hostile state.
2. Replace random Feature sprinkling with score-and-budget placement.
3. Store placement reason tags and generated strength/quality.
4. Generate discovery state from Territory knowledge and Feature difficulty.
5. Wire OnDiscovered, OnInteract, OnCleared, and later state transitions.
6. Replace hard-coded Act 0 feature rows with snapshot-backed Features and
hints.
7. Enforce Nexus-gated founding through runtime state.

The current templates for ruins, dungeon-linked clues and sites, ore veins, shrines, groves, and similar world content remain useful as content seeds, but their placement and lifecycle must be driven by this contract.