fix: reject HITL edits that repoint the generic call tool's action - #176
Merged
Merged
Conversation
The generic "call" tool carries its target in args.action, and HITL gates it per-call via a `when` predicate — so the interrupt only fires when the targeted action is gated. Nothing stopped a resume's edit decision from changing args.action to a *different* action, which would then run under the approval granted for the gated one — including an action that is not HITL-gated at all. Guard the edit at the decision boundary: an edit may change the parameters but not the action. Per-action tools are unaffected (their name is the action and carries no args.action to swap).
Akatuoro
approved these changes
Oct 2, 2026
sjvans
marked this pull request as ready for review
October 4, 2026 19:36
SummaryThe following content is AI-generated and provides a summary of the pull request: Titlefix: prevent HITL generic call edits from changing actions CategoryBug Fix 🐛 SummaryAdds a HITL resume safeguard that prevents The generic Changes
Related
Have you...
PR Bot InformationVersion:
|
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.
Problem
The generic combined
calltool carries its target action inargs.action, and HITL gates it per-call via thewhenpredicate added in #170 — so an interrupt only fires when the targeted action is gated (@agent.hitl/@Common.IsActionCritical).Nothing stopped a resume's edit decision from changing
args.actionto a different action. That different action would then execute under the approval the human granted for the gated one — including an action that isn't HITL-gated at all. Approve-then-edit becomes an escalation path.Fix
Guard at the edit decision boundary (
guardHitlEditsinsrv/handlers/graph-executor/hitl.js): for a genericcalltool, an edit may change the parameters but notargs.action. If it tries to repoint the action, the resume is rejected. Per-action tools are unaffected — their name is the action and they carry noargs.actionto swap. Non-edit decisions pass through.Scoped deliberately: it forbids changing the action outright (the tightest safe invariant), rather than consulting the service model to allow swaps between gated actions. Editing is for tuning parameters, not re-choosing the action.
Tests
tests/integration/hitl-edit-escalation-guard.test.js— parameters-only edit allowed, same-action edit allowed, action-swap rejected, per-action pass-through, non-edit pass-through, and positional matching across multiple decisions. Full non-hybrid suite green (563 passed).Context
Follow-up to the #174 discussion. The two-way action/
calltransform in #174 was dropped in favour of @Akatuoro's test-only approach on #166 (keep the technicalcallname, readargs.actionfor display). This PR keeps just the one piece that wasn't about presentation: the escalation guard.