docs(docs): 📝 Update Phase 3 military communications and resources documentation with handoff notes for data schema drift
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
5f0d8ddc08
commit
f064fd0612
3 changed files with 185 additions and 1 deletions
|
|
@ -0,0 +1,74 @@
|
|||
---
|
||||
from: simulator-infra (p1-60 fog-of-war closeout)
|
||||
to: game-data
|
||||
date: 2026-05-19
|
||||
blocks: `./run verify` step 1 (game data JSON schemas)
|
||||
related: .project/objectives/p1-60-fog-of-war-testing-ai-fairness.md
|
||||
---
|
||||
|
||||
# Handoff — pre-existing JSON schema drift surfaced by `./run verify`
|
||||
|
||||
While closing **p1-60 (fog-of-war end-to-end coverage + AI fairness)**, the collective ran the full workspace gate. The fog-of-war work itself is green (29/29 Rust vision tests, 12 projection redaction tests, 6 AI fairness tests, 32/32 GUT fog tests, criterion bench at ~90 µs on the small map). `./run verify` nevertheless aborts at **step 1/18 — game data JSON schemas**, on drift that pre-dates p1-60 and is orthogonal to vision.
|
||||
|
||||
This handoff captures the failure set verbatim from `./run verify` (re-run 2026-05-19 at HEAD `df052213a`) so the data owner can pick it up without re-running the gate.
|
||||
|
||||
## Failure set (verbatim)
|
||||
|
||||
### 1. `public/resources/units/great_sculptor.json` — gender enum
|
||||
```
|
||||
FAIL public/resources/units/great_sculptor.json: gender: 'either' is not of type 'object', 'null'
|
||||
```
|
||||
- File: `public/resources/units/great_sculptor.json:?` (field `gender: "either"`)
|
||||
- Schema expects `object` or `null`; `"either"` was a free-string value.
|
||||
- Fix surface: the gender schema in `tools/validate_data/schemas/` (or whichever validator owns the unit schema) — either accept `"either"` as a documented enum value, or normalise the data to the structured form already used by other unit files.
|
||||
|
||||
### 2. `public/games/age-of-dwarves/data/terrain/flora_cover_blends.json` — missing `id`, `name`
|
||||
```
|
||||
FAIL public/games/age-of-dwarves/data/terrain/flora_cover_blends.json[0..7]: 'id' is a required property
|
||||
FAIL public/games/age-of-dwarves/data/terrain/flora_cover_blends.json[0..7]: 'name' is a required property
|
||||
```
|
||||
All 8 array entries lack `id` and `name`. Either:
|
||||
- backfill `id`/`name` per entry (canonical, matches `substrate.json` pattern), or
|
||||
- relax the schema if blends are intentionally anonymous (then explain *why* in the schema doc).
|
||||
|
||||
### 3. `public/games/age-of-dwarves/data/terrain/substrate.json` — missing `movement_cost`, `defense_bonus`
|
||||
```
|
||||
FAIL public/games/age-of-dwarves/data/terrain/substrate.json[0..8]: 'movement_cost' is a required property
|
||||
FAIL public/games/age-of-dwarves/data/terrain/substrate.json[0..8]: 'defense_bonus' is a required property
|
||||
```
|
||||
9 substrate rows lack both fields. The schema is right to demand them — pathfinding and combat both read these at runtime. Backfill from the reference implementation or design notes; do **not** drop the schema requirement.
|
||||
|
||||
### 4. `public/games/age-of-dwarves/data/terrain/substrate_blends.json` — missing `id`, `name`
|
||||
Same shape as #2 — 5+ entries lacking the required identifiers.
|
||||
|
||||
## Why this didn't block p1-60
|
||||
|
||||
`./run verify` runs JSON schema checks **before** Rust workspace tests. None of the failing files feed into fog-of-war:
|
||||
|
||||
- `compute_vision` reads grid biome labels (string IDs) and elevation, not terrain JSON.
|
||||
- `mc-player-api::projection` uses tile metadata already in `GameState`, not on-disk JSON.
|
||||
- The fog GUT proofs build maps in-memory with hand-set biome strings.
|
||||
|
||||
The blocking surface is purely the data validator. Once you patch the four files (or the corresponding schemas), the gate should advance to step 2.
|
||||
|
||||
## Adjacent orthogonal failure (different owner — flagging only)
|
||||
|
||||
`cargo test -p mc-turn` shows one pre-existing failure unrelated to p1-60:
|
||||
|
||||
```
|
||||
test abstract_projection::five_players_overflow_truncates_to_max_players ... FAILED
|
||||
```
|
||||
|
||||
This test was already failing at 2026-05-04 (predates the alliances/wrap_mode/VisionState work) and has no fog-of-war coupling. It belongs with whoever owns `mc-turn::abstract_projection`; we left it untouched.
|
||||
|
||||
## Acceptance for closing this handoff
|
||||
|
||||
- [ ] `./run verify` advances past step 1 (game data JSON schemas) without `FAIL` lines for the four files above.
|
||||
- [ ] No regression in p1-60 fog-of-war tests (re-run after any schema change: `cd src/simulator && cargo test -p mc-vision -p mc-player-api`).
|
||||
- [ ] If a schema is relaxed instead of data being backfilled, document the rationale in the schema file's header.
|
||||
|
||||
## Pointers
|
||||
|
||||
- p1-60 objective: `.project/objectives/p1-60-fog-of-war-testing-ai-fairness.md` (status: done).
|
||||
- Changelog entries for the closure: `.project/CHANGELOG.md` (three entries on 2026-05-18).
|
||||
- Game-data agent task map: `.claude/instructions/agents-task-map.md`.
|
||||
|
|
@ -315,3 +315,113 @@ is an empty array (the icon itself is the indicator).
|
|||
4. Once the gating tech is researched, decorations are replaced by the resource icon.
|
||||
|
||||
Renderer work for decorations is scheduled for the next cycle (godot-renderer).
|
||||
|
||||
---
|
||||
|
||||
## §9 Slot-Enabler Resources
|
||||
|
||||
The resources in §3 are tile-level yield resources — the player builds an improvement on
|
||||
the tile and the city worked-tile economy gains a yield. A second class of resources —
|
||||
**slot-enablers** — gate optional carrier slots and equipment slots on units at training
|
||||
time (see [`UNIT_LOGISTICS.md`](UNIT_LOGISTICS.md) §"Modular slots gated by tech × resource"
|
||||
and [`TECH_TREE.md`](TECH_TREE.md) §"Slot-enable table"). A slot-enabler may *also* be a
|
||||
yield resource (cattle, iron, coal already appear in §3); some, like `boars`, `crag_aerie`,
|
||||
`runestone`, are slot-only.
|
||||
|
||||
Slot-enablers carry the three-axis visibility schema from §1 and the same
|
||||
`improvement_required` field, plus one additional field `slot_targets` listing the
|
||||
unit-class or improvement slots they enable. A resource that is **only** a slot-enabler
|
||||
(no city yield) carries `yields_per_turn: {}` and `improvement_required: null`.
|
||||
|
||||
### Slot-enabler classification table
|
||||
|
||||
| ID | visibility | yield_gate | improvement_gate | Tier | Notes |
|
||||
|---|---|---|---|---|---|
|
||||
| `cattle` (existing §3, bonus) | `always` | `null` | `null` | T1 | Wild herds visible; husbandry tech enables ox-wagon slot |
|
||||
| `boars` | `always` | `null` | `null` | T1 | Wild boars visible from turn 1; mount slot via `animal_training` |
|
||||
| `mountain_rams` | `always` | `null` | `null` | T2 | Visible on hill/mountain biomes; mount slot via `animal_training` |
|
||||
| `crag_aerie` | `tech_gated` | `falconry_command` | `falconry_command` | T3 | Improvement built on a cliff/mountain tile; produces nesting crag-ravens |
|
||||
| `hold_aerie` | `tech_gated` | `falconry_command` (era 6 branch) | `falconry_command` | T6 | Era-6 successor to crag_aerie; produces hold-falcons |
|
||||
| `saltpeter` (existing §3, strategic) | `tech_gated` | `alchemy` | `alchemy` | T4 | Cave precipitation; powder_charges slot via `gunpowder` |
|
||||
| `sulfur` | `tech_gated` | `proto_chemistry` | `proto_chemistry` | T5 | Volcanic vents and sulfur springs; powder gate alongside saltpeter |
|
||||
| `coal` (existing §3, strategic) | `tech_gated` | `metallurgy` | `metallurgy` | T3 | Subsurface seams; firearm + steam_engine + powder gate |
|
||||
| `iron` (existing §3, strategic) | `tech_gated` | `bronze_working` | `bronze_working` | T2 | Surface ore once smelting begins; firearm + steam_engine gate |
|
||||
| `runestone` | `tech_gated` | `runelore` | `runelore` | T4 | Hill/mountain tile; rune_panel slot via `rune_resonance` |
|
||||
| `copper` (existing §3, luxury) | `always` | `bronze_working` | `bronze_working` | T2 | Surface visible; radio_set + coilgun gate |
|
||||
| `mithril` | `tech_gated` | `mithril_smithing` | `mithril_smithing` | T5 | Deep vein; coilgun slot via `coilgun_theory` |
|
||||
| `adamantine` | `tech_gated` | `adamantine_forging` | `adamantine_forging` | T10 | Mantle-depth; mantle_drill slot via `deep_mantle_engineering` |
|
||||
| `fusion_cell` | `tech_gated` | `fusion_theory` | `fusion_theory` | T10 | Manufactured, not mined; mantle_drill power source |
|
||||
|
||||
### Slot-target mapping
|
||||
|
||||
The same `slot_targets` field appears on every slot-enabler entry, listing the unit-class
|
||||
slots it gates. Values come from UNIT_LOGISTICS.md §"Modular slots gated by tech × resource".
|
||||
|
||||
| Resource | `slot_targets` |
|
||||
|---|---|
|
||||
| `cattle` | `["ox_wagon"]` |
|
||||
| `boars` | `["mount"]` |
|
||||
| `mountain_rams` | `["mount"]` |
|
||||
| `crag_aerie` | `["officer_bird"]` |
|
||||
| `hold_aerie` | `["hold_falcon"]` |
|
||||
| `saltpeter` | `["powder_charges"]` |
|
||||
| `sulfur` | `["powder_charges"]` |
|
||||
| `coal` | `["powder_charges", "firearm", "steam_engine"]` |
|
||||
| `iron` | `["firearm", "steam_engine"]` |
|
||||
| `runestone` | `["rune_panel"]` |
|
||||
| `copper` | `["radio_set", "coilgun"]` |
|
||||
| `mithril` | `["coilgun"]` |
|
||||
| `adamantine` | `["mantle_drill"]` |
|
||||
| `fusion_cell` | `["mantle_drill"]` |
|
||||
|
||||
### Depletion and scarcity
|
||||
|
||||
Slot-enablers obey the same depletion rules as yield resources where the rule applies.
|
||||
|
||||
- **Renewable** (no depletion): `cattle`, `boars`, `mountain_rams`, `crag_aerie`,
|
||||
`hold_aerie`, `runestone`. These are biological or geological-feature resources that
|
||||
do not exhaust in normal play.
|
||||
- **Slow-depletion** (depletes on heavy industrial extraction, era 7+): `coal`, `iron`,
|
||||
`copper`, `sulfur`, `saltpeter`. Depletion is era-and-yield gated by
|
||||
`industrial_extraction_depletion` in `combat_balance.json`; pre-industrial extraction
|
||||
is treated as renewable for game-length simulations.
|
||||
- **Apex / non-replenishable**: `mithril`, `adamantine`, `fusion_cell`. Mithril and
|
||||
adamantine are tier-locked deep-vein resources; fusion_cell is manufactured at a
|
||||
fusion plant (consumes power, not a tile).
|
||||
|
||||
Scarcity is a soft signal expressed via `scarcity_tier: T1..T10`. Lower-tier resources
|
||||
appear on more world tiles (T1 = abundant: every reasonable city has at least one);
|
||||
higher-tier resources are intentionally sparse (T8+ may appear on a handful of tiles
|
||||
worldwide, forcing trade or conquest).
|
||||
|
||||
### JSON entry shape
|
||||
|
||||
A slot-enabler resource carries the standard three-axis block plus the slot fields:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "boars",
|
||||
"category": "slot_enabler",
|
||||
"visibility": "always",
|
||||
"yield_gate": null,
|
||||
"improvement_gate": null,
|
||||
"improvement_required": null,
|
||||
"indicator_decorations": [],
|
||||
"yields_per_turn": {},
|
||||
"scarcity_tier": 1,
|
||||
"slot_targets": ["mount"],
|
||||
"tier": 1,
|
||||
"depletion": "renewable"
|
||||
}
|
||||
```
|
||||
|
||||
Where a resource is *both* a tile-yield resource and a slot-enabler (cattle, coal, iron,
|
||||
copper, saltpeter), the entry merges both shapes — its yield block and improvement
|
||||
remain from §3, and the `slot_targets` field is appended.
|
||||
|
||||
### Cross-references
|
||||
|
||||
- Slot semantics, training-time resolution: [`UNIT_LOGISTICS.md`](UNIT_LOGISTICS.md) §5, §"Modular slots gated by tech × resource"
|
||||
- Tech-gate pairings: [`TECH_TREE.md`](TECH_TREE.md) §"Slot-enable table"
|
||||
- Resource visibility three-axis schema: §1 above
|
||||
- Migration tool that populates per-unit slot entries: `tools/migrate-units-logistics.py`
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ TurnEvent::CapitalBlackoutEnded { player: PlayerId, turn: u32, new_capital_city_
|
|||
"capital_blackout": {
|
||||
"decay_multiplier": 0.5,
|
||||
"comm_tier_penalty": 1,
|
||||
"auto_promote_after_turns": 5
|
||||
"auto_promote_after_turns": 1
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue