docs(SOUL): §6 Failure Recovery — pattern-match details + decide by player intent - #20
Open
Pablomonte wants to merge 1 commit into
Conversation
… player intent The previous §6 promised three canonical error_types to the captain LLM: "target_occupied", "no_solid_neighbor", "bot_in_target". These are referenced in agents/local_agent/embodied.py (SPATIAL_ERRORS set) and used to gate Tier 2a auto-retry. But the embodied service dispatcher (foldBotResponse in lib/dispatcher.js) collapsed ALL bot errors to a generic `error_type: "bot_action_failed"`. The canonical labels were never emitted, so the captain's recovery path keyed on them was dead. The bug is preexisting upstream — neither the dispatcher nor the bot re-classified placement failure strings into canonical error_types, so the recovery contract the SOUL described did not match runtime reality. This commit closes the gap at the SOUL layer (lowest blast radius — zero code change, deploys via profile sync). Two things change: 1. **Pattern-match `details` rather than `error_type`.** The captain is taught to read the bot's free-text diagnostic string against a 9-row catalog of real bot phrases. Each pattern was verified against the actual error throw site in agents/bot/server.js. 2. **Spatial recovery: think before relocating.** The first iteration of this SOUL listed "place at adjacent cell" as the default response to `target_occupied`. Field test exposed the flaw: the original coordinate often carried player intent (sealing a hole, hitting a named cell, completing a structure). Silently placing one cell over is a worse failure than refusing — it leaves the player with an incorrect world AND the false belief the task succeeded. New shape: §6 starts with a "pause and decide" checklist asking whether the cell was load-bearing, approximate, or just blocked by the body. The table lists OPTIONS, not prescriptions. Default tie-breaker is "ask the player" via a short chat message. Pattern table (each row anchored in a real bot string): | pattern in details | source | |-----------------------------------|--------------------------------------| | target space is occupied | server.js:2363 (place) | | inside my own body / footprint | server.js:2354 (place — PR nicoechaniz#17) | | no solid adjacent block / against | server.js:2407 + 2358 (place) | | did not materialize | server.js:2343 (place) | | No {item} in inventory | server.js:2227 + 2317 (equip/place) | | crafting_table nearby | server.js:2163, 2169 (craft_item) | | Mined K/N | dispatcher.js:detectSoftFailure | | Can't ... / Failed to ... | bot soft-failure prefix | | timeout | generic | §1 worked example also rewritten: instead of silently relocating to an adjacent cell, the captain now thinks aloud about whether relocation serves the player's intent — and asks if it doesn't. Companion PR with the dispatcher-side fix that ALSO emits canonical error_types (so SOUL pattern matching + canonical error_types both work, defense-in-depth): nicoechaniz#19 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Rewrites §6 of `agents/embodied-service/profile-templates/daemoncraft-base.SOUL.md` so the captain LLM's recovery contract matches runtime reality and stops silently relocating placements that carried player intent.
What was wrong
The previous §6 promised three canonical error_types — `target_occupied`, `no_solid_neighbor`, `bot_in_target` — that the runner's Tier 2a auto-retry block (`agents/local_agent/embodied.py:SPATIAL_ERRORS`) is keyed on. But the embodied service dispatcher (`foldBotResponse` in `lib/dispatcher.js`) collapsed every bot error to a generic `bot_action_failed`. The canonical labels were never emitted, so the recovery contract the SOUL described did not match what the captain actually saw at runtime.
Field test exposed a second issue with the first iteration of this rewrite: the catalog listed "place at adjacent cell" as the default for `target_occupied`. The original coordinate often carried player intent (sealing a hole, hitting a named cell, completing a structure). Silently placing one cell over is a worse failure than refusing — it leaves the player with an incorrect world AND the false belief the task succeeded.
What changes
Pattern-match `details` rather than `error_type`. The captain is taught to read the bot's free-text diagnostic string against a 9-row catalog of real bot phrases. Each pattern was verified against the actual error throw site in `agents/bot/server.js`.
Spatial recovery: pause and decide. Added a "think first" checklist before any spatial recovery:
§1 worked example rewritten to show "think aloud" before relocating, including an example where the right answer is a chat message back to the player rather than a placement workaround.
Pattern table (each row anchored in a real throw site):
Companion PR
DC #19 — dispatcher classifier that promotes the bot's diagnostic to canonical `error_type` upstream. With that merged, the captain has BOTH a canonical error_type (for runner auto-retry) AND the SOUL pattern catalog (for cases the classifier doesn't cover). This SOUL PR works on its own and degrades gracefully — but the two together close the loop end-to-end.
Test plan
🤖 Generated with Claude Code