Skip to content

fix(claude-native): give the evaluate-policy hook the day-long timeout#2012

Open
tomsen-ai wants to merge 1 commit into
omnigent-ai:mainfrom
tomsen-ai:fix/evaluate-policy-hook-timeout
Open

fix(claude-native): give the evaluate-policy hook the day-long timeout#2012
tomsen-ai wants to merge 1 commit into
omnigent-ai:mainfrom
tomsen-ai:fix/evaluate-policy-hook-timeout

Conversation

@tomsen-ai

@tomsen-ai tomsen-ai commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Related issue

N/A

Summary

  • The evaluate-policy command hook (build_hook_settings in claude_native_bridge.py) had no explicit timeout, so Claude Code's ~60s command-hook default kills the hook subprocess. But a TOOL_CALL/REQUEST policy ASK parks server-side until a human answers — up to the deciding policy's ask_timeout (default one day) — and the evaluate-policy client already waits the full day (_EVALUATE_POLICY_TIMEOUT_S = 86400). So every admin-policy ASK (e.g. a cost-budget gate) was silently capped at 60s.
  • In acceptEdits/bypassPermissions mode, where PermissionRequest never fires, this evaluate-policy gate is the sole human approval point — so the 60s cap means the hook-timeout fallback decides the policy before the operator can respond.
  • Fix: add timeout: 86400, matching the sibling permission_hook (which already carries it for exactly this reason). It was the only one of the three command hooks left on Claude Code's default.

ELI5: the hook that waits for a human to approve a policy prompt didn't tell Claude Code how long to wait, so Claude Code killed it after ~60s — long before the person could answer. The permission hook right next to it already says "wait a day"; this one just forgot to.

three command hooks in build_hook_settings:
  permission_hook       → timeout: 86400   ✓ (waits for the human)
  AskUserQuestion hook   → timeout: 10      ✓ (short by design)
  evaluate_policy_hook   → (none) → ~60s default   ✗  ← this PR

The real ceiling stays the policy's own ask_timeout; this just stops the command-hook layer from capping the wait first.

Test Plan

  • New unit test test_augment_claude_args_evaluate_policy_hook_has_day_long_timeout: asserts every registered evaluate-policy hook (PreToolUse/PostToolUse/UserPromptSubmit) carries timeout == 86400. Red on main (KeyError: 'timeout' — the key is absent), green with the fix.
  • tests/test_claude_native_bridge.py otherwise unchanged; the two serve_mcp/relay failures on my machine are pre-existing (they spawn a real subprocess that doesn't come up in my local sandbox) and reproduce identically with this change stashed — unrelated to this hook change.

Demo

Red → green on the unit test. Red run is the pre-fix source with this PR's test: the evaluate-policy hook dict has no timeout key (KeyError), while the sibling permission_hook already carries 86400.

red-to-green evaluate-policy hook timeout test

Type of change

  • Bug fix
  • Feature
  • UI / frontend change
  • Refactor / chore
  • Docs
  • Test / CI
  • Breaking change

Test coverage

  • Unit tests added / updated
  • Integration tests added / updated
  • E2E tests added / updated
  • Manual verification completed
  • Existing tests cover this change
  • Not applicable

Coverage notes

The new unit test drives augment_claude_args and asserts the timeout on every evaluate-policy hook registration; it fails on main and passes with the fix. The end-to-end "human answers after 60s" path depends on Claude Code's command-hook kill behaviour and isn't unit-testable here, but the fix mirrors the already-shipped permission_hook timeout.

Changelog

Admin policy approval prompts (e.g. cost-budget gates) in native Claude sessions no longer time out after ~60s before the operator can respond.

🤖 Generated with Claude Code

The evaluate-policy command hook had no explicit timeout, so Claude
Code's ~60s command-hook default kills the hook subprocess. But a
TOOL_CALL/REQUEST policy ASK parks server-side until a human answers
(up to the deciding policy's ask_timeout, default one day), and the
evaluate-policy client already waits the full day for that verdict — so
every admin-policy ASK (e.g. a cost-budget gate) is silently capped at
60s. In acceptEdits/bypassPermissions mode, where PermissionRequest
never fires, this evaluate-policy gate is the sole human approval point,
so the 60s cap means the policy is decided by the hook-timeout fallback
before the operator can respond.

The sibling permission_hook already carries timeout=86400 for exactly
this reason (see its inline rationale); the AskUserQuestion hook sets its
own timeout too. The evaluate-policy hook was the only one of the three
command hooks left on the default. Add timeout=86400 so no layer caps
the wait before the policy's own ask_timeout.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

@tomsen-ai This PR is a Bug fix, Feature, or UI / frontend change but the Demo section is missing or only contains a placeholder.

These change types require a screenshot or screen recording so reviewers can see the new behaviour without checking out the branch. Please update the Demo section with:

  • A screenshot or screen recording of the change, or
  • A link to a hosted video or GIF showing the new behaviour.

Use N/A only when the change has no user-visible effect whatsoever (e.g. a pure refactor or test-only change). If that's the case, uncheck the relevant type box and check Refactor / chore or Test / CI instead.

@github-actions github-actions Bot added the needs-demo PR needs a demo screenshot or recording label Jul 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-demo PR needs a demo screenshot or recording size/M Pull request size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants