feat(simulation): grassland biome-awareness + alien-ecology vocab (T-1085 workstream 4, D-246)
The mosaic palette gains a climate-biome dimension for the Grassland surface-class: savanna / temperate / boreal / tundra now read distinctly rather than collapsing to one biome-blind palette (the D-246 biome-awareness fix). - atlas/mosaic.rs: ClimateBiome (from temperature_c + moisture_q) + four biome-keyed Grassland palettes; palette(class, biome). Savanna carries scattered Forest copses, tundra carries lichen + sparse bare ground and no forest. §8-safe (veg + water only). - atlas/voxel.rs: derive the biome; a cold barren district (tundra/boreal) now takes the sparse mosaic rather than staying blank — worlds that read "0 vegetated / blank" now read structured-sparse (D-245 climate-appropriateness). vegetated_districts 8→20 and 0→39 on the cold validation bodies. - data/mosaic_constants.toml: biome-keyed grassland mirror. - docs/design/alien-ecology-vocabulary.md: Miri's full biome × register naming layer (the cane/vane/wrack/husk/drum-root native lexicon + Earth-register names) — the derived-label source for the palette and Phase-5 rendering. Believability golden regenerated. Full server suite green. Forest biomes and the introduced-Earth register are the noted continuation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -205,3 +205,86 @@ Chirality decisions resolved (2026-07-02, with Jeroen):
|
||||
NAMING CONFIRMED: Keid''s habitable body Cadwal → Linnaeus (the great classifier; ties to Solander/Solandar taxonomy + the ''five kingdoms''). Capital stays Vance.', NULL, '2026-07-02 21:24:12', '2026-07-02 21:24:12.734', '2026-07-02 21:24:12.734', NULL, 'b13c9f1ce1d47437fdb599e6efce7f0e', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91R8RV38BJXGB2V55FP3B8', 'status', 'backlog', 'in_progress', NULL, '2026-07-03 20:18:52', '2026-07-03 20:18:52.241', '2026-07-03 20:18:52.241', NULL, '89aa6692b3a1ab821cb7b02c3970f5a5', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91R8RV38BJXGB2V55FP3B8', 'status', 'in_progress', 'in_progress', NULL, '2026-07-03 20:20:01', '2026-07-03 20:20:01.466', '2026-07-03 20:20:01.466', NULL, '6d2a3d77d702940bbc9207e4b9ce2b26', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91R8RV38BJXGB2V55FP3B8', 'description', 'Operationalize the D-247 native-biosphere premise. Full brief appended.
|
||||
|
||||
---
|
||||
BRIEF (2026-07-02) — governing record: D-247 (governance/decisions/content.md); consumer: D-246 / T-1084 mosaic register.
|
||||
|
||||
WHAT THIS IS
|
||||
D-247 established that habitable Reach worlds were alive before humans (the settlement timeline forbids terraforming from dead rock), and that an AUTHORED per-world chirality bit gates whether native life is edible. This ticket turns that canon into data + reconciled wiki + the vocabulary the mosaic needs. Owner: Miri (worldbuilding/continuity). Stakeholder: Burnelli (food-import economics). Co-maintainer for the vocab: Araminta (visual grammar, per the T-995 ObjectTag precedent).
|
||||
|
||||
THE MODEL (locked in D-247 — do not re-litigate, apply it):
|
||||
- `biosphere_class ∈ {NativeCompatible, NativeMirror, TerraformedSterile, Airless}`. It is an AUTHORED INPUT, never seed-derived — it follows a world''s economic/cultural identity.
|
||||
- Compatible ("levo") = edible; coupling *permits* an authored hazard but does not force it (most are benign gardens).
|
||||
- Mirror ("dextro") = inedible but *guaranteed* inert (can''t infect/poison — safe to study).
|
||||
- "Safe" ≠ "edible" — decoupled. Bio-safe is guaranteed on Mirror; food-safe is Compatible-only.
|
||||
- Achiral seam (always works either way): breathe air, drink water, mine ore, burn/build with native biomass. Only eat/metabolize/medicate/infect/chirally-poison are gated.
|
||||
- ~50/50 Compatible:Mirror is a DESIGN TARGET across canon-silent worlds, not a per-world draw.
|
||||
|
||||
WORKSTREAMS
|
||||
1. CHIRALITY ASSIGNMENT (Miri). Give every inhabited body a biosphere_class by authored identity: principled default from `economic_base_primary` + `planet_class` (food/drink exporters → Compatible; dead+maintained-atmosphere → TerraformedSterile), explicit overrides where canon speaks. Locked exemplars: Arbour (GJ-338B)=Compatible; Solandar (GJ-827)=Mirror; Keid (GJ-166A)=Compatible (preserved *from exploitation* of edible alien life — the stronger conservation motive; Solandar is the Mirror-inert preserve); Oshima (GJ-79)=TerraformedSterile. Hit the ~50/50 target across the silent remainder.
|
||||
2. WIKI CONTINUITY (Miri). Reconcile the entries that already gesture at native biochemistry so each is consistent with its assigned bit + the mechanism: GJ-827, GJ-524, GJ-166A, GJ-684A, GJ-197, GJ-79, GJ-124 (resolve whether Hạ Long''s "protein" is native-Compatible harvest or Earth aquaculture). Additive/explanatory, not contradictory — preserve deliberately-vague lines as intentional.
|
||||
3. biosphere_class AUTHORING PATH (asset-pipeline discipline — schema + source + values together, per .claude/rules/asset-pipeline.md). Add `biosphere_class` to wiki body frontmatter (where `substrate:` already lives), a nullable `bodies.biosphere_class` column in systems-schema.sql + MIGRATION_SQL, and importer read. NOT needed for D-246; lands with this pass.
|
||||
4. ALIEN-ECOLOGY VOCABULARY (Miri + Araminta) — feeds T-1084 directly. The mosaic palette is keyed on surface-class × climate-biome × biosphere-register (D-246 Palette-key). Provide the micro-habitat NAMES per biome × register: native-mirror niches get *alien* clade names (Solandar''s "five kingdoms" flavor); introduced-Earth niches get Earth names (wheatfield, orchard, pasture). Fill the fixed niche spine (canopy / understory / wet-hollow / pioneer / bare) per climate-biome (savanna gallery-copse, tundra thermokarst / lichen-heath, boreal muskeg / deadfall, …). DETERMINISM: the vocab must be fixed before T-1084 generates its first world (a later addition re-rolls affected voxels). Table size is not a perf/storage concern — author generously but to taste (~100k is headroom, not a target).
|
||||
|
||||
BURNELLI (stakeholder, follow-on): a food-supply demand primitive keyed on biosphere_class (Mirror + frontier → import dependency; Compatible → local-food capable). Phase-2 economy consumer; does not block this ticket.
|
||||
|
||||
CONSTRAINTS
|
||||
- Authored input, not derivation (Arbour''s estate food must never be coin-flipped inedible).
|
||||
- Semantic axes stay clade-agnostic (Forest = canopy whether oak or mega-fungus); the register skins niches, it does not change gameplay semantics.
|
||||
- The mosaic geometry is chirality-blind — this work does NOT touch voxel geometry, only edibility/economy/naming/vocab.
|
||||
|
||||
Chirality decisions resolved (2026-07-02, with Jeroen):
|
||||
- Locked exemplars: Arbour=NativeCompatible, Solandar=NativeMirror, Keid=NativeCompatible, Oshima=TerraformedSterile.
|
||||
- Miri assignments accepted: GJ-524=Mirror, Freyburg(GJ-684A)=Compatible, Hạ Long(GJ-124)=Compatible (native-Compatible harvest, per her rationale).
|
||||
- USER OVERRIDES: Puerto Último(GJ-197)=NativeCompatible (breadbasket identity over Miri''s balance-motivated Mirror). Edict/Sirius(GJ-244A)=Airless — keep the world harsh/frozen (deliberately-inconvenient below-grade transit capital is load-bearing canon); no climate change; below-grade sealed habitat = no open-air biosphere.
|
||||
- Two-gate default rule ACCEPTED for canon-silent worlds: Gate 0 (habitability from atmosphere/hydrosphere frontmatter → Airless / TerraformedSterile / Alive), Gate 1 (Compatible vs Mirror from economic_base_primary; agriculture→Compatible near-lock, penal→Mirror, research→50/50 lever).
|
||||
- NAMING: Keid''s habitable body renamed Cadwal→(pending final pick; rec Linnaeus — pairs with Solander, its student naturalist; or Beagle). Capital stays ''Vance'' (already the author tribute). Miri''s IP flag (Cadwal = Vance''s exact book title) is the driver.
|
||||
- Still to APPLY: the 7 additive wiki continuity edits (Miri specified exact text), the biosphere_class frontmatter+schema+importer plumbing (workstream 3), and the Cadwal→<name> rename across wiki + the GJ166A atlas proposal.
|
||||
|
||||
NAMING CONFIRMED: Keid''s habitable body Cadwal → Linnaeus (the great classifier; ties to Solander/Solandar taxonomy + the ''five kingdoms''). Capital stays Vance.', 'Operationalize the D-247 native-biosphere premise. Full brief appended.
|
||||
|
||||
---
|
||||
BRIEF (2026-07-02) — governing record: D-247 (governance/decisions/content.md); consumer: D-246 / T-1084 mosaic register.
|
||||
|
||||
WHAT THIS IS
|
||||
D-247 established that habitable Reach worlds were alive before humans (the settlement timeline forbids terraforming from dead rock), and that an AUTHORED per-world chirality bit gates whether native life is edible. This ticket turns that canon into data + reconciled wiki + the vocabulary the mosaic needs. Owner: Miri (worldbuilding/continuity). Stakeholder: Burnelli (food-import economics). Co-maintainer for the vocab: Araminta (visual grammar, per the T-995 ObjectTag precedent).
|
||||
|
||||
THE MODEL (locked in D-247 — do not re-litigate, apply it):
|
||||
- `biosphere_class ∈ {NativeCompatible, NativeMirror, TerraformedSterile, Airless}`. It is an AUTHORED INPUT, never seed-derived — it follows a world''s economic/cultural identity.
|
||||
- Compatible ("levo") = edible; coupling *permits* an authored hazard but does not force it (most are benign gardens).
|
||||
- Mirror ("dextro") = inedible but *guaranteed* inert (can''t infect/poison — safe to study).
|
||||
- "Safe" ≠ "edible" — decoupled. Bio-safe is guaranteed on Mirror; food-safe is Compatible-only.
|
||||
- Achiral seam (always works either way): breathe air, drink water, mine ore, burn/build with native biomass. Only eat/metabolize/medicate/infect/chirally-poison are gated.
|
||||
- ~50/50 Compatible:Mirror is a DESIGN TARGET across canon-silent worlds, not a per-world draw.
|
||||
|
||||
WORKSTREAMS
|
||||
1. CHIRALITY ASSIGNMENT (Miri). Give every inhabited body a biosphere_class by authored identity: principled default from `economic_base_primary` + `planet_class` (food/drink exporters → Compatible; dead+maintained-atmosphere → TerraformedSterile), explicit overrides where canon speaks. Locked exemplars: Arbour (GJ-338B)=Compatible; Solandar (GJ-827)=Mirror; Keid (GJ-166A)=Compatible (preserved *from exploitation* of edible alien life — the stronger conservation motive; Solandar is the Mirror-inert preserve); Oshima (GJ-79)=TerraformedSterile. Hit the ~50/50 target across the silent remainder.
|
||||
2. WIKI CONTINUITY (Miri). Reconcile the entries that already gesture at native biochemistry so each is consistent with its assigned bit + the mechanism: GJ-827, GJ-524, GJ-166A, GJ-684A, GJ-197, GJ-79, GJ-124 (resolve whether Hạ Long''s "protein" is native-Compatible harvest or Earth aquaculture). Additive/explanatory, not contradictory — preserve deliberately-vague lines as intentional.
|
||||
3. biosphere_class AUTHORING PATH (asset-pipeline discipline — schema + source + values together, per .claude/rules/asset-pipeline.md). Add `biosphere_class` to wiki body frontmatter (where `substrate:` already lives), a nullable `bodies.biosphere_class` column in systems-schema.sql + MIGRATION_SQL, and importer read. NOT needed for D-246; lands with this pass.
|
||||
4. ALIEN-ECOLOGY VOCABULARY (Miri + Araminta) — feeds T-1084 directly. The mosaic palette is keyed on surface-class × climate-biome × biosphere-register (D-246 Palette-key). Provide the micro-habitat NAMES per biome × register: native-mirror niches get *alien* clade names (Solandar''s "five kingdoms" flavor); introduced-Earth niches get Earth names (wheatfield, orchard, pasture). Fill the fixed niche spine (canopy / understory / wet-hollow / pioneer / bare) per climate-biome (savanna gallery-copse, tundra thermokarst / lichen-heath, boreal muskeg / deadfall, …). DETERMINISM: the vocab must be fixed before T-1084 generates its first world (a later addition re-rolls affected voxels). Table size is not a perf/storage concern — author generously but to taste (~100k is headroom, not a target).
|
||||
|
||||
BURNELLI (stakeholder, follow-on): a food-supply demand primitive keyed on biosphere_class (Mirror + frontier → import dependency; Compatible → local-food capable). Phase-2 economy consumer; does not block this ticket.
|
||||
|
||||
CONSTRAINTS
|
||||
- Authored input, not derivation (Arbour''s estate food must never be coin-flipped inedible).
|
||||
- Semantic axes stay clade-agnostic (Forest = canopy whether oak or mega-fungus); the register skins niches, it does not change gameplay semantics.
|
||||
- The mosaic geometry is chirality-blind — this work does NOT touch voxel geometry, only edibility/economy/naming/vocab.
|
||||
|
||||
Chirality decisions resolved (2026-07-02, with Jeroen):
|
||||
- Locked exemplars: Arbour=NativeCompatible, Solandar=NativeMirror, Keid=NativeCompatible, Oshima=TerraformedSterile.
|
||||
- Miri assignments accepted: GJ-524=Mirror, Freyburg(GJ-684A)=Compatible, Hạ Long(GJ-124)=Compatible (native-Compatible harvest, per her rationale).
|
||||
- USER OVERRIDES: Puerto Último(GJ-197)=NativeCompatible (breadbasket identity over Miri''s balance-motivated Mirror). Edict/Sirius(GJ-244A)=Airless — keep the world harsh/frozen (deliberately-inconvenient below-grade transit capital is load-bearing canon); no climate change; below-grade sealed habitat = no open-air biosphere.
|
||||
- Two-gate default rule ACCEPTED for canon-silent worlds: Gate 0 (habitability from atmosphere/hydrosphere frontmatter → Airless / TerraformedSterile / Alive), Gate 1 (Compatible vs Mirror from economic_base_primary; agriculture→Compatible near-lock, penal→Mirror, research→50/50 lever).
|
||||
- NAMING: Keid''s habitable body renamed Cadwal→(pending final pick; rec Linnaeus — pairs with Solander, its student naturalist; or Beagle). Capital stays ''Vance'' (already the author tribute). Miri''s IP flag (Cadwal = Vance''s exact book title) is the driver.
|
||||
- Still to APPLY: the 7 additive wiki continuity edits (Miri specified exact text), the biosphere_class frontmatter+schema+importer plumbing (workstream 3), and the Cadwal→<name> rename across wiki + the GJ166A atlas proposal.
|
||||
|
||||
NAMING CONFIRMED: Keid''s habitable body Cadwal → Linnaeus (the great classifier; ties to Solander/Solandar taxonomy + the ''five kingdoms''). Capital stays Vance.
|
||||
|
||||
PROGRESS 2026-07-03: Workstreams 1-2 DONE + committed (388168eef, branch micro-habitat-mosaic).
|
||||
- Cadwal→Linnaeus rename applied (body frontmatter name + biosphere_class:NativeCompatible, GJ-166A infobox, atlas proposal, D-247 clarified). Capital stays Vance.
|
||||
- 5 wiki continuity edits applied (GJ-524 Mirror, GJ-166A/Keid Compatible, GJ-684A Freyburg Compatible, GJ-124 Hạ Long Compatible, GJ-197 Puerto Último Compatible). Solandar/Oshima needed none.
|
||||
REMAINING:
|
||||
- Workstream 3 (biosphere_class plumbing): add nullable bodies.biosphere_class column to systems-schema.sql; teach tooling/db/wiki_sync.py import_from_wiki to read biosphere_class frontmatter + apply the two-gate DEFAULT for canon-silent bodies (Gate0 atmosphere/hydrosphere, Gate1 economic_role/economic_base); add explicit frontmatter for the 3 override bodies still needing it (Solandar=NativeMirror, GJ-524=NativeMirror [uninhabited-but-alive → default would mis-Airless it], Edict/GJ244Ad=Airless [standard-atm+ice edge case]); ensure generate_wiki round-trips biosphere_class; then the BAKE (run import_from_wiki + generate_wiki → systems.db + regenerated infoboxes, incl. the Linnaeus name propagation) + commit systems.db. Add biosphere_class to BodyParams read set (D-240) as the D-247 code hook. NOTE: the bake is a systems.db binary-artifact commit — consequential, do deliberately.
|
||||
- Workstream 4 (alien-ecology vocab → palette): integrate Miri''s biome × register vocabulary (cane/vane/wrack/husk/drum-root native-mirror lexicon + Earth-register names, per her Deliverable 3) into atlas/mosaic.rs + mosaic_constants.toml — extends the temperate/native baseline to the full surface-class × climate-biome × register palette. This also completes T-1084''s biome-awareness. Determinism: lock before generation.
|
||||
Miri''s full Deliverable 3 vocab (the source for workstream 4) is in her T-1085 agent report.', NULL, '2026-07-03 20:40:15', '2026-07-03 20:40:15.305', '2026-07-03 20:40:15.305', NULL, 'fa34e073db0be60d59ec01ebd7a5e5f4', 2) ON CONFLICT(hash) DO NOTHING;
|
||||
|
||||
@@ -218,3 +218,49 @@ Chirality decisions resolved (2026-07-02, with Jeroen):
|
||||
- Still to APPLY: the 7 additive wiki continuity edits (Miri specified exact text), the biosphere_class frontmatter+schema+importer plumbing (workstream 3), and the Cadwal→<name> rename across wiki + the GJ166A atlas proposal.
|
||||
|
||||
NAMING CONFIRMED: Keid''s habitable body Cadwal → Linnaeus (the great classifier; ties to Solander/Solandar taxonomy + the ''five kingdoms''). Capital stays Vance.', 'in_progress', 'medium', 'miri', NULL, 'D-247', '2026-07-02 20:30:57.222', '2026-07-03 20:20:01.466', NULL, 'f7bd0e6fd21f924f65afcec9a7ed9624', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FJ91R8RV38BJXGB2V55FP3B8', 'story', '06FGSJNP8YM537DJCC82ZD6544', 'Biosphere register (D-247) — chirality bits, wiki continuity, biosphere_class authoring + alien-ecology vocab', 'Operationalize the D-247 native-biosphere premise. Full brief appended.
|
||||
|
||||
---
|
||||
BRIEF (2026-07-02) — governing record: D-247 (governance/decisions/content.md); consumer: D-246 / T-1084 mosaic register.
|
||||
|
||||
WHAT THIS IS
|
||||
D-247 established that habitable Reach worlds were alive before humans (the settlement timeline forbids terraforming from dead rock), and that an AUTHORED per-world chirality bit gates whether native life is edible. This ticket turns that canon into data + reconciled wiki + the vocabulary the mosaic needs. Owner: Miri (worldbuilding/continuity). Stakeholder: Burnelli (food-import economics). Co-maintainer for the vocab: Araminta (visual grammar, per the T-995 ObjectTag precedent).
|
||||
|
||||
THE MODEL (locked in D-247 — do not re-litigate, apply it):
|
||||
- `biosphere_class ∈ {NativeCompatible, NativeMirror, TerraformedSterile, Airless}`. It is an AUTHORED INPUT, never seed-derived — it follows a world''s economic/cultural identity.
|
||||
- Compatible ("levo") = edible; coupling *permits* an authored hazard but does not force it (most are benign gardens).
|
||||
- Mirror ("dextro") = inedible but *guaranteed* inert (can''t infect/poison — safe to study).
|
||||
- "Safe" ≠ "edible" — decoupled. Bio-safe is guaranteed on Mirror; food-safe is Compatible-only.
|
||||
- Achiral seam (always works either way): breathe air, drink water, mine ore, burn/build with native biomass. Only eat/metabolize/medicate/infect/chirally-poison are gated.
|
||||
- ~50/50 Compatible:Mirror is a DESIGN TARGET across canon-silent worlds, not a per-world draw.
|
||||
|
||||
WORKSTREAMS
|
||||
1. CHIRALITY ASSIGNMENT (Miri). Give every inhabited body a biosphere_class by authored identity: principled default from `economic_base_primary` + `planet_class` (food/drink exporters → Compatible; dead+maintained-atmosphere → TerraformedSterile), explicit overrides where canon speaks. Locked exemplars: Arbour (GJ-338B)=Compatible; Solandar (GJ-827)=Mirror; Keid (GJ-166A)=Compatible (preserved *from exploitation* of edible alien life — the stronger conservation motive; Solandar is the Mirror-inert preserve); Oshima (GJ-79)=TerraformedSterile. Hit the ~50/50 target across the silent remainder.
|
||||
2. WIKI CONTINUITY (Miri). Reconcile the entries that already gesture at native biochemistry so each is consistent with its assigned bit + the mechanism: GJ-827, GJ-524, GJ-166A, GJ-684A, GJ-197, GJ-79, GJ-124 (resolve whether Hạ Long''s "protein" is native-Compatible harvest or Earth aquaculture). Additive/explanatory, not contradictory — preserve deliberately-vague lines as intentional.
|
||||
3. biosphere_class AUTHORING PATH (asset-pipeline discipline — schema + source + values together, per .claude/rules/asset-pipeline.md). Add `biosphere_class` to wiki body frontmatter (where `substrate:` already lives), a nullable `bodies.biosphere_class` column in systems-schema.sql + MIGRATION_SQL, and importer read. NOT needed for D-246; lands with this pass.
|
||||
4. ALIEN-ECOLOGY VOCABULARY (Miri + Araminta) — feeds T-1084 directly. The mosaic palette is keyed on surface-class × climate-biome × biosphere-register (D-246 Palette-key). Provide the micro-habitat NAMES per biome × register: native-mirror niches get *alien* clade names (Solandar''s "five kingdoms" flavor); introduced-Earth niches get Earth names (wheatfield, orchard, pasture). Fill the fixed niche spine (canopy / understory / wet-hollow / pioneer / bare) per climate-biome (savanna gallery-copse, tundra thermokarst / lichen-heath, boreal muskeg / deadfall, …). DETERMINISM: the vocab must be fixed before T-1084 generates its first world (a later addition re-rolls affected voxels). Table size is not a perf/storage concern — author generously but to taste (~100k is headroom, not a target).
|
||||
|
||||
BURNELLI (stakeholder, follow-on): a food-supply demand primitive keyed on biosphere_class (Mirror + frontier → import dependency; Compatible → local-food capable). Phase-2 economy consumer; does not block this ticket.
|
||||
|
||||
CONSTRAINTS
|
||||
- Authored input, not derivation (Arbour''s estate food must never be coin-flipped inedible).
|
||||
- Semantic axes stay clade-agnostic (Forest = canopy whether oak or mega-fungus); the register skins niches, it does not change gameplay semantics.
|
||||
- The mosaic geometry is chirality-blind — this work does NOT touch voxel geometry, only edibility/economy/naming/vocab.
|
||||
|
||||
Chirality decisions resolved (2026-07-02, with Jeroen):
|
||||
- Locked exemplars: Arbour=NativeCompatible, Solandar=NativeMirror, Keid=NativeCompatible, Oshima=TerraformedSterile.
|
||||
- Miri assignments accepted: GJ-524=Mirror, Freyburg(GJ-684A)=Compatible, Hạ Long(GJ-124)=Compatible (native-Compatible harvest, per her rationale).
|
||||
- USER OVERRIDES: Puerto Último(GJ-197)=NativeCompatible (breadbasket identity over Miri''s balance-motivated Mirror). Edict/Sirius(GJ-244A)=Airless — keep the world harsh/frozen (deliberately-inconvenient below-grade transit capital is load-bearing canon); no climate change; below-grade sealed habitat = no open-air biosphere.
|
||||
- Two-gate default rule ACCEPTED for canon-silent worlds: Gate 0 (habitability from atmosphere/hydrosphere frontmatter → Airless / TerraformedSterile / Alive), Gate 1 (Compatible vs Mirror from economic_base_primary; agriculture→Compatible near-lock, penal→Mirror, research→50/50 lever).
|
||||
- NAMING: Keid''s habitable body renamed Cadwal→(pending final pick; rec Linnaeus — pairs with Solander, its student naturalist; or Beagle). Capital stays ''Vance'' (already the author tribute). Miri''s IP flag (Cadwal = Vance''s exact book title) is the driver.
|
||||
- Still to APPLY: the 7 additive wiki continuity edits (Miri specified exact text), the biosphere_class frontmatter+schema+importer plumbing (workstream 3), and the Cadwal→<name> rename across wiki + the GJ166A atlas proposal.
|
||||
|
||||
NAMING CONFIRMED: Keid''s habitable body Cadwal → Linnaeus (the great classifier; ties to Solander/Solandar taxonomy + the ''five kingdoms''). Capital stays Vance.
|
||||
|
||||
PROGRESS 2026-07-03: Workstreams 1-2 DONE + committed (388168eef, branch micro-habitat-mosaic).
|
||||
- Cadwal→Linnaeus rename applied (body frontmatter name + biosphere_class:NativeCompatible, GJ-166A infobox, atlas proposal, D-247 clarified). Capital stays Vance.
|
||||
- 5 wiki continuity edits applied (GJ-524 Mirror, GJ-166A/Keid Compatible, GJ-684A Freyburg Compatible, GJ-124 Hạ Long Compatible, GJ-197 Puerto Último Compatible). Solandar/Oshima needed none.
|
||||
REMAINING:
|
||||
- Workstream 3 (biosphere_class plumbing): add nullable bodies.biosphere_class column to systems-schema.sql; teach tooling/db/wiki_sync.py import_from_wiki to read biosphere_class frontmatter + apply the two-gate DEFAULT for canon-silent bodies (Gate0 atmosphere/hydrosphere, Gate1 economic_role/economic_base); add explicit frontmatter for the 3 override bodies still needing it (Solandar=NativeMirror, GJ-524=NativeMirror [uninhabited-but-alive → default would mis-Airless it], Edict/GJ244Ad=Airless [standard-atm+ice edge case]); ensure generate_wiki round-trips biosphere_class; then the BAKE (run import_from_wiki + generate_wiki → systems.db + regenerated infoboxes, incl. the Linnaeus name propagation) + commit systems.db. Add biosphere_class to BodyParams read set (D-240) as the D-247 code hook. NOTE: the bake is a systems.db binary-artifact commit — consequential, do deliberately.
|
||||
- Workstream 4 (alien-ecology vocab → palette): integrate Miri''s biome × register vocabulary (cane/vane/wrack/husk/drum-root native-mirror lexicon + Earth-register names, per her Deliverable 3) into atlas/mosaic.rs + mosaic_constants.toml — extends the temperate/native baseline to the full surface-class × climate-biome × register palette. This also completes T-1084''s biome-awareness. Determinism: lock before generation.
|
||||
Miri''s full Deliverable 3 vocab (the source for workstream 4) is in her T-1085 agent report.', 'in_progress', 'medium', 'miri', NULL, 'D-247', '2026-07-02 20:30:57.222', '2026-07-03 20:40:15.305', NULL, '83246ebc2aa0550f44afd68721efb9d4', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
# Alien-Ecology Vocabulary — micro-habitat naming layer (D-247 / D-246 / T-1085)
|
||||
|
||||
Authored by **Miri** (T-1085 workstream 4), 2026-07-03. This is the **naming /
|
||||
rendering** layer that skins the mosaic's semantic micro-habitats (T-1084, D-246).
|
||||
The mosaic selects **D-228 axis-triples** (terrain × vegetation × water); this table
|
||||
supplies the **display names** per `climate-biome × register × niche`, so a "canopy"
|
||||
niche in a temperate forest reads as *vane-cane stand* (native-mirror) or *dense
|
||||
stand* (introduced-Earth). Names are **derived labels** (D-228) — never stored on the
|
||||
voxel. Co-maintenance with **Araminta** for visual grammar (per the T-995 ObjectTag
|
||||
precedent).
|
||||
|
||||
Governing canon: [D-247](../../governance/decisions/content.md) (native biospheres +
|
||||
chirality), [D-246](../../governance/decisions/architecture.md) (the mosaic that
|
||||
consumes this). Determinism: this vocabulary is part of the deterministic input
|
||||
surface once wired — fix it before the mosaic generates its first world.
|
||||
|
||||
---
|
||||
|
||||
## Methodology
|
||||
|
||||
### Niche spine (the cross-biome authoring scaffold — reinterpreted per biome)
|
||||
|
||||
The five niches are **roles**, not literal "trees exist here" claims — each biome
|
||||
reinterprets them (a grassland's "canopy" is its tallest grass stratum):
|
||||
|
||||
- **canopy** — the biome's tallest/densest cover stratum. Full overhead concealment
|
||||
where the biome has one; the thickest topmost growth otherwise. Blocks sightlines +
|
||||
weather; sets the movement-sound baseline.
|
||||
- **understory** — the layer beneath/within canopy, or a secondary partial-cover
|
||||
stratum where there's no true canopy. Partial concealment, filtered light.
|
||||
- **wet-hollow** — moisture-conditioned low point, tied to the `voxel_relief`
|
||||
micro-thalweg (D-246). Slows movement; sound and smell carry differently.
|
||||
- **pioneer** — colonizing / disturbed / regrowth ground; first-succession or edge
|
||||
margin. The "in-between" transition zone.
|
||||
- **bare-ground** — minimal-to-no cover, exposed substrate. Best sightlines, least
|
||||
concealment, fastest movement; the biome's "clearing"/"pan" default.
|
||||
|
||||
### Register naming
|
||||
|
||||
- **Introduced-Earth** — ordinary recognizable agricultural/ecological English
|
||||
(orchard, pasture, hedgerow): warm, human-scaled, legible at a glance.
|
||||
- **Native (alien)** — built from a small recurring invented growth-habit lexicon (the
|
||||
alien equivalent of "tree / grass / moss / reed" as informal field terms, not formal
|
||||
taxonomy — Solandar's "five kingdoms" stays deliberately unnamed at the formal level).
|
||||
|
||||
### The native growth-habit lexicon
|
||||
|
||||
| Root | Fills the role of | Typical niche |
|
||||
|---|---|---|
|
||||
| **cane** | tall, upright, single-or-clustered stalks | canopy / understory in wooded biomes |
|
||||
| **vane** | broad, blade-like, often iridescent structures | canopy (the richest biomes) |
|
||||
| **wrack** | low, spreading, mat-forming growth | bare-ground / pioneer / understory |
|
||||
| **husk** | bulb/pod-bearing, clustered near water | wet-hollow |
|
||||
| **drum-root** | colonial, ring-spreading root-network | pioneer (recurs across Grassland/Tundra/Savanna) |
|
||||
|
||||
A few names deliberately **recur across biomes** (husk-fall tangle, lichen-scald flat,
|
||||
scorch-bloom flush, the drum-root/ring motif) — intentional coherence: it reads as one
|
||||
designed ecology, not eleven unrelated ones. This is the Bobiverse "convergent-but-alien
|
||||
niches" touchstone made concrete: the same growth-habit fills the same niche across
|
||||
biomes, as oak/pine/baobab all fill "canopy" on Earth without being the same species.
|
||||
|
||||
### Sensory discipline — the achiral seam (D-247) stays intact
|
||||
|
||||
Native water is always safe to drink, ground always safe to mine/walk, biomass always
|
||||
safe to burn/build. Every note flavors **strangeness** (smell, sound, texture, footing),
|
||||
never *danger*, for those actions. Where hazard flavor appears it is **mechanical/
|
||||
textural** (brittle husks giving way, thorns, uneven footing) — never biochemical
|
||||
(Mirror life can't infect or poison; Compatible hazard is an *authored* option, flagged
|
||||
as a hook, not exercised on any specific world here).
|
||||
|
||||
### Scope
|
||||
|
||||
This table fills **climate-biome × register**, richest on the six vegetated biomes,
|
||||
lighter on the five extreme ones (niches merged where they don't naturally apply). A
|
||||
full `climate-biome × surface-class × register` cross-product is a future pass; the
|
||||
D-246 Sand/Rock/Gravel/Lava surface-class rows already carry register-neutral flavor.
|
||||
|
||||
---
|
||||
|
||||
## Rich biomes
|
||||
|
||||
### TropicalWet
|
||||
*The Solandar register — hot, wet, maximum biomass, fast decomposition. "Twelve thousand species, five kingdoms."*
|
||||
|
||||
| Niche | Native-Mirror | Introduced-Earth |
|
||||
|---|---|---|
|
||||
| Canopy | **Vane-crown stand** — towering oil-sheened vane-blades interlock into a solid ceiling; understory twilight-dim at midday. A thick sweetish rot-and-sap smell that never clears. | **Cacao shade-block** — planted tree-crop under managed shade canopy; rows just regular enough to give away human hands. |
|
||||
| Understory | **Wrack-drape thicket** — wet curtains of wrack draping from the canopy; clings and slows movement, leaves a faint chemical tang. | **Shade-coffee row** — broad-leafed cultivars beneath the plantation canopy. |
|
||||
| Wet-hollow | **Husk-seep hollow** — bellied husk-growths at a warm standing seep; water runs faintly opalescent with alien tannins — safe to drink, unmistakably not Earth's water by the smell. | **Rice-paddy terrace** — flooded cultivated wet-ground rows. |
|
||||
| Pioneer | **Scorch-bloom flush** — fast alien color-succession flooding a canopy-fall light-gap within weeks, before slower vane-forms retake it. | **Cassava clearing** — a slashed-and-fallow plot gone to quick Earth pioneer weeds and root crops. |
|
||||
| Bare-ground | **Salt-crust flat** — mineral-crusted open patch where nothing native roots, by chemistry not disturbance; wrong-colored crust crunches underfoot. | **Threshing yard** — bare packed earth cut into the plantation. |
|
||||
|
||||
### TemperateForest
|
||||
|
||||
| Niche | Native-Mirror | Introduced-Earth (existing D-246 baseline) |
|
||||
|---|---|---|
|
||||
| Canopy | **Vane-cane stand** — cane trunks crowned with stiff, faintly metallic-blue vane-fronds; a dry clicking rustle, not a hiss — it doesn't *sound* like a forest. | **Dense stand** |
|
||||
| Understory | **Wrack-frond undergrowth** — knee-high tangle, cool and slightly rubbery; brushing it releases a sharp resinous smell with no Earth analog. | **Fern undergrowth** |
|
||||
| Wet-hollow | **Husk-reed run** — husk-reeds trace the brook's micro-thalweg; husks pop and refill audibly as current passes — heard before seen. | **Brook** |
|
||||
| Pioneer | **Husk-fall tangle** — collapsed cane-husks, brittle and hollow rather than woody; lighter to move than deadfall but sharper underfoot (a footing hazard, not a fire-fuel one). | **Deadfall** |
|
||||
| Bare-ground | **Bloom-scald clearing** — kept open by an allelopathic wrack that poisons competing roots (achiral-safe to walk, just barren); faint bitter-almond air. | **Glade** |
|
||||
|
||||
### TemperateGrassland
|
||||
|
||||
| Niche | Native-Mirror | Introduced-Earth |
|
||||
|---|---|---|
|
||||
| Canopy | **Cane-tassel sweep** — waist-to-shoulder cane tipped with heavy seed-tassels; moves in slow grass-like waves, but the tassels chime softly against each other. | **Tussock** |
|
||||
| Understory | **Wrack-bloom understory** — a low flowering layer threading between the cane-tassels; a sweet "almost right" smell that unsettles Earth-register visitors. | **Wildflower** |
|
||||
| Wet-hollow | **Husk-line seep** — the ephemeral channel lined with squat husk-forms that only surface after rain — a visible tell of where the water runs even in dry season. | **Dry wash** |
|
||||
| Pioneer | **Drum-root knot** — a knotted ring of colonial root-growth pushing up through the grass, spreading centimeters a year; the ring's center is always slightly bare. | **Scrub island** |
|
||||
| Bare-ground | **Hardpan scald** — a mineral-crusted bare patch; the ground rings slightly hollow underfoot. | **Grazing pan** — bare-trodden earth from stock. |
|
||||
|
||||
### BorealForest
|
||||
|
||||
| Niche | Native-Mirror | Introduced-Earth |
|
||||
|---|---|---|
|
||||
| Canopy | **Rime-vane stand** — slow, frost-hardy vane-cane holding a permanent rime-like bloom even in summer; dim, cold, nearly silent — a "wrong" quiet. | **Spruce-shadow stand** — conifer-analog, deep cold shade, needle-duff footing. |
|
||||
| Understory | **Wrack-moss carpet** — thick spongy wrack holding meltwater like a sponge; boots sink and release a cold mineral smell. | **Bilberry scrub** |
|
||||
| Wet-hollow | **Husk-bog muskeg** — waterlogged cold ground where the tussocks are husk-forms; each step risks a hollow husk giving way. | **Muskeg fen** |
|
||||
| Pioneer | **Husk-fall tangle** (shared with TemperateForest) | **Deadfall** — cold-climate blowdown. |
|
||||
| Bare-ground | **Lichen-scald flat** — thin pale native crust over permafrost-like ground, ancient and slow; disturbing it outlasts a human lifetime. | **Burn scar** |
|
||||
|
||||
### Tundra
|
||||
*Treeless, thermokarst. Thin biomass; niches all present but small.*
|
||||
|
||||
| Niche | Native-Mirror | Introduced-Earth |
|
||||
|---|---|---|
|
||||
| Canopy (dwarf) | **Husk-heath brake** — the tallest native growth is ankle-high, a dense husk-mat; reads as heath at distance, clearly not-leaves up close. | **Dwarf-willow brake** |
|
||||
| Understory | **Wrack-lichen mat** — a thin crust; grows so slowly that a season's footpath shows a decade later. | **Moss-sedge mat** |
|
||||
| Wet-hollow | **Thermokarst husk-pool** — a collapse-and-thaw pool ringed with husk-forms that emerge only in the brief thaw window — seasonal in a way no other biome's wet-hollow is. | **Thaw-pond sedge** |
|
||||
| Pioneer | **Drum-root ring** (shared motif, at tundra scale — centimeters across after decades) | **Gravel scar** |
|
||||
| Bare-ground | **Lichen-scald flat** (shared with Boreal — here over patterned-ground polygons) | **Frost-heave flat** |
|
||||
|
||||
### Savanna
|
||||
*Warm, seasonal, grass-dominant with scattered tree-copses.*
|
||||
|
||||
| Niche | Native-Mirror | Introduced-Earth |
|
||||
|---|---|---|
|
||||
| Canopy | **Vane-crown copse** — an isolated stand, the only real shade for kilometers; mistakable for a gallery copse at distance, but the bark-analog is smooth and faintly warm. | **Gallery copse** |
|
||||
| Understory | **Husk-thorn scrub** — thorny native scrub, identical obstruction/concealment to acacia; the thorns are hollow and whistle faintly in wind. | **Acacia scrub** |
|
||||
| Wet-hollow | **Husk-pan waterhole** — seasonal flood-and-dry; dormant husk-forms visibly "wake" within days of the first rain. | **Seasonal waterhole** |
|
||||
| Pioneer | **Scorch-bloom flush** (shared with TropicalWet — succession by seasonal fire) | **Burnt-grass flush** |
|
||||
| Bare-ground | **Drum-mound flat** — a hardpan clearing built by colonial drum-root activity; bare, sun-baked, faintly warm underfoot even at night. | **Termite-pan clearing** |
|
||||
|
||||
---
|
||||
|
||||
## Lighter biomes (extreme classes — niches merged/noted where they don't apply)
|
||||
|
||||
### Desert
|
||||
| Niche | Native-Mirror | Introduced-Earth |
|
||||
|---|---|---|
|
||||
| Canopy ("tallest thing here") | **Cane-spire stand** — sparse deep-taprooted spires, each commanding the horizon with a thin moving shadow. | **Date-palm draw** |
|
||||
| Understory + pioneer (merged) | **Wrack-thorn scatter** — sparse widely-spaced domed clumps hoarding moisture. | **Scrub flat** |
|
||||
| Wet-hollow | **Husk-spring hollow** — a rare seep ringed with water-swollen husk-forms; the local landmark. Water fine to drink; nothing in the ring looks edible. | **Wadi oasis** |
|
||||
| Bare-ground | *served by the D-246 Sand/Rock rows* (dune crest, hardpan, outcrop, scree) — bare rock/sand carries no register. | (same) |
|
||||
|
||||
### Alpine
|
||||
| Niche | Native-Mirror | Introduced-Earth |
|
||||
|---|---|---|
|
||||
| Canopy (treeline fringe) | **Wind-cane fringe** — wind-flagged, permanently bent one way; the flag-shape wayfinds like krummholz, the material reads wrong up close. | **Krummholz fringe** |
|
||||
| Understory + pioneer (merged) | **Wrack-cushion field** — tight ground-hugging growth, faintly warm to bare skin (a metabolic-heat tell Earth cushion plants lack). | **Cushion-plant field** |
|
||||
| Wet-hollow | **Husk-melt seep** — seasonal meltwater seep, husk-forms present only weeks a year. | **Snowmelt sedge** |
|
||||
| Bare-ground | *served by the Rock rows* (outcrop/scree/talus/ledge/**lichen** — lichen doubles as this biome's dominant cover). | (same) |
|
||||
|
||||
### Volcanic
|
||||
*D-210 flags this the least data-grounded biome; the Lava surface-class already has the richest table. Kept light.*
|
||||
|
||||
| Niche | Native-Mirror | Introduced-Earth |
|
||||
|---|---|---|
|
||||
| Recovering slope (canopy/understory collapsed) | **Husk-root slope** — pioneer husk-root colonizing cooled ash, first native life back after a flow. | **Ash-orchard slope** — Earth fruit trees on fertile volcanic ash. |
|
||||
| Wet-hollow | **Husk-vent seep** — a geothermal seep, the hardiest husk-forms in the register; warm, safe to bathe in. | **Hot-spring terrace** |
|
||||
| Pioneer + bare-ground | *served by the Lava rows* (fresh sheet, weathered crust w/ Lichen, tube collapse, pioneer scrub). | (same) |
|
||||
|
||||
### Wetland (climate-biome)
|
||||
*Heavily overlaps the surface-class Wetland table (richest baseline). Native mirror given for symmetry; kept light.*
|
||||
|
||||
| Niche | Native-Mirror | Introduced-Earth (existing D-246 names) |
|
||||
|---|---|---|
|
||||
| Canopy | **Husk-crown copse** — water-rooted husk-trees hung with drip-tendrils. | **Copse** |
|
||||
| Understory / bare-ground | **Wrack-flat clearing** — open wrack-carpeted shallows. | **Meadow / Clearing** |
|
||||
| Wet-hollow (×3) | **Husk-bog / Husk-marsh / Husk-run** — the marsh variant's reed-analog hisses faintly when disturbed, a natural detection tell. | **Bog / Marsh / Creek** |
|
||||
| Pioneer | thin/underdeveloped (same gap as the baseline) | (same gap) |
|
||||
|
||||
### CoastalLowland
|
||||
| Niche | Native-Mirror | Introduced-Earth |
|
||||
|---|---|---|
|
||||
| Canopy | **Vane-palm fringe** — salt-tolerant, leaning permanently seaward; same visual tell as a coastal treeline, different material. | **Coconut fringe** |
|
||||
| Understory + pioneer (merged) | **Wrack-tangle scrub** — salt-hardy tangle; smells of ozone and brine-that's-not-quite-brine. | **Dune scrub** |
|
||||
| Wet-hollow (tidal) | **Husk-tide flat** — husk-forms seal shut at low tide and visibly "breathe" open as water returns — a legible tide-state tell. | **Salt-marsh flat** |
|
||||
| Bare-ground | **Husk-shard beach** — the tideline wrack is broken husk-fragments instead of shells; the wrong shapes up close. | **Shell-sand beach** |
|
||||
|
||||
---
|
||||
|
||||
## Open hooks (Miri, T-1085)
|
||||
|
||||
- **Five kingdoms** — Solandar's "twelve thousand species across five kingdoms" is left
|
||||
formally unnamed (deliberately-vague canon). Naming the kingdoms is a future hook.
|
||||
- **Compatible-world hazard** — a Compatible (levo) biome (TropicalWet, Savanna) is the
|
||||
right *register* for a future authored native pathogen/toxin (D-247 §"coupling permits
|
||||
but doesn't force"); a hook, not yet exercised.
|
||||
- **Full cross-product** — climate-biome × **surface-class** × register (this table is
|
||||
climate-biome × register only) is a future pass.
|
||||
@@ -107,38 +107,160 @@ water = "Dry"
|
||||
weight = 15
|
||||
affinity = "any"
|
||||
|
||||
[[grassland]]
|
||||
name = "tussock"
|
||||
# Grassland is BIOME-KEYED (T-1085, D-246): the ClimateBiome derived from the district's
|
||||
# temperature_c + moisture_q selects savanna / temperate / boreal / tundra, so a
|
||||
# grassland reads distinctly per climate rather than as one biome-blind palette. §8-safe
|
||||
# (vegetation + water; terrain stays Soil in v1). Names per
|
||||
# docs/design/alien-ecology-vocabulary.md.
|
||||
|
||||
[[grassland_temperate]]
|
||||
name = "cane-tassel sweep"
|
||||
terrain = "Soil"
|
||||
vegetation = "Grass"
|
||||
water = "Dry"
|
||||
weight = 40
|
||||
affinity = "any"
|
||||
|
||||
[[grassland]]
|
||||
name = "scrub island"
|
||||
[[grassland_temperate]]
|
||||
name = "drum-root knot"
|
||||
terrain = "Soil"
|
||||
vegetation = "Scrub"
|
||||
water = "Dry"
|
||||
weight = 18
|
||||
affinity = "dry"
|
||||
|
||||
[[grassland]]
|
||||
name = "wildflower"
|
||||
[[grassland_temperate]]
|
||||
name = "wrack-bloom"
|
||||
terrain = "Soil"
|
||||
vegetation = "Meadow"
|
||||
water = "Dry"
|
||||
weight = 17
|
||||
affinity = "dry"
|
||||
|
||||
[[grassland]]
|
||||
name = "dry wash"
|
||||
terrain = "Gravel"
|
||||
[[grassland_temperate]]
|
||||
name = "husk-line seep"
|
||||
terrain = "Soil"
|
||||
vegetation = "Barren"
|
||||
water = "Dry"
|
||||
weight = 10
|
||||
affinity = "wet"
|
||||
|
||||
# Savanna: scattered Forest copses in a grass matrix — the vane-crown copse is the
|
||||
# clearest distinction from temperate grassland.
|
||||
[[grassland_savanna]]
|
||||
name = "cane-tassel sweep"
|
||||
terrain = "Soil"
|
||||
vegetation = "Grass"
|
||||
water = "Dry"
|
||||
weight = 38
|
||||
affinity = "any"
|
||||
|
||||
[[grassland_savanna]]
|
||||
name = "vane-crown copse"
|
||||
terrain = "Soil"
|
||||
vegetation = "Forest"
|
||||
water = "Dry"
|
||||
weight = 12
|
||||
affinity = "dry"
|
||||
|
||||
[[grassland_savanna]]
|
||||
name = "husk-thorn scrub"
|
||||
terrain = "Soil"
|
||||
vegetation = "Scrub"
|
||||
water = "Dry"
|
||||
weight = 18
|
||||
affinity = "dry"
|
||||
|
||||
[[grassland_savanna]]
|
||||
name = "husk-pan waterhole"
|
||||
terrain = "Soil"
|
||||
vegetation = "Grass"
|
||||
water = "Shallow"
|
||||
weight = 10
|
||||
affinity = "wet"
|
||||
|
||||
[[grassland_savanna]]
|
||||
name = "drum-mound flat"
|
||||
terrain = "Soil"
|
||||
vegetation = "Barren"
|
||||
water = "Dry"
|
||||
weight = 12
|
||||
affinity = "dry"
|
||||
|
||||
# Boreal grassland: cooler, sparser — more scrub, a lichen fraction, no meadow.
|
||||
[[grassland_boreal]]
|
||||
name = "cane-tassel sweep"
|
||||
terrain = "Soil"
|
||||
vegetation = "Grass"
|
||||
water = "Dry"
|
||||
weight = 30
|
||||
affinity = "any"
|
||||
|
||||
[[grassland_boreal]]
|
||||
name = "wrack-scrub"
|
||||
terrain = "Soil"
|
||||
vegetation = "Scrub"
|
||||
water = "Dry"
|
||||
weight = 25
|
||||
affinity = "dry"
|
||||
|
||||
[[grassland_boreal]]
|
||||
name = "husk-line seep"
|
||||
terrain = "Soil"
|
||||
vegetation = "Grass"
|
||||
water = "Shallow"
|
||||
weight = 10
|
||||
affinity = "wet"
|
||||
|
||||
[[grassland_boreal]]
|
||||
name = "wrack-lichen mat"
|
||||
terrain = "Soil"
|
||||
vegetation = "Lichen"
|
||||
water = "Dry"
|
||||
weight = 12
|
||||
affinity = "any"
|
||||
|
||||
[[grassland_boreal]]
|
||||
name = "cold scald"
|
||||
terrain = "Soil"
|
||||
vegetation = "Barren"
|
||||
water = "Dry"
|
||||
weight = 15
|
||||
affinity = "dry"
|
||||
|
||||
# Tundra: sparse and cold — scrub, lichen, bare patterned ground, NO forest.
|
||||
[[grassland_tundra]]
|
||||
name = "husk-heath brake"
|
||||
terrain = "Soil"
|
||||
vegetation = "Scrub"
|
||||
water = "Dry"
|
||||
weight = 26
|
||||
affinity = "any"
|
||||
|
||||
[[grassland_tundra]]
|
||||
name = "wrack-lichen mat"
|
||||
terrain = "Soil"
|
||||
vegetation = "Lichen"
|
||||
water = "Dry"
|
||||
weight = 24
|
||||
affinity = "any"
|
||||
|
||||
[[grassland_tundra]]
|
||||
name = "thermokarst husk-pool"
|
||||
terrain = "Soil"
|
||||
vegetation = "Grass"
|
||||
water = "Shallow"
|
||||
weight = 10
|
||||
affinity = "wet"
|
||||
|
||||
[[grassland_tundra]]
|
||||
name = "lichen-scald flat"
|
||||
terrain = "Soil"
|
||||
vegetation = "Barren"
|
||||
water = "Dry"
|
||||
weight = 30
|
||||
affinity = "dry"
|
||||
|
||||
# ── Follow-up (§8-aware material pass): Sand / Rock / Gravel / Lava ──────────────
|
||||
|
||||
[[sand]]
|
||||
|
||||
+136
-18
@@ -85,6 +85,40 @@ impl SurfaceClass {
|
||||
}
|
||||
}
|
||||
|
||||
/// The district's climate-biome (T-1085, D-246) — derived from `temperature_c` +
|
||||
/// `moisture_q`. It refines the *vegetated* surface-class palettes so a Grassland reads
|
||||
/// as savanna / temperate / boreal / tundra rather than one biome-blind palette (the
|
||||
/// D-246 biome-awareness fix). The alien display names per biome × register live in
|
||||
/// `docs/design/alien-ecology-vocabulary.md`; this layer carries only the D-228 axes.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ClimateBiome {
|
||||
Tropical,
|
||||
Temperate,
|
||||
Boreal,
|
||||
Tundra,
|
||||
Savanna,
|
||||
}
|
||||
|
||||
impl ClimateBiome {
|
||||
/// Coarse biome from mean-annual temperature (°C) + district moisture (0–100).
|
||||
/// Airless districts never reach the mosaic; the `10.0` default is a safe
|
||||
/// temperate fallback for a missing temperature.
|
||||
pub fn from_climate(temperature_c: Option<f32>, moisture_q: i32) -> Self {
|
||||
let t = temperature_c.unwrap_or(10.0);
|
||||
if t < 0.0 {
|
||||
ClimateBiome::Tundra
|
||||
} else if t < 7.0 {
|
||||
ClimateBiome::Boreal
|
||||
} else if t <= 20.0 {
|
||||
ClimateBiome::Temperate
|
||||
} else if moisture_q >= 45 {
|
||||
ClimateBiome::Tropical
|
||||
} else {
|
||||
ClimateBiome::Savanna
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Shorthand for the const tables below.
|
||||
use MoistureAffinity::{Any, Dry, Wet};
|
||||
use TerrainMaterial as T;
|
||||
@@ -128,11 +162,49 @@ const FOREST: &[MicroHabitat] = &[
|
||||
h("fern undergrowth", T::Soil, V::Thicket, W::Dry, 15, Any),
|
||||
];
|
||||
|
||||
const GRASSLAND: &[MicroHabitat] = &[
|
||||
h("tussock", T::Soil, V::Grass, W::Dry, 40, Any),
|
||||
h("scrub island", T::Soil, V::Scrub, W::Dry, 18, Dry),
|
||||
h("wildflower", T::Soil, V::Meadow, W::Dry, 17, Dry),
|
||||
h("dry wash", T::Gravel, V::Barren, W::Dry, 10, Wet),
|
||||
// Grassland is biome-keyed (T-1085): savanna / temperate / boreal / tundra read
|
||||
// distinctly rather than as one biome-blind palette (D-246). §8-safe — vegetation +
|
||||
// water only; terrain stays Soil in v1 (the Gravel dry-wash material variant is the
|
||||
// §8-aware follow-up). Names per docs/design/alien-ecology-vocabulary.md.
|
||||
const GRASSLAND_TEMPERATE: &[MicroHabitat] = &[
|
||||
h("cane-tassel sweep", T::Soil, V::Grass, W::Dry, 40, Any),
|
||||
h("drum-root knot", T::Soil, V::Scrub, W::Dry, 18, Dry),
|
||||
h("wrack-bloom", T::Soil, V::Meadow, W::Dry, 17, Dry),
|
||||
h("husk-line seep", T::Soil, V::Barren, W::Dry, 10, Wet),
|
||||
];
|
||||
|
||||
// Savanna: the signature is scattered Forest copses in a grass matrix (the
|
||||
// vane-crown copse) — the clearest biome distinction from temperate grassland.
|
||||
const GRASSLAND_SAVANNA: &[MicroHabitat] = &[
|
||||
h("cane-tassel sweep", T::Soil, V::Grass, W::Dry, 38, Any),
|
||||
h("vane-crown copse", T::Soil, V::Forest, W::Dry, 12, Dry),
|
||||
h("husk-thorn scrub", T::Soil, V::Scrub, W::Dry, 18, Dry),
|
||||
h("husk-pan waterhole", T::Soil, V::Grass, W::Shallow, 10, Wet),
|
||||
h("drum-mound flat", T::Soil, V::Barren, W::Dry, 12, Dry),
|
||||
];
|
||||
|
||||
// Boreal grassland: cooler and sparser — more scrub, a lichen fraction, no meadow.
|
||||
const GRASSLAND_BOREAL: &[MicroHabitat] = &[
|
||||
h("cane-tassel sweep", T::Soil, V::Grass, W::Dry, 30, Any),
|
||||
h("wrack-scrub", T::Soil, V::Scrub, W::Dry, 25, Dry),
|
||||
h("husk-line seep", T::Soil, V::Grass, W::Shallow, 10, Wet),
|
||||
h("wrack-lichen mat", T::Soil, V::Lichen, W::Dry, 12, Any),
|
||||
h("cold scald", T::Soil, V::Barren, W::Dry, 15, Dry),
|
||||
];
|
||||
|
||||
// Tundra: sparse and cold — scrub, lichen, bare patterned ground, NO forest.
|
||||
const GRASSLAND_TUNDRA: &[MicroHabitat] = &[
|
||||
h("husk-heath brake", T::Soil, V::Scrub, W::Dry, 26, Any),
|
||||
h("wrack-lichen mat", T::Soil, V::Lichen, W::Dry, 24, Any),
|
||||
h(
|
||||
"thermokarst husk-pool",
|
||||
T::Soil,
|
||||
V::Grass,
|
||||
W::Shallow,
|
||||
10,
|
||||
Wet,
|
||||
),
|
||||
h("lichen-scald flat", T::Soil, V::Barren, W::Dry, 30, Dry),
|
||||
];
|
||||
|
||||
const SAND: &[MicroHabitat] = &[
|
||||
@@ -161,12 +233,19 @@ const LAVA: &[MicroHabitat] = &[
|
||||
h("pioneer scrub", T::Lava, V::Scrub, W::Dry, 20, Dry),
|
||||
];
|
||||
|
||||
/// The embedded palette for a surface-class (temperate / native baseline).
|
||||
pub fn palette(class: SurfaceClass) -> &'static [MicroHabitat] {
|
||||
/// The embedded native palette for a `(surface-class, climate-biome)` (D-246 Palette
|
||||
/// key). Grassland is biome-keyed (T-1085); the other classes are biome-invariant in
|
||||
/// v1 — Forest biomes (tropical/boreal) and the extreme classes are the follow-up.
|
||||
pub fn palette(class: SurfaceClass, biome: ClimateBiome) -> &'static [MicroHabitat] {
|
||||
match class {
|
||||
SurfaceClass::Wetland => WETLAND,
|
||||
SurfaceClass::Forest => FOREST,
|
||||
SurfaceClass::Grassland => GRASSLAND,
|
||||
SurfaceClass::Grassland => match biome {
|
||||
ClimateBiome::Savanna | ClimateBiome::Tropical => GRASSLAND_SAVANNA,
|
||||
ClimateBiome::Boreal => GRASSLAND_BOREAL,
|
||||
ClimateBiome::Tundra => GRASSLAND_TUNDRA,
|
||||
ClimateBiome::Temperate => GRASSLAND_TEMPERATE,
|
||||
},
|
||||
SurfaceClass::Sand => SAND,
|
||||
SurfaceClass::Rock => ROCK,
|
||||
SurfaceClass::Gravel => GRAVEL,
|
||||
@@ -240,7 +319,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn every_palette_nonempty_and_positively_weighted() {
|
||||
for class in [
|
||||
let classes = [
|
||||
SurfaceClass::Wetland,
|
||||
SurfaceClass::Forest,
|
||||
SurfaceClass::Grassland,
|
||||
@@ -248,19 +327,58 @@ mod tests {
|
||||
SurfaceClass::Rock,
|
||||
SurfaceClass::Gravel,
|
||||
SurfaceClass::Lava,
|
||||
] {
|
||||
let p = palette(class);
|
||||
assert!(!p.is_empty(), "{class:?} palette empty");
|
||||
assert!(
|
||||
p.iter().all(|hab| hab.weight > 0),
|
||||
"{class:?} has a non-positive weight"
|
||||
);
|
||||
];
|
||||
let biomes = [
|
||||
ClimateBiome::Tropical,
|
||||
ClimateBiome::Temperate,
|
||||
ClimateBiome::Boreal,
|
||||
ClimateBiome::Tundra,
|
||||
ClimateBiome::Savanna,
|
||||
];
|
||||
for class in classes {
|
||||
for biome in biomes {
|
||||
let p = palette(class, biome);
|
||||
assert!(!p.is_empty(), "{class:?}/{biome:?} palette empty");
|
||||
assert!(
|
||||
p.iter().all(|hab| hab.weight > 0),
|
||||
"{class:?}/{biome:?} has a non-positive weight"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_climate_bands() {
|
||||
use ClimateBiome::*;
|
||||
assert_eq!(ClimateBiome::from_climate(Some(-10.0), 40), Tundra);
|
||||
assert_eq!(ClimateBiome::from_climate(Some(3.0), 40), Boreal);
|
||||
assert_eq!(ClimateBiome::from_climate(Some(12.0), 40), Temperate);
|
||||
assert_eq!(ClimateBiome::from_climate(Some(28.0), 70), Tropical);
|
||||
assert_eq!(ClimateBiome::from_climate(Some(28.0), 20), Savanna);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn grassland_biomes_are_distinct() {
|
||||
// Savanna carries scattered Forest copses; tundra carries none but has Lichen.
|
||||
let savanna = palette(SurfaceClass::Grassland, ClimateBiome::Savanna);
|
||||
let tundra = palette(SurfaceClass::Grassland, ClimateBiome::Tundra);
|
||||
assert!(
|
||||
savanna.iter().any(|h| h.vegetation == V::Forest),
|
||||
"savanna should have Forest copses"
|
||||
);
|
||||
assert!(
|
||||
!tundra.iter().any(|h| h.vegetation == V::Forest),
|
||||
"tundra must not carry Forest"
|
||||
);
|
||||
assert!(
|
||||
tundra.iter().any(|h| h.vegetation == V::Lichen),
|
||||
"tundra should have Lichen"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn select_is_deterministic_and_spans_the_palette() {
|
||||
let p = palette(SurfaceClass::Wetland);
|
||||
let p = palette(SurfaceClass::Wetland, ClimateBiome::Temperate);
|
||||
assert_eq!(select(p, 0.37, 0.5).name, select(p, 0.37, 0.5).name);
|
||||
let names: std::collections::BTreeSet<_> = (0..100)
|
||||
.map(|i| select(p, i as f64 / 100.0, 0.5).name)
|
||||
@@ -274,7 +392,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn wetness_favours_wet_habitats_over_dry_signal() {
|
||||
let p = palette(SurfaceClass::Wetland);
|
||||
let p = palette(SurfaceClass::Wetland, ClimateBiome::Temperate);
|
||||
let wet_count = |wetness: f64| {
|
||||
(0..100)
|
||||
.filter(|i| {
|
||||
|
||||
@@ -530,10 +530,22 @@ pub fn derive_voxel_column(
|
||||
use crate::atlas::mosaic::{self, SurfaceClass};
|
||||
let dominant_veg = Vegetation::from_vegetation_class(district_eff.vegetation_class);
|
||||
let class = SurfaceClass::from_base(column.terrain, dominant_veg);
|
||||
// Climate-biome (T-1085) refines the Grassland palette: savanna / temperate /
|
||||
// boreal / tundra read distinctly (D-246 biome-awareness).
|
||||
let biome =
|
||||
mosaic::ClimateBiome::from_climate(district_eff.temperature_c, district_eff.moisture_q);
|
||||
let apply = match class {
|
||||
SurfaceClass::Wetland | SurfaceClass::Forest => true,
|
||||
// Barren grassland (cold / arid) stays barren — no imposed grass.
|
||||
SurfaceClass::Grassland => !matches!(dominant_veg, Vegetation::Barren),
|
||||
// A vegetated grassland always; a barren-dominant one only when the biome is
|
||||
// cold (tundra / boreal), where the sparse lichen/scrub mosaic is climate-
|
||||
// appropriate — a hot barren district (desert on Soil) stays bare.
|
||||
SurfaceClass::Grassland => {
|
||||
!matches!(dominant_veg, Vegetation::Barren)
|
||||
|| matches!(
|
||||
biome,
|
||||
mosaic::ClimateBiome::Tundra | mosaic::ClimateBiome::Boreal
|
||||
)
|
||||
}
|
||||
// Rock / Sand / Gravel / Lava are material-driven — a §8-aware follow-up.
|
||||
_ => false,
|
||||
};
|
||||
@@ -550,7 +562,7 @@ pub fn derive_voxel_column(
|
||||
// lowered on the rises (relief_signal negative in valleys).
|
||||
let moisture = (district_eff.moisture_q as f64 / 100.0).clamp(0.0, 1.0);
|
||||
let wetness = (moisture - relief_signal).clamp(0.0, 1.0);
|
||||
let hab = mosaic::select(mosaic::palette(class), field, wetness);
|
||||
let hab = mosaic::select(mosaic::palette(class, biome), field, wetness);
|
||||
column.vegetation = hab.vegetation;
|
||||
// Add standing water only where the family left it dry AND the chunk's
|
||||
// hydrology gate allows it (T-1040: water placement must agree with
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
"drainage_samples": 0,
|
||||
"drainage_monotonic": 0,
|
||||
"vegetation_samples": 64,
|
||||
"vegetated_districts": 8
|
||||
"vegetated_districts": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -70,7 +70,7 @@
|
||||
"vegetation_classes": 1,
|
||||
"terrain_materials": 4,
|
||||
"voxel_relief_m": 19,
|
||||
"micro_habitat_distinct": 0
|
||||
"micro_habitat_distinct": 1
|
||||
},
|
||||
"coherence": {
|
||||
"water_districts": 25,
|
||||
@@ -78,7 +78,7 @@
|
||||
"drainage_samples": 0,
|
||||
"drainage_monotonic": 0,
|
||||
"vegetation_samples": 64,
|
||||
"vegetated_districts": 0
|
||||
"vegetated_districts": 39
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user