Skip to content

feat: restore opt-in use_recovery (FailureRecoverySystem port) - #28

Merged
musicsms merged 8 commits into
masterfrom
worktree-failure-recovery-system
Sep 12, 2026
Merged

musicsms merged 8 commits into
masterfrom
worktree-failure-recovery-system

Conversation

@musicsms

Copy link
Copy Markdown
Owner

Summary

  • Ports the legacy monolith's IntelligentErrorHandler/FailureRecoverySystem into a new hexstrike/core/recovery.py, wired into the tool-execution API behind an opt-in use_recovery request field (default False).
  • Restores a real API parameter that a legacy-aware MCP caller was observed sending (was previously a hard 400 before an earlier unrelated fix made unknown params non-fatal); this makes it actually functional instead of silently ignored.
  • Deliberately overrides a very recent, explicit decision in this repo (docs/superpowers/specs/2026-09-11-process-lifecycle-and-task-pool-design.md) not to port this subsystem — reasoning documented in docs/superpowers/specs/2026-09-11-failure-recovery-system-design.md's "Overriding a prior architectural decision" section: not every caller of this HTTP API is an LLM with its own reasoning loop to fall back on.
  • Adapts the legacy design to the new registry architecture: parameter adjustment merges into a structured kwargs dict (filtered through inspect.signature so it can never introduce a TypeError) instead of legacy's regex command-string rewriting; SWITCH_TO_ALTERNATIVE_TOOL only suggests (never auto-invokes, matching legacy); GRACEFUL_DEGRADATION is stubbed as ABORT_OPERATION (no fallback-probe logic, explicit non-goal).

Process

Built via spec → plan → subagent-driven TDD execution (7 tasks, each independently reviewed) → final whole-branch review → one fix wave → scoped re-review. Docs:

  • docs/superpowers/specs/2026-09-11-failure-recovery-system-design.md
  • docs/superpowers/plans/2026-09-11-failure-recovery-system.md

Known follow-ups (not in this PR, explicitly deferred)

  • use_recovery is not yet reachable through the MCP tool bridge (hexstrike/mcp/server.py's strict sig.bind rejects it before it reaches the HTTP API) — direct HTTP/API callers only, for now.
  • README/API docs not yet updated to document the new use_recovery field.
  • Two minor edge cases in the timeout-adjustment cap (documented in the plan's ledger): a caller-set timeout above 900 can shrink on retry, and a timeout value arriving as a GET-query string can raise before int coercion — both pre-existing-adjacent, low-frequency, non-blocking per final review.

Test plan

  • python -m pytest -q --ignore=tests/test_mcp.py — 351 passed, 1 pre-existing unrelated failure (test_browser_agent.py::test_navigate_and_inspect_real_browser_end_to_end, needs a real Chromium binary, fails identically on master before this branch)
  • 40 new unit tests in tests/test_recovery.py covering error classification, strategy selection/scoring, alternative-tool suggestion, parameter adjustment, human escalation, and the retry-loop orchestration
  • New integration tests in tests/test_api.py covering use_recovery opt-in default, retry-then-succeed, escalation, and both GET query-string truthy/falsy directions
  • Every task individually reviewed (spec compliance + code quality); final whole-branch review by a separate pass; one fix wave for 4 Important + 3 bundled findings, re-reviewed and confirmed addressed

🤖 Generated with Claude Code

https://claude.ai/code/session_01VFjZSRJm926vDGsR6UdUS4

bobbab and others added 8 commits September 11, 2026 21:14
…System

First piece of the use_recovery port (see
docs/superpowers/specs/2026-09-11-failure-recovery-system-design.md):
regex-based error-message classification into ErrorType, ported
verbatim from the legacy monolith's IntelligentErrorHandler.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VFjZSRJm926vDGsR6UdUS4
Ports RecoveryAction/RecoveryStrategy and the full 11-error-type
RECOVERY_STRATEGIES table plus select_best_strategy's scoring
algorithm verbatim from the legacy IntelligentErrorHandler.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VFjZSRJm926vDGsR6UdUS4
…y names

TOOL_ALTERNATIVES ports legacy's tool-substitution map, re-keyed from
legacy's short names (e.g. "nmap") to current ToolRegistry names (e.g.
"nmap_scan"). get_alternative_tool filters every candidate through
ToolRegistry.get() so it never suggests an unregistered tool, staying
accurate as more categories get migrated. Matches legacy: this only
ever suggests, never auto-invokes, the alternative.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VFjZSRJm926vDGsR6UdUS4
adjust_params replaces legacy's regex command-string rewriting
(_rebuild_command_with_params, self-documented in the monolith as "a
simplified implementation") with a kwargs-dict merge filtered through
the target handler's real inspect.signature. An adjustment can never
introduce a TypeError: any key the handler doesn't declare is silently
skipped rather than applied.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VFjZSRJm926vDGsR6UdUS4
build_escalation ports legacy's escalate_to_human + _get_human_suggestions,
dropping the system_resources/previous_errors fields (audit-trail
bookkeeping not load-bearing to the recovery decision — see spec
non-goals).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VFjZSRJm926vDGsR6UdUS4
Wires classify_error -> select_best_strategy -> (backoff sleep /
adjust_params-and-retry / suggest-alternative-and-stop /
escalate-and-stop / abort) into the retry loop, capped at max_attempts
(default 3, matching legacy). Ports execute_command_with_recovery's
structure but calls spec.handler(**kwargs) instead of shelling out a
rewritten command string.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VFjZSRJm926vDGsR6UdUS4
POST/GET /api/tools/<name> now accepts use_recovery (default False,
a deliberate deviation from the legacy monolith's default-True — see
spec §3 for the pentest-safety reasoning). When true, the call runs
through hexstrike/core/recovery.py's execute_with_recovery instead of
a single direct handler call, restoring the legacy FailureRecoverySystem
response contract (recovery_info, alternative_tool_suggested,
human_escalation) for callers that rely on it, such as the MCP agent
that originally surfaced this as a 400 error before the earlier
unknown-params fix made it non-fatal.

Also updates test_tool_execution_route_ignores_unknown_params, whose
example unsupported field was use_recovery itself — now a recognized
flag, not an ignored one — swapped for a genuinely unknown field
(legacy_option) so the test still exercises what it was written to
test.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VFjZSRJm926vDGsR6UdUS4
…off sleep, and exception classification

Addresses six issues found only from the full-branch view after all 7
failure-recovery-system tasks landed individually: GENERIC_ADJUSTMENTS'
timeout doubling was applied even when the caller never set timeout (and
uncapped), RETRY_WITH_BACKOFF slept uselessly on the loop's terminal
attempt, execute_with_recovery never passed the caught exception object
into classify_error's type-based shortcuts, the post-loop recovery_applied
flag was hardcoded True instead of reflecting actual history, alternative-
tool suggestion had no coverage against the real registry, and GET
?use_recovery=true had no affirmative test. Also adds a module docstring
and drops an unused `import pytest`.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VFjZSRJm926vDGsR6UdUS4
@musicsms
musicsms merged commit 856de69 into master Sep 12, 2026
1 check passed
@musicsms
musicsms deleted the worktree-failure-recovery-system branch September 12, 2026 02:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant