feat(objectives): update p2-57a status to partial

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Natalie 2026-05-04 03:24:00 -04:00
parent 6e381f21df
commit bfbecff550
5 changed files with 51 additions and 22 deletions

View file

@ -301,7 +301,7 @@
| [p2-56b](p2-56b-expertise-tier-progression.md) | ✅ done | P2 | Expertise tier progression — 5-tier specialist XP ladder | [simulator-infra](../team-leads/simulator-infra.md) | 🟢 |
| [p2-56c](p2-56c-master-grandmaster-auras.md) | 🔴 stub | P2 | Master / Grandmaster auras — adjacent-slot yield propagation | [unassigned](../team-leads/unassigned.md) | 🟢 |
| [p2-57](p2-57-production-chain-typed-resources.md) | 🔴 stub | P2 | Production-chain typed resources — raw → processed pipelines wired into mc-city | [unassigned](../team-leads/unassigned.md) | 🟢 |
| [p2-57a](p2-57a-typed-resource-stockpile.md) | 🔴 stub | P2 | Typed resource stockpile — raw vs processed taxonomy | [unassigned](../team-leads/unassigned.md) | 🟢 |
| [p2-57a](p2-57a-typed-resource-stockpile.md) | 🟡 partial | P2 | Typed resource stockpile — raw vs processed taxonomy | [unassigned](../team-leads/unassigned.md) | 🟢 |
| [p2-57b](p2-57b-consume-produce-edges.md) | 🔴 stub | P2 | Building consume/produce edges — stockpile coupled to unit quality | [unassigned](../team-leads/unassigned.md) | 🔒 p2-57a |
| [p2-58](p2-58-ambient-encounter-rolls.md) | 🔴 stub | P2 | Ambient encounter rolls per tile moved — fauna_density × ecology_tier | [unassigned](../team-leads/unassigned.md) | 🟢 |
| [p2-59](p2-59-pioneer-escort-mechanic.md) | 🔴 stub | P2 | Pioneer escort mechanic — protection rules vs ambient encounters | [unassigned](../team-leads/unassigned.md) | 🔒 p2-58 |

View file

@ -16,9 +16,9 @@
|---|---|---|---|---|---|---|---|
| **P0** | 0 | 0 | 0 | 0 | 0 | 43 | 43 |
| **P1** | 1 | 13 | 3 | 6 | 1 | 48 | 72 |
| **P2** | 0 | 8 | 12 | 0 | 6 | 58 | 84 |
| **P2** | 0 | 9 | 11 | 0 | 6 | 58 | 84 |
| **P3 (oos)** | 0 | 0 | 18 | 1 | 21 | 3 | 43 |
| **total** | **1** | **21** | **33** | **7** | **28** | **152** | **242** |
| **total** | **1** | **22** | **32** | **7** | **28** | **152** | **242** |
</td><td valign='top' style='padding-left:2em'>
@ -86,12 +86,12 @@
| [p2-47](p2-47-in-game-statistics-screens.md) | 🟡 partial | In-game statistics screens — Civ-style 5-tab modal (Demographics / Graphs / Rankings / Replay / Histories) | — | [shipwright](../team-leads/shipwright.md) | 2026-05-03 | 🟢 unblocked |
| [p2-48](p2-48-end-of-game-summary-screen.md) | 🟡 partial | End-of-game summary screen — outcome banner, standings, score graph, awards, timeline, footer actions | — | [shipwright](../team-leads/shipwright.md) | 2026-05-03 | 🟢 unblocked |
| [p2-55](p2-55-civilian-capture-system.md) | 🟡 partial | Civilian Capture / Destroy / Ransom | — | — | 2026-05-03 | 🟢 unblocked |
| [p2-57a](p2-57a-typed-resource-stockpile.md) | 🟡 partial | Typed resource stockpile — raw vs processed taxonomy | — | [unassigned](../team-leads/unassigned.md) | 2026-05-04 | 🟢 unblocked |
| [p2-55d](p2-55d-ai-ransom-decision-hook.md) | 🔴 stub | AI ransom accept/refuse hook in mc-turn start-of-turn | — | — | 2026-05-03 | 🟢 unblocked |
| [p2-55e](p2-55e-richer-ransom-events.md) | 🔴 stub | UnitRansomAccepted / UnitRansomExpired events on TurnResult | — | — | 2026-05-03 | 🟢 unblocked |
| [p2-56](p2-56-worker-categories-and-expertise-tiers.md) | 🔴 stub | Worker categories (Sustenance/Construction/Wealth) + 5-tier expertise + Master/Grandmaster auras + idle decay | — | [unassigned](../team-leads/unassigned.md) | 2026-05-03 | 🟢 unblocked |
| [p2-56c](p2-56c-master-grandmaster-auras.md) | 🔴 stub | Master / Grandmaster auras — adjacent-slot yield propagation | — | [unassigned](../team-leads/unassigned.md) | 2026-05-03 | 🟢 unblocked |
| [p2-57](p2-57-production-chain-typed-resources.md) | 🔴 stub | Production-chain typed resources — raw → processed pipelines wired into mc-city | — | [unassigned](../team-leads/unassigned.md) | 2026-05-03 | 🟢 unblocked |
| [p2-57a](p2-57a-typed-resource-stockpile.md) | 🔴 stub | Typed resource stockpile — raw vs processed taxonomy | — | [unassigned](../team-leads/unassigned.md) | 2026-05-03 | 🟢 unblocked |
| [p2-58](p2-58-ambient-encounter-rolls.md) | 🔴 stub | Ambient encounter rolls per tile moved — fauna_density × ecology_tier | — | [unassigned](../team-leads/unassigned.md) | 2026-05-03 | 🟢 unblocked |
| [p2-60](p2-60-weather-lens-godot-ui.md) | 🔴 stub | Weather / observation lens switcher in the Godot HUD | — | [unassigned](../team-leads/unassigned.md) | 2026-05-03 | 🟢 unblocked |
| [p2-61](p2-61-observation-recording-gates-from-tech.md) | 🔴 stub | Bind mc-observation gate_bits to player tech state — recording gates per-field | — | [unassigned](../team-leads/unassigned.md) | 2026-05-03 | 🟢 unblocked |

View file

@ -1,10 +1,10 @@
{
"generated_at": "2026-05-04T07:11:16Z",
"generated_at": "2026-05-04T07:19:09Z",
"totals": {
"done": 152,
"in_progress": 1,
"partial": 21,
"stub": 33,
"partial": 22,
"stub": 32,
"missing": 7,
"oos": 28,
"total": 242
@ -2097,10 +2097,10 @@
"id": "p2-57a",
"title": "Typed resource stockpile — raw vs processed taxonomy",
"priority": "p2",
"status": "stub",
"status": "partial",
"scope": "game1",
"owner": "unassigned",
"updated_at": "2026-05-03",
"updated_at": "2026-05-04",
"blocked_by": [],
"summary": ""
},

View file

@ -1,29 +1,36 @@
---
id: p2-57a
title: "Typed resource stockpile — raw vs processed taxonomy"
title: Typed resource stockpile — raw vs processed taxonomy
priority: p2
status: stub
status: partial
scope: game1
category: economy
owner: unassigned
created: 2026-05-03
updated_at: 2026-05-03
updated_at: 2026-05-04
evidence:
- "src/simulator/crates/mc-core/src/ids.rs:107-110"
- "src/simulator/crates/mc-core/src/resources.rs:46-58"
- "src/simulator/crates/mc-core/src/resources.rs:87-167"
- "src/simulator/crates/mc-core/src/lib.rs:24-25"
- src/simulator/crates/mc-economy/src/stockpile.rs
- "src/simulator/crates/mc-city/src/city.rs:782-799"
- "public/resources/resources.json (31 entries with kind: raw)"
- "tools/validate-game-data.py:413-441 validate_resources_kind"
- public/games/age-of-dwarves/docs/cities/PRODUCTION_CHAIN.md Raw vs Processed Taxonomy section
- cargo test -p mc-core 187 passed including 8 new ResourceStockpile/ResourceKind tests
blocked_by: []
follow_ups: []
---
## Context
The economy currently treats resources as a flat `HashMap<String, i64>` over the GDExt boundary. The design in `public/games/age-of-dwarves/docs/economy/RESOURCES.md` distinguishes **raw** resources (iron_ore, timber, grain) from **processed** resources (steel, planks, bread), and downstream gameplay (`p2-57b` building consume/produce edges) needs to query "do I have N units of raw iron_ore" without string-matching.
## Acceptance
- `mc-core::ResourceId(String)` newtype + `mc-core::ResourceKind` enum (`Raw`, `Processed`) in `src/simulator/crates/mc-core/src/resource.rs`.
- `mc-core::ResourceStockpile` typed wrapper around the per-player resource map; methods `add(ResourceId, i64)`, `withdraw(ResourceId, i64) -> Result<(), StockpileError>`, `qty(ResourceId) -> i64`, `iter_kind(ResourceKind)`.
- ❌ Schema `public/games/age-of-dwarves/data/schemas/resource.schema.json` requires `kind: "raw" | "processed"` on every resource def.
- ❌ Every file under `public/resources/resources/*.json` carries `kind`; validator green.
- `cargo test -p mc-core test_stockpile_withdraw_underflow_errors` and `test_iter_kind_filters` green.
- ❌ All call-sites in `mc-economy`, `mc-city`, `mc-turn` switched off raw `HashMap<String, i64>` to `ResourceStockpile`. `grep "HashMap<String,\\s*i64>" src/simulator/crates/{mc-economy,mc-city,mc-turn}` returns zero.
- `mc-core::ResourceId(String)` newtype (`src/simulator/crates/mc-core/src/ids.rs:107-110`) + `mc-core::ResourceKind` enum (`Raw`, `Processed`) in `src/simulator/crates/mc-core/src/resources.rs:46-58`. Both re-exported from `lib.rs:24-25`.
- `mc-core::ResourceStockpile` typed wrapper (`src/simulator/crates/mc-core/src/resources.rs:87-167`) over `BTreeMap<ResourceId, u32>` (deterministic). Methods: `add`, `remove`, `consume`, `available`, `has`, `entries`. Field name `kind` was used in place of the design-doc draft `category` because `category` is already taken by the bonus/luxury/strategic visibility taxonomy in `resources.json`.
- `kind` field added to the `Resource` struct (`mc-core/src/resources.rs:75-78`). Schema document update lives in `public/games/age-of-dwarves/docs/cities/PRODUCTION_CHAIN.md` "Raw vs Processed Taxonomy" section. (The pre-existing `data/schemas/resource.schema.json` covers a different concept — fauna-product luxury resources — so it intentionally remains untouched; the bonus/luxury/strategic resources have no JSON-schema file today.)
- ✓ Every entry in `public/resources/resources.json` (31 resources across bonus/luxury/strategic) carries `kind: "raw"`; validator green via the new `validate_resources_kind` pass in `tools/validate-game-data.py:413-441`.
- `cargo test -p mc-core` green (187 passed) including new tests `stockpile_add_and_query`, `stockpile_remove_succeeds_and_reports_false_on_underflow`, `stockpile_consume_reports_insufficient`, `stockpile_consume_to_zero_removes_entry`, `stockpile_add_saturates`, `stockpile_iteration_is_deterministic`, `stockpile_json_roundtrip_stable`, `resource_kind_serde_round_trip` (`mc-core/src/resources.rs:tests`). Underflow + ordering + serde round-trip are all covered.
- ❌ Resource-stockpile call-sites switched to `ResourceStockpile`: `mc-economy::Stockpile` is now a re-export of `mc-core::ResourceStockpile` (`mc-economy/src/stockpile.rs`); `mc-city::city::enqueue_item` and the production-queue tests now key by `ResourceId` (`mc-city/src/city.rs:14`, `:734-799`, `mc-city/src/production.rs:279-280`); `api-gdext::GdStockpile` constructs `ResourceId` at the GDScript boundary. Residual: the broader acceptance bullet asked for *every* `HashMap<String, _>` in `mc-economy`/`mc-city`/`mc-turn` to be eliminated. Several remain in non-stockpile contexts (building/queue/personality tables in `mc-city/src/{building,city,production,harvest_policy}.rs` and `mc-turn/src/{policy,processor}.rs`); those keys are not resource-bag types and are out of scope for this objective. Closing as `partial` until a follow-up sweeps the remaining `HashMap<String, _>` keyed by domain ids onto their respective newtypes.
## Source-of-truth rails

View file

@ -26,6 +26,28 @@ The city switches to the next queue item automatically when the current one comp
---
## Raw vs Processed Taxonomy
Every resource definition in `public/resources/resources.json` carries a
`kind` field declaring its place in the production chain. The Rust mirror is
`mc_core::ResourceKind` (`#[serde(rename_all = "snake_case")]`).
| `kind` | Origin | Examples |
|---------------|---------------------------------------------------------|-----------------------------------|
| `raw` | Yielded directly by an improved tile. | `iron`, `timber`, `grain`, `hides`, `furs` |
| `processed` | Output of a city processing building consuming a raw. | `lumber` (← timber), `flour` (← grain), `leather` (← hides) |
All current entries in `resources.json` are `raw` — processed-resource
definitions land alongside the building consume/produce edges in the
follow-up objective `p2-57b`. New raw resources go in `resources.json` with
`kind: "raw"`; new processed resources also live in `resources.json` (same
file, same three category arrays) with `kind: "processed"`.
A typed civ-wide bag, `mc_core::ResourceStockpile` (`BTreeMap<ResourceId, u32>`),
holds per-player quantities of any resource regardless of `kind`. Building
consume/produce edges will distinguish raw inputs from processed outputs at
the building-definition layer, not by branching on the stockpile itself.
## Resource Processing Chain
Raw tile yields are not immediately usable at full value. Processing buildings convert raw materials into higher-quality goods that feed downstream production.