diff --git a/memory.md b/memory.md index c0b40ce..844044c 100644 --- a/memory.md +++ b/memory.md @@ -330,6 +330,34 @@ Same scope as locked in `~/claude/ideas/rimlike/plan.md`. Realistic timeline 3 - **Pattern recorded — "ingredient2 inversion: primary is carried, secondary is buffered".** The two-trip craft refactor (commit d9638a4) settled on: `recipe.ingredient_type` = the carried (primary) ingredient, `recipe.ingredient2_type` = the buffered (secondary, may be multi-count) ingredient. For cremation this is corpse (carried) + 5 wood (buffered across multiple pickup/deposit trips). Workbench.deposited_inputs Dictionary holds the buffered count. JobRunner._tick_craft validates buffer at full count, consumes both at completion. Pawn carry slot stays single-stack. `Workbench._last_consumed_ingredient` transient field captures the carried item before queue_free so signal consumers (cremation_pyre.on_craft_complete → corpse_cremated) get a non-null ref. - **Delegation report — audit + 5-sprint day.** Five `researcher` (Haiku) for the initial audit fan-out. Across the five fix-sprints: 12 `gdscript-refactor` (Sonnet) dispatches, 1 `quick-edit` (Haiku) for the J+M mechanical batch. Opus handled all pre-write contracts, integration verification, the cross-agent conflict resolution, and all 6 commits. Tiered system fired naturally across both axes (audit + execution). +### 2026-05-17 + +- **Hyena reskin shipped** (commit `f30c7a8`). Replaced procedural wolf draw with CraftPix Free Desert Enemy Sprite Sheets — 48×48 side-view, 4-frame idle + 6-frame walk. AnimatedSprite2D mounted in Wolf.setup() + from_dict() (same pattern as pawn reskin Slice 1). Player-facing copy renamed wolf→hyena in strings.gd + event_catalog.gd EventDef titles/bodies. Internal class names (Wolf, World.wolves, EventBus.wolf_spawned, event IDs like `lone_wolf`) preserved for save compat — explicit comment in wolf.gd. MCP-verified: hyena AnimatedSprite2D mounts on spawn, idle anim plays, storyteller modal renders "Lone Hyena — A starving hyena circles your livestock." Memory.md asset audit had said "no wolf in bundle" — this session's fresh scan via researcher (Haiku) found the CraftPix-DesertEnemies pack sitting next to the Humble bundle. Lesson: original asset audit was incomplete. +- **Pattern recorded — "rename player-facing, preserve internal identifiers".** When changing entity flavor (wolf → hyena, future renames), edit display strings only (strings.gd + EventDef labels). Keep class names, registry fields, signals, save class_ids, event IDs the same to avoid breaking saves + cross-system wiring. Header comment in the entity file explains the historical naming. + +- **Cooking pipeline starvation fix shipped** (commit `87a7beb`) after playtest report "pawns starve even with harvested crops." Root cause: `CraftingProvider` (category=&"crafting", priority=4) handled BOTH crafting-skill bills AND cooking-skill bills. Decision tiebreaker (lower pawn-priority wins; tie → higher provider.priority wins) ranked Plant=5 / Chop=5 ABOVE Crafting=4, so pawns endlessly harvested fresh crops instead of cooking ones already on the floor. Raw +25 vegetable couldn't outpace HUNGER_DECAY × 3 pawns; colony starved on a pile of uncooked food. +- **Fix**: split `CookingProvider` out of `CraftingProvider`. Same find/score logic, including ingredient2 buffer flow. CookingProvider has `category=&"cooking"`, `priority=6` (above Plant/Chop), filters bills by `required_skill == &"cooking"`. CraftingProvider now filters bills by `required_skill == &"crafting"`. Added `&"cooking": 3` to `pawn.work_priorities` defaults (was missing — 8 keys vs design spec's 9). WorkPriorityMatrix gains a "Cook" column. MCP-verified: 2 bread items appeared by tick 261 of fresh boot. +- **Pattern recorded — "provider-priority eclipse"**. When multiple providers share a category (like crafting+cooking did) AND default pawn-priorities are equal, the decision tiebreaker uses provider.priority descending. Always-available higher-priority work eclipses batch-style lower-priority work. Same root cause hit cooking (eclipsed by plant/chop) and hauling (eclipsed by everything). Phase 6 placeholder priorities flagged for full Phase 20 retune. Going forward: any new provider needs to land at a priority that doesn't starve under realistic always-busy load. Audit ALL providers when adding one. + +- **Sow + crop zone designation shipped** (commit `c6c88ac`) after playtest report "pawns aren't replanting crops + need a way to designate new crop areas." Two issues: (a) `_find_sow` required a TYPE_GRAIN item as seed but Millstone's flour bill FOREVER consumed all grain before sow could claim it (especially with CookingProvider now priority 6 creating constant flour demand); (b) no UI for player to designate new crop tiles. +- **Fix**: removed grain requirement entirely. Sow is now Rimworld-style — the designation triggers work; no input consumed. _find_sow returns a 2-toil walk → interact job. Crop.on_sow_tick flips stage to SOWN. Plus 4 new BuildDrawer paint tools (Wheat/Potato/Corn/Strawberry) in a new "Farm" section column. Painting a grass tile spawns a TILLED Crop entity; PlantProvider sow then picks it up. Tile validity: grass + walkable + no existing crop/tree. MCP-verified: 12 forced-TILLED crops fully cycled TILLED → SOWN → growth → READY → harvest. Paint tool spawned wheat at (35, 30); wall tile at (44, 23) correctly rejected. +- **Pattern recorded — "input cost on a routine work toil starves under contention"**. Original sow design consumed 1 grain (matching the design-doc feel of "seed cost"), which seemed fine in isolation. Under multi-provider load (cooking demanding grain too), the input cost became a contention bottleneck. Rimworld's "designation triggers work, no input cost" pattern avoids the contention entirely. Apply for future work types that compete for the same item pool. + +- **Hauling priority bump 3 → 5 shipped** (commit `ab53808`) after playtest report "where is all the bread and meals going? Not in the crate." Cooking was working (verified); output spawned at the Hearth tile and never hauled. Same eclipse pattern: HaulingProvider priority 3 was below every gathering/production provider (Plant=5, Chop=5, Cooking=6, Construction=6, Crafting=4, Mine=4). With 3 pawns + constant production, no one ever reached "idle enough to haul." EatProvider (7) also ate food directly off the workbench tile. +- **Fix**: 1-line bump to priority 5 (same tier as Plant and Chop). MCP-verified: 1 grain + 1 wood arrived in cabin crate within 3000 ticks; pawns visibly mid-haul. Cooking still fires in parallel. + +- **Reachability pre-check sprint partial** (commit `16e04e4`). Researcher audit (Haiku) found 6 WorkProviders missing reachability gates before returning jobs: cooking, crafting, plant-harvest, sleep, chop, mine. Gap class: pawn offered doomed walk-job → JobRunner cancels each tick → Decision re-offers same job → 20Hz busy-spin starves lower-priority work. Same root pattern as the cooking starvation. Dispatched Sonnet to add all 6. +- **4 landed, 2 reverted**. PlantHarvest, Sleep, Chop, Mine all got safe reachability gates (mirroring Pattern A from HaulingProvider/EatProvider for walkable targets, Pattern B from ConstructionProvider for impassable ones). Cooking + Crafting changes had to be reverted: they intermittently returned null in live sim despite all manual MCP-probe conditions passing — likely an edge in the adjacent-walkable computation under sim-tick contention. Filed for a smaller, more careful follow-up. +- **Pattern recorded — "MCP probe context vs live sim context can diverge"**. Manually called `cooking_provider.find_best_for(pawn)` showed all checks pass (ingredient reachable, workbench approach reachable). But the LIVE sim returned null for the same call shortly after. Items get carried, claims toggle, paths invalidate within ticks. For stateful providers, don't fully trust isolated probes — verify by observing aggregate outcomes (items produced, jobs fired in audit log) over many ticks. + +- **Provider audit findings preserved** (deferred to Phase 20): + - Construction = Cooking = 6 tie → Construction always fires first (stable sort + input order). Player won't notice unless both have queued work simultaneously. + - Plant = Chop = Haul = 5 → harvest > chop > haul in tiebreaker order. Wood briefly piles up at tree tiles during early game. + - Cleaning (priority 2) → never fires while higher-priority work exists. Rooms get grimy. Phase 20 tuning territory. + - No CombatProvider (Phase 10 partial — pawn-side combat deferred per earlier memory). + +- **Delegation report — 2026-05-17 playtest fix day.** Five `gdscript-refactor` (Sonnet) dispatches across 5 sprints (hyena reskin, CookingProvider split, sow + crop zone, reachability sprint, audit-driven fixes). Two `researcher` (Haiku) dispatches: wild-beast sprite hunt across all asset packs (found CraftPix Hyena), provider audit. Opus handled all live MCP probes, pre-write contracts, integration verification, the cooking/crafting revert decision, and all 6 commits. Trust-but-verify proved its keep AGAIN: the Smelter/Millstone/Hearth audit yesterday was wrong (workbenches already wired); today the agent's claim "cooking/crafting reachability works" was wrong (live sim regressed). Always verify in MCP if the change touches scheduling. + ## External references - **Forgejo repo:** https://git.rdx4.com/megaproxy/rimlike (private)