feat(runtime): fully autonomous self-healing — no operator approval #10

Merged
halofourteen merged 1 commits from feat/autonomous-self-healing into main 2026-05-25 16:56:03 +03:00
halofourteen commented 2026-05-25 16:56:00 +03:00 (Migrated from github.com)

Why

Operator: "бот должен быть полностью автономным — сам себя улучшать и чинить, в этом и есть смысл; пока что он стоит на месте и кидает proposals на каждый чих — это кардинально не то что я хочу".

Changes

  1. Proposal trigger filter — `runtime/bot.js` classifies the failure detail into bug / timeout / feature-gap / other. Trigger fires only on bugs (TypeError / Cannot read / is not defined) or persistent same-op timeouts. Feature gaps like `no reachable log` / `no food` / `no bed` are skipped — reflex routing handles those. Threshold raised 3→5.

  2. Auto-apply — `runtime/auto-improve.js` polls `state//proposals/` every 2s with a 10s settle debounce; spawns `scripts/auto-patch.js` detached. The patcher creates `auto/` branch, runs `pi -p` (10 min timeout), and cherry-picks onto main only if every changed file is under `runtime/`. No push, no PR. Rate limits: 15 min between runs + 4/hour cap.

  3. Auto-rollback — `runtime/supervisor.js` watches restart frequency. >5 restarts/min AND last commit younger than 15 min AND touched `runtime/` ⇒ `git reset --hard HEAD~1`, reset counters, retry. Up to 3 rollbacks per supervisor lifetime then bails out.

  4. current-task.json slim — drop the full snapshot embedding, keep only label/status/position. Slim snapshot still goes into proposals for LLM context.

  5. Docs rewrite — `docs/runtime.md` self-improvement section reflects the new contract end-to-end.

Loop diagram

fail → classify → 5-in-a-row of bugs/timeouts → proposal.md →
  auto-improve poll → debounce 10s → auto-patch.js →
  branch + pi -p + cherry-pick → supervisor reloads on runtime/*.js change
  → if child crashes 5×/min on fresh commit → rollback → restart

Manual escape hatches retained but rarely needed

  • TUI `y` to peek at a proposal
  • `npm run propose:apply` for attended version (no auto cherry-pick)
  • `npm run stop` to kill everything

Test plan

  • Imports load (sanity check passed)
  • Stale proposals from earlier smoke tests cleared
  • Live: start `npm run bot`, force a TypeError in actions.js, verify autopatch loop kicks in and rolls back if patch broken
  • Live: verify that "no food in inventory" no longer triggers proposals (it's a feature gap)

Follow-up (next PR)

Crafting actions + tech-tree reflex + LLM planner driving `state//plan.md` toward the "процветающая деревня с хозяйством" goal.

🤖 Generated with Claude Code

## Why Operator: "бот должен быть полностью автономным — сам себя улучшать и чинить, в этом и есть смысл; пока что он стоит на месте и кидает proposals на каждый чих — это кардинально не то что я хочу". ## Changes 1. **Proposal trigger filter** — \`runtime/bot.js\` classifies the failure detail into bug / timeout / feature-gap / other. Trigger fires only on bugs (TypeError / Cannot read / is not defined) or persistent same-op timeouts. Feature gaps like \`no reachable log\` / \`no food\` / \`no bed\` are skipped — reflex routing handles those. Threshold raised 3→5. 2. **Auto-apply** — \`runtime/auto-improve.js\` polls \`state/<host>/proposals/\` every 2s with a 10s settle debounce; spawns \`scripts/auto-patch.js\` detached. The patcher creates \`auto/<slug>\` branch, runs \`pi -p\` (10 min timeout), and cherry-picks onto main only if every changed file is under \`runtime/\`. No push, no PR. Rate limits: 15 min between runs + 4/hour cap. 3. **Auto-rollback** — \`runtime/supervisor.js\` watches restart frequency. >5 restarts/min AND last commit younger than 15 min AND touched \`runtime/\` ⇒ \`git reset --hard HEAD~1\`, reset counters, retry. Up to 3 rollbacks per supervisor lifetime then bails out. 4. **current-task.json slim** — drop the full snapshot embedding, keep only label/status/position. Slim snapshot still goes into proposals for LLM context. 5. **Docs rewrite** — \`docs/runtime.md\` self-improvement section reflects the new contract end-to-end. ## Loop diagram ``` fail → classify → 5-in-a-row of bugs/timeouts → proposal.md → auto-improve poll → debounce 10s → auto-patch.js → branch + pi -p + cherry-pick → supervisor reloads on runtime/*.js change → if child crashes 5×/min on fresh commit → rollback → restart ``` ## Manual escape hatches retained but rarely needed - TUI \`y\` to peek at a proposal - \`npm run propose:apply\` for attended version (no auto cherry-pick) - \`npm run stop\` to kill everything ## Test plan - [x] Imports load (sanity check passed) - [x] Stale proposals from earlier smoke tests cleared - [ ] Live: start \`npm run bot\`, force a TypeError in actions.js, verify autopatch loop kicks in and rolls back if patch broken - [ ] Live: verify that "no food in inventory" no longer triggers proposals (it's a feature gap) ## Follow-up (next PR) Crafting actions + tech-tree reflex + LLM planner driving \`state/<host>/plan.md\` toward the "процветающая деревня с хозяйством" goal. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.