You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The policy engine MUST be capable of producing one of five decisions: ALLOW, DENY, MODIFY, STEP_UP, or DEFER.
Focus of this issue: DEFER.
Current state
Not implemented. Guardrail hits are terminal — a violation errors out the current execution:
forge-core/runtime/skill_guardrails.go:160
return "", fmt.Errorf("tool output blocked by skill guardrail")
There is no primitive to pause the executor, hand off to a human or external decision-maker, and resume when a decision arrives.
Gap
R4-DEFER expects the engine to be able to say "I cannot decide this — pause and await a human/other authority". The executor loop (forge-core/runtime/loop.go:LLMExecutor.Execute) is a stateful step-machine but not resumable across process restarts, and the A2A tasks state model doesn't have a deferred state.
Proposed implementation
Architectural — the biggest gap in the R4 set.
Add TaskStateDeferred to the A2A task-status enum.
Timeout time.Duration — how long to wait before auto-DENY
ContextForApprover string — the decision context serialized for the approver
Executor loop learns to:
Persist current step state to MemoryStore (already stores conversation; extend to store the pending tool call + args)
Emit task_deferred audit event
Poll (or subscribe) for an approve/reject signal via new endpoint POST /tasks/{id}/decisions
Resume execution when a decision arrives OR auto-DENY on timeout
Delivery: reuse existing channel adapters (Slack/Telegram/Teams) to notify approvers with the deferred-context payload; approver replies via emoji or a signed URL that hits POST /tasks/{id}/decisions.
Effort
~2 weeks (executor resumability is the hard part).
Acceptance criteria
TaskStateDeferred recognized in A2A responses
DecisionDefer returnable from any guardrail hook
Executor persists step state on Defer; ctx returns without terminating the task
POST /tasks/{id}/decisions accepts {decision, approver, note} and resumes the executor
Timeout auto-DENYs and audits
Slack + Telegram notify handlers wired to receive deferred-context payloads
Requirement (governance framework, MUST)
Focus of this issue: DEFER.
Current state
Not implemented. Guardrail hits are terminal — a violation errors out the current execution:
There is no primitive to pause the executor, hand off to a human or external decision-maker, and resume when a decision arrives.
Gap
R4-DEFER expects the engine to be able to say "I cannot decide this — pause and await a human/other authority". The executor loop (
forge-core/runtime/loop.go:LLMExecutor.Execute) is a stateful step-machine but not resumable across process restarts, and the A2A tasks state model doesn't have adeferredstate.Proposed implementation
Architectural — the biggest gap in the R4 set.
TaskStateDeferredto the A2A task-status enum.DecisionDefertoPolicyDecision(see R4a (governance): generalize MODIFY decision beyond cli_execute output #209) with fields:DeferTo string— target (e.g.,"human:oncall","channel:slack:#approvals")Timeout time.Duration— how long to wait before auto-DENYContextForApprover string— the decision context serialized for the approverMemoryStore(already stores conversation; extend to store the pending tool call + args)task_deferredaudit eventPOST /tasks/{id}/decisionsPOST /tasks/{id}/decisions.Effort
~2 weeks (executor resumability is the hard part).
Acceptance criteria
TaskStateDeferredrecognized in A2A responsesDecisionDeferreturnable from any guardrail hookPOST /tasks/{id}/decisionsaccepts{decision, approver, note}and resumes the executordocs/security/defer-decisions.md