P0 blocker — implement canonical resumable runtime tool approval lifecycle #209

Closed
opened 2026-08-24 07:47:10 +00:00 by lost-rob0t · 0 comments
lost-rob0t commented 2026-08-24 07:47:10 +00:00 (Migrated from github.com)

Parent epic: #127
Blocks: #191, #134
Depends on: #131, #133
Integrates with: #82, #83 and the existing LangGraph agent/tool path.

Why this blocker exists

Auto-RAGE research for #191 falsified its inherited premise that Zara already has an executable approval lifecycle to carry over ZARA/1.

The repository currently has schema-level ApproveTool, RejectTool, ToolWaitingForUser and related tool events, but the production path is not resumable:

  • LangGraphRuntimeBackend does not override approve_tool or reject_tool; the inherited methods always raise UnsupportedRuntimeCommand;
  • create_agent_graph() compiles without a checkpointer;
  • run_conversation_loop() creates a fresh graph per turn and calls ainvoke(state) without a stable LangGraph thread id;
  • the tools node executes tool calls directly, with no risk policy or interrupt;
  • no production code publishes ToolWaitingForUser or binds an approval decision to pending graph state;
  • current tool lifecycle publication is schema/test/UI support, not a real approval authority.

Current official LangGraph guidance requires checkpointed graph state, a stable thread id, an interrupt, and resume through Command(resume=...). A wire-only implementation in #191 would expose commands that cannot authorize real runtime work and would let #134 claim synthetic Voice parity.

Goal

Implement one canonical, principal/conversation/turn-scoped, resumable tool-approval lifecycle in the existing Zara runtime and LangGraph agent path. It must be usable through RuntimeHost commands/events and remain transport-neutral so #191 can carry it over authenticated ZARA/1 without inventing a second tool runtime.

Required architecture

Research owns exact internals, but the result must:

  • classify registered tools by explicit server-side approval policy;
  • pause before an approval-required tool side effect;
  • persist enough graph/runtime state to resume safely after asynchronous approval or rejection;
  • bind pending approval to authenticated principal, conversation, canonical turn and stable tool_run_id;
  • publish typed ToolQueued/ToolWaitingForUser/UserResponded/terminal tool lifecycle events through the principal runtime bus;
  • resume only the exact pending action through existing ApproveTool / RejectTool commands;
  • keep the RuntimeHost loop responsive while one turn waits;
  • define cleanup for cancellation, timeout, disconnect/reconnect, shutdown and restart;
  • reject unknown, stale, cancelled, mismatched and replayed decisions;
  • guarantee the side effect runs at most once;
  • keep tool arguments/results, prompts, credentials and provider internals out of audit/log output according to policy;
  • use the existing agent/tool registry and runtime boundary, not a second executor or approval interpreter.

Security and isolation

  • Server-side authenticated principal and server policy remain authority.
  • A different principal can never observe or answer another principal’s approval.
  • Same-principal multi-device visibility/ownership is explicit and later enforced by #191 at the authenticated session boundary.
  • Approval grants one pending tool_run_id; it is not a generic tool invocation capability.
  • Cancellation and approval races are deterministically fenced.
  • Pending state and queues are bounded.
  • Persistent checkpoint state is principal-scoped and restart behavior is explicit.

TDD requirements

Write failing tests before production changes for:

  • real approval-required local tool pauses before its side effect;
  • approve resumes once and publishes lifecycle events;
  • reject never runs the side effect and completes the turn coherently;
  • wrong/stale/cancelled/replayed tool ids fail closed;
  • deterministic cancel-vs-approve race;
  • another principal remains isolated and unblocked;
  • timeout/disconnect/restart/shutdown cleanup;
  • bounded pending approvals;
  • sanitized logs/errors/checkpoints;
  • non-approval tools preserve current behavior;
  • persistent/durable behavior matches the researched policy.

Add a focused non-interactive gate and include its deterministic subset in the complete repository/Nix gate.

Acceptance

Using the production runtime backend and a deterministic local approval-required tool, an authenticated principal can start a turn, receive a typed approval request before any side effect, approve or reject it through RuntimeHost, and observe one coherent terminal tool/turn result. Cancellation, replay, mismatched identity and lifecycle failures cannot execute the tool or leak state. #191 may resume only after this transport-neutral contract is exact-head green and merged.

Non-goals

  • no ZARA/1 message additions; owned by #191 after this issue;
  • no future #150 device capability/action plane;
  • no arbitrary shell/tool invocation;
  • no provider-specific checkpoint objects in public runtime events;
  • no Prolog-RLM dependency.
Parent epic: #127 Blocks: #191, #134 Depends on: #131, #133 Integrates with: #82, #83 and the existing LangGraph agent/tool path. ## Why this blocker exists Auto-RAGE research for #191 falsified its inherited premise that Zara already has an executable approval lifecycle to carry over `ZARA/1`. The repository currently has schema-level `ApproveTool`, `RejectTool`, `ToolWaitingForUser` and related tool events, but the production path is not resumable: - `LangGraphRuntimeBackend` does not override `approve_tool` or `reject_tool`; the inherited methods always raise `UnsupportedRuntimeCommand`; - `create_agent_graph()` compiles without a checkpointer; - `run_conversation_loop()` creates a fresh graph per turn and calls `ainvoke(state)` without a stable LangGraph thread id; - the tools node executes tool calls directly, with no risk policy or interrupt; - no production code publishes `ToolWaitingForUser` or binds an approval decision to pending graph state; - current tool lifecycle publication is schema/test/UI support, not a real approval authority. Current official LangGraph guidance requires checkpointed graph state, a stable thread id, an interrupt, and resume through `Command(resume=...)`. A wire-only implementation in #191 would expose commands that cannot authorize real runtime work and would let #134 claim synthetic Voice parity. ## Goal Implement one canonical, principal/conversation/turn-scoped, resumable tool-approval lifecycle in the existing Zara runtime and LangGraph agent path. It must be usable through `RuntimeHost` commands/events and remain transport-neutral so #191 can carry it over authenticated `ZARA/1` without inventing a second tool runtime. ## Required architecture Research owns exact internals, but the result must: - classify registered tools by explicit server-side approval policy; - pause before an approval-required tool side effect; - persist enough graph/runtime state to resume safely after asynchronous approval or rejection; - bind pending approval to authenticated principal, conversation, canonical turn and stable `tool_run_id`; - publish typed `ToolQueued`/`ToolWaitingForUser`/`UserResponded`/terminal tool lifecycle events through the principal runtime bus; - resume only the exact pending action through existing `ApproveTool` / `RejectTool` commands; - keep the RuntimeHost loop responsive while one turn waits; - define cleanup for cancellation, timeout, disconnect/reconnect, shutdown and restart; - reject unknown, stale, cancelled, mismatched and replayed decisions; - guarantee the side effect runs at most once; - keep tool arguments/results, prompts, credentials and provider internals out of audit/log output according to policy; - use the existing agent/tool registry and runtime boundary, not a second executor or approval interpreter. ## Security and isolation - Server-side authenticated principal and server policy remain authority. - A different principal can never observe or answer another principal’s approval. - Same-principal multi-device visibility/ownership is explicit and later enforced by #191 at the authenticated session boundary. - Approval grants one pending `tool_run_id`; it is not a generic tool invocation capability. - Cancellation and approval races are deterministically fenced. - Pending state and queues are bounded. - Persistent checkpoint state is principal-scoped and restart behavior is explicit. ## TDD requirements Write failing tests before production changes for: - real approval-required local tool pauses before its side effect; - approve resumes once and publishes lifecycle events; - reject never runs the side effect and completes the turn coherently; - wrong/stale/cancelled/replayed tool ids fail closed; - deterministic cancel-vs-approve race; - another principal remains isolated and unblocked; - timeout/disconnect/restart/shutdown cleanup; - bounded pending approvals; - sanitized logs/errors/checkpoints; - non-approval tools preserve current behavior; - persistent/durable behavior matches the researched policy. Add a focused non-interactive gate and include its deterministic subset in the complete repository/Nix gate. ## Acceptance Using the production runtime backend and a deterministic local approval-required tool, an authenticated principal can start a turn, receive a typed approval request before any side effect, approve or reject it through `RuntimeHost`, and observe one coherent terminal tool/turn result. Cancellation, replay, mismatched identity and lifecycle failures cannot execute the tool or leak state. #191 may resume only after this transport-neutral contract is exact-head green and merged. ## Non-goals - no `ZARA/1` message additions; owned by #191 after this issue; - no future #150 device capability/action plane; - no arbitrary shell/tool invocation; - no provider-specific checkpoint objects in public runtime events; - no Prolog-RLM dependency.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
nsaspy/zara#209
No description provided.