From 07fb66608a7253bd8404957ea2f91c6bd0f77209 Mon Sep 17 00:00:00 2001 From: megaproxy Date: Tue, 12 May 2026 13:37:21 +0100 Subject: [PATCH] Decision: remove rest from NEEDS_CATEGORIES so work fires before fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NEEDS_CATEGORIES used to be [&"rest", &"eat", &"sleep"]. Decision iterates needs providers before eligible work providers and picks the first one that returns a non-null job. EatProvider/SleepProvider correctly gate on hunger/sleep thresholds (return null when not hungry/tired), so they yield to work when no need is pressing. But RestProvider always returns a job — by design, it's the catch-all fallback ("stand here"). With "rest" in NEEDS_CATEGORIES the loop preempted on RestProvider every tick: pawns assigned 'Rest at (50, 50)' and never reached the chop/mine/construction providers despite valid designations. Fix: remove &"rest" from NEEDS_CATEGORIES. RestProvider falls into the eligible bucket; its provider.priority=0 sorts it last in the eligible sort (chop=5, mine/construction=5, etc, win the priority tiebreaker). work_priorities doesn't include a "rest" key so priorities.get falls through to NORMAL=3, keeping rest eligible for everyone (the UI matrix deliberately omits rest per Pawn.work_priorities comment). Verified MCP runtime: fresh boot, all 3 pawns picked 'Build stone wall at (44, 28)' instead of 'Rest at (50, 50)'; advanced to next wall site within 5 seconds. Bug surfaced by first real playtest with painted designations — the in-context audit caught it within ~5 min of inspection. Co-Authored-By: Claude Opus 4.7 (1M context) --- scenes/ai/decision.gd | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/scenes/ai/decision.gd b/scenes/ai/decision.gd index deec5e0..dd63fac 100644 --- a/scenes/ai/decision.gd +++ b/scenes/ai/decision.gd @@ -41,14 +41,21 @@ static func pick_next_job(pawn, work_providers: Array) -> Job: # ── Layer 4: Work providers ────────────────────────────────────────────── # Needs-driven categories are handled entirely by Layer-3 status interrupts - # and need-threshold providers (rest/eat/sleep/doctor fire when hunger/sleep + # and need-threshold providers (eat/sleep/doctor fire when hunger/sleep # thresholds trigger, not via player priority). We skip the priority filter # for them so a pawn can never accidentally starve because the player set # &"eat" to OFF. The player-configurable list is the 7 work categories: # construction / chop / plant / mine / crafting / haul / clean # Doctor IS in the matrix (player can opt a pawn out of doctor duty) but # the needs-driven "go heal yourself" path bypasses this filter at Layer 3. - const NEEDS_CATEGORIES: Array = [&"rest", &"eat", &"sleep"] + # + # Rest is NOT a need-gated category — RestProvider always returns a job (its + # job IS "stand here"), so if rest ran before elective work, pawns would + # never chop/mine/build. Rest is the eligible-bucket fallback: it sorts last + # because provider.priority=0, so any real work wins. Bug ref: 2026-05-12 + # session — pawns idled with valid chop/mine/build designations because + # &"rest" was in NEEDS_CATEGORIES and RestProvider preempted everything. + const NEEDS_CATEGORIES: Array = [&"eat", &"sleep"] # Pawn's work_priorities dict — empty dict if the field is absent (pre-Phase-17 # pawns loaded from old saves). Missing category key defaults to 3 (NORMAL) so