Skip to content

v0.9.8: make one-shot approval outcomes durable and fail-closed #5360

Closed

Description

@Hmbown

Why

Mining deepseek-ai/deepseek-harness 0.1.0-rc.5 at 47f943859bef60e4160492346772ded9b24f765a found one approval pattern worth adopting without importing its Cordis/plugin architecture: every approval request has one closed outcome, the ask/decision pair is written to the session log, and only an explicit one-shot allow grants execution. Missing, cancelled, throwing, or malformed answerers become a fail-closed outcome.

Codewhale already fails closed at the live channel boundary in crates/tui/src/core/engine/approval.rs, but approval evidence is split between transient engine events and the optional CODEWHALE_TOOL_AUDIT_LOG projection in core/engine/tool_execution.rs. A resumed session cannot reconstruct the exact ask/outcome pair from its own durable record.

Small design

Keep the existing engine and tool-call path. Do not add a plugin bus or generic policy framework.

  • Define one closed internal approval outcome covering: approved once, denied, cancelled, unavailable, and retry once with the approved sandbox policy.
  • Correlate each outcome to the exact tool call/approval attempt. Reuse the tool-call id if it is already unique enough; add a separate approval id only if a test proves it is needed.
  • Persist an asked receipt before waiting and one terminal decided receipt before execution proceeds or the denied result is returned.
  • Treat channel closure, cancellation, malformed/stale decisions, and persistence failure as non-grants. Only approved once or the exact approved retry policy may cross the gate.
  • Keep the external JSONL audit as an optional projection, never the authority.
  • Keep approval receipts out of the model transcript; the existing tool result remains the model-visible outcome.

Acceptance

  • A keyless engine test covers approved, denied, cancelled, unavailable/channel-closed, and retry-with-policy outcomes.
  • Replay/resume reconstructs every completed ask/decision pair and detects an unmatched ask after interruption.
  • No path executes a tool when the terminal approval receipt cannot be committed.
  • Existing Ask / Auto-Review / Full Access / Never behavior and sandbox precedence do not change.
  • Focused tests plus cargo fmt --all -- --check pass.

Source comparison

  • Harness: packages/interaction/user-approval/src/index.ts, docs/subsystems/approval.md
  • Codewhale: crates/tui/src/core/engine/approval.rs, crates/tui/src/core/engine/turn_loop.rs, crates/tui/src/core/engine/tool_execution.rs

No-Issue: research-derived v0.9.8 hardening task.

Activity

  1. added this to the v0.9.8 milestone on Aug 13, 2026
  2. modified the milestones: v0.9.8, v0.9.9, v0.9.10 on Aug 14, 2026
  3. Hmbown commented on Aug 17, 2026

    @Hmbown
    CollaboratorAuthor

    Rolled to v0.9.10: the v0.9.9 release branch merged to main tonight (#5476) without this landing; nothing here is closed or dropped.

  4. moved this from Backlog to In progress in CodeWhaleon Aug 17, 2026
  5. moved this from In progress to Done in CodeWhaleon Aug 19, 2026
  6. added 2 commits that reference this issue on Aug 19, 2026
    f8246f6
    68f5da2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions