v0.2.0-rc.2: P0 hardening — Pi headless, test isolation, advice fixes #21

Merged
halofourteen merged 1 commits from feat/v0.2.0-rc.2-hardening into main 2026-05-27 14:10:28 +03:00
halofourteen commented 2026-05-27 13:57:09 +03:00 (Migrated from github.com)

Summary

P0 hardening patch on top of rc.1, addressing four real bugs spotted from
live observation + adding the self-reflection loop the operator asked
for.

Bugs fixed

  1. Pi subprocess opens second MC connection. When the hybrid runtime
    spawns pi -p \"...\" for banter / coach / planner, the loaded
    extensions/mineflayer-bridge.ts calls connect(\"startup\") and
    races for the nickname. PEPA_HEADLESS=1 env (set by
    runtime/pi-bridge.js) now makes the bridge skip its connect.

  2. Tests poison live state. runtime/log.js, scenario-memory.js,
    world-journal.js, and knowledge/store.js all key off
    config.stateDir. Under npm test that resolved to the live
    state/<host>/, so test rows ended up in real scenarios.jsonl.
    config.js now detects node test context (or PEPA_STATE_DIR
    override) and redirects to /tmp/pepa-test-state-<pid>/. ~550
    historical test rows cleaned from live state in this commit.

  3. defendReflex marks lesson failed too early. Combat advice override
    used to call reportAdviceOutcome({succeeded:false}) before the
    flee skill returned. The creeper-rule lesson got
    applied_count=2, succeeded_count=0 not because the lesson is bad
    but because we marked it bad pre-emptively. Now dispatchDefendFlee
    carries lessonId and reports the actual flee outcome.

  4. Pi-coach mode-name leak. Coach lessons sometimes set
    prefer_skill: \"night_shelter\" or self_preservation (those are
    mode names, not skill ids), so they failed SAFE_OVERRIDES and
    silently fell to avoid instead of override.
    normalisePreferSkill in coach/advice.js translates mode names
    and underscore-shapes to canonical skill ids.

New behavior

  1. Self-reflection loop (runtime/coach/reflect.js). Every 30 min
    Pi gets asked: "Are you making progress, or in a loop? What should
    you do?" Reply parsed into verdict + summary + next-action + new
    lessons. Reflection written to state/<host>/reflections/<ts>.md;
    lessons land in knowledge.lessons with source=\"pi-reflect\".
    Rate-limited 2 calls/hour.

Test plan

  • npm test — 246/246 green (was 237; +9 advice/reflect coverage).
  • Verified empirically: after the config fix, npm test adds 0
    rows to the live scenarios.jsonl.
  • extensions/mineflayer-bridge.ts typecheck — diff only adds an
    early-return guard.

Followups (rc.3 candidates)

  • Wedged-pit emergency policy: at low HP + no food + no movement, force
    village.choose-base or survive.sleep instead of explore.far.
  • Promote village.choose-base early in the curriculum when bot's been
    stuck in same chunk > N minutes.
  • Tool-progression auto-craft: if gather.stone returns missing_tool,
    curriculum should auto-dispatch craft.wooden-pickaxe.
## Summary P0 hardening patch on top of rc.1, addressing four real bugs spotted from live observation + adding the self-reflection loop the operator asked for. ### Bugs fixed 1. **Pi subprocess opens second MC connection.** When the hybrid runtime spawns `pi -p \"...\"` for banter / coach / planner, the loaded `extensions/mineflayer-bridge.ts` calls `connect(\"startup\")` and races for the nickname. `PEPA_HEADLESS=1` env (set by `runtime/pi-bridge.js`) now makes the bridge skip its connect. 2. **Tests poison live state.** `runtime/log.js`, `scenario-memory.js`, `world-journal.js`, and `knowledge/store.js` all key off `config.stateDir`. Under `npm test` that resolved to the live `state/<host>/`, so test rows ended up in real `scenarios.jsonl`. `config.js` now detects node test context (or `PEPA_STATE_DIR` override) and redirects to `/tmp/pepa-test-state-<pid>/`. ~550 historical test rows cleaned from live state in this commit. 3. **defendReflex marks lesson failed too early.** Combat advice override used to call `reportAdviceOutcome({succeeded:false})` *before* the flee skill returned. The creeper-rule lesson got `applied_count=2, succeeded_count=0` not because the lesson is bad but because we marked it bad pre-emptively. Now `dispatchDefendFlee` carries `lessonId` and reports the actual flee outcome. 4. **Pi-coach mode-name leak.** Coach lessons sometimes set `prefer_skill: \"night_shelter\"` or `self_preservation` (those are mode names, not skill ids), so they failed `SAFE_OVERRIDES` and silently fell to `avoid` instead of `override`. `normalisePreferSkill` in `coach/advice.js` translates mode names and underscore-shapes to canonical skill ids. ### New behavior 5. **Self-reflection loop** (`runtime/coach/reflect.js`). Every 30 min Pi gets asked: \"Are you making progress, or in a loop? What should you do?\" Reply parsed into verdict + summary + next-action + new lessons. Reflection written to `state/<host>/reflections/<ts>.md`; lessons land in `knowledge.lessons` with `source=\"pi-reflect\"`. Rate-limited 2 calls/hour. ## Test plan - [x] `npm test` — 246/246 green (was 237; +9 advice/reflect coverage). - [x] Verified empirically: after the config fix, `npm test` adds 0 rows to the live `scenarios.jsonl`. - [x] `extensions/mineflayer-bridge.ts` typecheck — diff only adds an early-return guard. ## Followups (rc.3 candidates) - Wedged-pit emergency policy: at low HP + no food + no movement, force `village.choose-base` or `survive.sleep` instead of `explore.far`. - Promote `village.choose-base` early in the curriculum when bot's been stuck in same chunk > N minutes. - Tool-progression auto-craft: if `gather.stone` returns `missing_tool`, curriculum should auto-dispatch `craft.wooden-pickaxe`.
Sign in to join this conversation.