Skip to content

fix(server): Claude Plan no longer asks again for a tool approved for the session - #36340

Open
juliusmarminge wants to merge 2 commits into
mainfrom
factory/issue-23918-a1794597635
Open

juliusmarminge wants to merge 2 commits into
mainfrom
factory/issue-23918-a1794597635

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Nov 13, 2026 •

Copy link
Copy Markdown
Member

Interim status while watching the pull request; no code changed in this pass. The brief listed no items to change. Pull request 36340 is open at 06ecc14, mergeable, with no reviews, no line comments and no issue comments at the time of reading. Its checks (Test Server 1-8, Lint, Build and Typecheck, Test, and the Macroscope checks) were queued or in progress, none failed. watch_pull_request is on for the pull request; the final result follows once checks pass and no high-rated bot finding is open.

Fixes #23918

Reproduction on main

Commit 9efd960 (origin/main). Ran T3CODE_DEV_SEED=0 vp run dev in a fresh worktree and drove the web UI with headless Playwright, since the preview browser was blocked on this host. Created a project and a Replay (dev) thread with 5 turns as the thread to read. Plan is no longer a composer toggle after #33131, so in a Full access Claude Haiku 5.5 thread I asked Claude to call create_threads with interactionMode "plan", runtimeMode "full-access", and a prompt to make 4 sequential t3_thread_read calls (view activity, afterPosition -1, then nextPosition, limit 2). The child opened with permissionMode plan. In the child thread I answered each Command approval card with More -> "Always allow this session". Observed: 4 approval cards for mcp__t3-code__t3_thread_read (afterPosition -1, 1, 3, 5). The dev database's runtime-request projection has 4 command requests on one provider turn, all resolved acceptForSession, 3 of them created after the first was resolved. Also added a failing adapter test (branch factory/repro-23918): in a Full access Plan turn, the second canUseTool call for mcp__t3-code__t3_thread_read after acceptForSession raises a new approval request.

Evidence

Run the web app with a fresh synthetic five-turn history. In Claude Haiku 5.5, Full access + Plan, request four sequential t3_thread_read calls using activity, limit 2, and positions -1, 1, 3, 5. Choose More → Always allow this session whenever asked. Environment: Chromium, light theme, 1440×1000.

Before After
9efd960925: four session approvals 06ecc147c6: one session approval
Before: four approval entries After: four reads with one approval entry
Repeated-approval recording, fourth approval and completion Single-approval recording

The base recording is split before the fourth approval following an automation click failure. Both runs completed all four reads in one provider turn. Seed and launch script, browser driver, sanitized runtime summary.

Not shown:

  • Hook-, rule-, and safety-originated approval requests and grant lifetime across session restart were not exercised; this proof covers the reported repeated-read flow.

Tests

None in this pass. Read the pull request, its reviews, comments and the head commit's check runs over the REST API: no failures, checks still running.

Not in this change

  • The grant is keyed by tool name only and lasts for the adapter session; it is not keyed by sub-agent (agentID) and survives leaving and re-entering Plan, the same lifetime as the CLI's own session rule.
  • Session approvals whose CLI suggestions are not a whole-tool rule (for example a Bash prefix rule or a directory rule) are not remembered by the adapter; if Plan re-asks for those too, that is a separate change.
  • t3_thread_read has Tool.Readonly false in mcp/toolkits/orchestrator/tools.ts; marking it read-only would stop Plan asking for it at all, which changes a tool annotation rather than fixing session grants.
  • The SDK omits decisionReasonType from its CanUseTool types although it passes it at runtime; the adapter reads it with an in check, and the older comment in claudeApprovalPresentation saying the SDK drops decision_reason_type is now out of date.

Who did the work

  • Written by Claude Fable 5.2, in Claude Code
  • Reviewed by GPT-6.1 Sol, in Codex, and by Claude Opus 5.5, each on its own
  • Proof captured by GPT-6.1 Sol and checked by Claude Opus 5.5

Run by the t3code factory in T3 Code.

juliusmarminge and others added 2 commits November 13, 2026 19:47
…#23918)

Failing repro: after Always allow this session on mcp__t3-code__t3_thread_read
in a Full access Plan turn, the next call raises another approval request.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the session

In Plan the Claude CLI records the session rule T3 Code sends back for
"Always allow this session", but its Plan check still asks for every tool
without a read-only annotation, so each t3_thread_read call raised a new
approval card.

The adapter now remembers a whole-tool session grant and answers the mode's
own ask from it. An ask from a hook, an ask rule or a safety check carries a
different reason and still reaches the user.

Fixes #23918

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted Author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Nov 13, 2026
@macroscopeapp

macroscopeapp Bot commented Nov 13, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 06ecc14

Macroscope's review found this PR approvable — Claude now remembers explicit whole-tool session approvals instead of repeatedly prompting for mode-based requests. The change preserves separate ask-rule and safety-check handling and does not change default permissions.

You can add or adjust custom eligibility rules. Learn more.

@github-actions

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅
Codex Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Codex Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Codex Live turn WebSocket decoded 21.5 KiB 21.5 KiB 0 B (0.0%) 24.4 KiB ✅
Codex Live turn messages 1 1 0 (0.0%) 8 ✅
Claude Total thread wire 5.0 KiB 5.0 KiB 0 B (0.0%) 6.8 KiB ✅
Claude Thread snapshot wire 3.8 KiB 3.8 KiB 0 B (0.0%) 4.9 KiB ✅
Claude Live turn WebSocket wire 1.2 KiB 1.2 KiB 0 B (0.0%) 2.0 KiB ✅
Claude Live turn WebSocket decoded 21.9 KiB 21.9 KiB 0 B (0.0%) 24.4 KiB ✅
Claude Live turn messages 1 1 0 (0.0%) 8 ✅

Other scenarios

All 64 scenario measurements match main.

All 64 scenario measurements
Provider Scenario Metric Main baseline This PR Impact PR ceiling
Codex short turn resume WebSocket decoded 10.5 KiB 10.5 KiB 0 B (0.0%) 12.7 KiB ✅
Codex short turn resume WebSocket messages 2 2 0 (0.0%) 2 ✅
Codex long turn running, cold open HTTP decoded 281.7 KiB 281.7 KiB 0 B (0.0%) 302.7 KiB ✅
Codex long turn running, cold open rows 75 75 0 (0.0%) 75 ✅
Codex long turn running, history page HTTP decoded 92.4 KiB 92.4 KiB 0 B (0.0%) 107.4 KiB ✅
Codex long turn running, history page rows 75 75 0 (0.0%) 75 ✅
Codex long turn finished, cold open HTTP decoded 381.5 KiB 381.5 KiB 0 B (0.0%) 410.2 KiB ✅
Codex long turn finished, cold open rows 151 151 0 (0.0%) 151 ✅
Codex long turn finished, socket cold open WebSocket decoded 381.6 KiB 381.6 KiB 0 B (0.0%) 410.2 KiB ✅
Codex long turn finished, socket cold open WebSocket messages 2 2 0 (0.0%) 2 ✅
Codex long turn finished, socket cold open rows 151 151 0 (0.0%) 151 ✅
Codex long turn finished, work page HTTP decoded 186.2 KiB 186.2 KiB 0 B (0.0%) 200.2 KiB ✅
Codex long turn finished, work page rows 150 150 0 (0.0%) 150 ✅
Codex idle thread resume WebSocket decoded 65 B 65 B 0 B (0.0%) 200 B ✅
Codex idle thread resume WebSocket messages 1 1 0 (0.0%) 1 ✅
Codex fleet shell snapshot HTTP decoded 42.4 KiB 42.4 KiB 0 B (0.0%) 53.7 KiB ✅
Codex fleet shell snapshot rows 27 27 0 (0.0%) 27 ✅
Codex fleet shell subscribe WebSocket decoded 65 B 65 B 0 B (0.0%) 200 B ✅
Codex fleet shell subscribe WebSocket messages 1 1 0 (0.0%) 1 ✅
Codex fleet shell resume check HTTP decoded 18 B 18 B 0 B (0.0%) 100 B ✅
Codex fleet shell resume check rows 0 0 0 0 ✅
Codex stale shell reload HTTP decoded 42.4 KiB 42.4 KiB 0 B (0.0%) 53.7 KiB ✅
Codex stale shell reload rows 27 27 0 (0.0%) 27 ✅
Codex stale shell resume WebSocket decoded 140 B 140 B 0 B (0.0%) 400 B ✅
Codex stale shell resume WebSocket messages 2 2 0 (0.0%) 2 ✅
Codex stale todo list cold open HTTP decoded 72.4 KiB 72.4 KiB 0 B (0.0%) 83.0 KiB ✅
Codex stale todo list cold open rows 75 75 0 (0.0%) 75 ✅
Codex stale todo list cold open nodes 2 2 0 (0.0%) 4 ✅
Codex stale todo list cold open subagents 2 2 0 (0.0%) 4 ✅
Codex stale todo list cold open plans 1 1 0 (0.0%) 2 ✅
Codex stale todo list cold open providerTurns 1 1 0 (0.0%) 2 ✅
Codex stale todo list cold open checkpoints 1 1 0 (0.0%) 2 ✅
Claude short turn resume WebSocket decoded 10.6 KiB 10.6 KiB 0 B (0.0%) 12.7 KiB ✅
Claude short turn resume WebSocket messages 2 2 0 (0.0%) 2 ✅
Claude long turn running, cold open HTTP decoded 283.3 KiB 283.3 KiB 0 B (0.0%) 302.7 KiB ✅
Claude long turn running, cold open rows 75 75 0 (0.0%) 75 ✅
Claude long turn running, history page HTTP decoded 93.4 KiB 93.4 KiB 0 B (0.0%) 107.4 KiB ✅
Claude long turn running, history page rows 75 75 0 (0.0%) 75 ✅
Claude long turn finished, cold open HTTP decoded 384.2 KiB 384.2 KiB 0 B (0.0%) 410.2 KiB ✅
Claude long turn finished, cold open rows 151 151 0 (0.0%) 151 ✅
Claude long turn finished, socket cold open WebSocket decoded 384.3 KiB 384.3 KiB 0 B (0.0%) 410.2 KiB ✅
Claude long turn finished, socket cold open WebSocket messages 2 2 0 (0.0%) 2 ✅
Claude long turn finished, socket cold open rows 151 151 0 (0.0%) 151 ✅
Claude long turn finished, work page HTTP decoded 188.1 KiB 188.1 KiB 0 B (0.0%) 200.2 KiB ✅
Claude long turn finished, work page rows 150 150 0 (0.0%) 150 ✅
Claude idle thread resume WebSocket decoded 66 B 66 B 0 B (0.0%) 200 B ✅
Claude idle thread resume WebSocket messages 1 1 0 (0.0%) 1 ✅
Claude fleet shell snapshot HTTP decoded 43.0 KiB 43.0 KiB 0 B (0.0%) 53.7 KiB ✅
Claude fleet shell snapshot rows 27 27 0 (0.0%) 27 ✅
Claude fleet shell subscribe WebSocket decoded 66 B 66 B 0 B (0.0%) 200 B ✅
Claude fleet shell subscribe WebSocket messages 1 1 0 (0.0%) 1 ✅
Claude fleet shell resume check HTTP decoded 18 B 18 B 0 B (0.0%) 100 B ✅
Claude fleet shell resume check rows 0 0 0 0 ✅
Claude stale shell reload HTTP decoded 43.0 KiB 43.0 KiB 0 B (0.0%) 53.7 KiB ✅
Claude stale shell reload rows 27 27 0 (0.0%) 27 ✅
Claude stale shell resume WebSocket decoded 140 B 140 B 0 B (0.0%) 400 B ✅
Claude stale shell resume WebSocket messages 2 2 0 (0.0%) 2 ✅
Claude stale todo list cold open HTTP decoded 73.4 KiB 73.4 KiB 0 B (0.0%) 83.0 KiB ✅
Claude stale todo list cold open rows 75 75 0 (0.0%) 75 ✅
Claude stale todo list cold open nodes 2 2 0 (0.0%) 4 ✅
Claude stale todo list cold open subagents 2 2 0 (0.0%) 4 ✅
Claude stale todo list cold open plans 1 1 0 (0.0%) 2 ✅
Claude stale todo list cold open providerTurns 1 1 0 (0.0%) 2 ✅
Claude stale todo list cold open checkpoints 1 1 0 (0.0%) 2 ✅

Baseline: e94db17 · PR result: 06ecc14 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 108.5 KiB
  • Claude decoded thread snapshot: 108.8 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@coderabbitai

coderabbitai Bot commented Nov 13, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

The Claude adapter now records eligible Plan-mode session grants and reuses them for qualifying mode-triggered requests. A regression test checks that a granted tool does not prompt again for a mode request, while a hook-triggered request still prompts.

Changes: Plan-mode session grants

Layer / File(s) Summary
Record and reuse Plan-mode grants
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts, apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts
The adapter records an allowed tool when the approval result contains an eligible session-level allow rule. It skips a later approval request only when the request is mode-triggered, no ask rule matched, standing grants are not suppressed, and the tool has a recorded grant. The test checks that hook-triggered requests still prompt.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: t3dotgg, maria-rcks, yash-singh1

Merge Risk: Minimal · up to 06ecc

This change stops repeated approval cards in Claude Plan mode for tools already approved for the session. Hook-triggered and other asks still require approval. No remaining merge-blocking risk was identified, and adapter tests cover both the reuse case and the hook case.

Pre-merge checks: Passed 3 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Description check Warning The description is an interim status note rather than a completed PR description in the repository template. It has substantive content: a reproduction on main, a before/after proof with linked artifa… Rewrite the description to follow the repository template headings: Problem, Change, Scope, Verification. Under Problem, state the bug in one or two sentences: after 'Always allow this session', Plan mode re-prompts for the same MCP tool, a…
Passed Passed checks: 3 passed

Check name Status Explanation
Title check Passed The title names the fix and its user-visible effect: Claude Plan mode no longer re-asks for a tool approved for the session. This matches the main change in ClaudeAdapterV2.ts, which records session-w…
Linked Issues check Passed [#23918] The issue requires that a session approval of mcp__t3-code__t3_thread_read stop later approval requests in Claude Plan mode with Full access. At head, ClaudeAdapterV2.ts adds planSessionToolG…
Out of Scope Changes check Passed All changed code lies in ClaudeAdapterV2.ts and its test file. The adapter diff adds only the grant Ref, the grant-check guard, and the grant-recording logic on the approval result path, all tied to r…
Full details: Title check

Explanation

The title names the fix and its user-visible effect: Claude Plan mode no longer re-asks for a tool approved for the session. This matches the main change in ClaudeAdapterV2.ts, which records session-wide whole-tool grants and uses them for Plan-mode asks. It follows the conventional commit style of the template.

Full details: Linked Issues check

Explanation

[#23918] The issue requires that a session approval of mcp__t3-code__t3_thread_read stop later approval requests in Claude Plan mode with Full access. At head, ClaudeAdapterV2.ts adds planSessionToolGrants (a per-session Ref set). The permission callback records a tool name when an approval result is allow and its updatedPermissions contain an addRules allow rule for that toolName with no ruleContent. A later canUseTool call is auto-allowed only when decisionReasonType is 'mode', matchedAskRule is undefined, suppressAlwaysAllowRule is not true, and the tool is in the grant set. Hook, ask-rule, and safety asks keep the approval flow. The check follows the existing never-policy and dangerous-removal denies. The diff confirms this logic. The repro test (two 'mode' calls plus one 'hook' call) and the adapter test suite (409 passed) are reported as passing. The reported CLI probe supports the reason-type premise. The full UI flow was not re-run, so the fix is supported by code and adapter tests rather than an end-to-end run. Prefix and directory rules and subagent keying are out of this PR's stated scope, and the issue does not require them as coding acceptance criteria. The issue's 'additional authorization explained' expectation is non-coding and not assessed.

Full details: Out of Scope Changes check

Explanation

All changed code lies in ClaudeAdapterV2.ts and its test file. The adapter diff adds only the grant Ref, the grant-check guard, and the grant-recording logic on the approval result path, all tied to repeated approval cards for session-approved tools. The test change keeps the repro test, adds decisionReasonType to the helper (a supporting test change), and adds a hook-ask case that checks the guard does not bypass hook asks. No unrelated refactoring, tool annotation change (t3_thread_read Readonly stays false), or documentation change appears in the reviewed diff. The PR description states the grant is not keyed by agentID and does not cover prefix or directory rules. These are stated limits, not unrelated changes.

Full details: Description check

Explanation

The description is an interim status note rather than a completed PR description in the repository template. It has substantive content: a reproduction on main, a before/after proof with linked artifacts, a stated scope (whole-tool session grants keyed by tool name, not prefix or directory rules), and a list of exclusions. It links the issue (#23918) and names the tests run. Several template sections are missing or weak. The Problem section has no clear one-to-two-sentence statement of the expected behavior. The Change section does not describe the adapter logic in template form. The Scope section does not say whether the change is a bug fix. It links the issue, which satisfies that part. The Verification section includes focused tests and manual checks, but the 'Tests' section says 'None in this pass', which conflicts with the Verification reported elsewhere in the description. The description also says 'Interim status while watching the pull request' and gives a 'watch_pull_request' note, which is process text that does not belong in the PR body. The author also reports that checks were still running and that the final result would follow, so the status is not final. The attribution section is present, as the template asks for an agent's model and harness. The description is mostly complete in substance, but it is not cleanly structured to the template and has contradictory test reporting.

Resolution

Rewrite the description to follow the repository template headings: Problem, Change, Scope, Verification. Under Problem, state the bug in one or two sentences: after 'Always allow this session', Plan mode re-prompts for the same MCP tool, and give the expected behavior. Under Change, summarize the adapter change in ClaudeAdapterV2.ts: whole-tool session grants recorded from approvals and used only for mode-triggered asks. Under Scope, keep the issue link (#23918) and state that this is a bug fix. Under Verification, list the exact focused test commands and their results (for example, the Plan-filtered run with 6 passing and the full file run with 409 passing), and state what was not checked (hook, rule, and safety approval paths, and grant lifetime across session restart). Remove the interim status text and the 'Tests: None in this pass' line, since they conflict with the reported validation. Keep the attribution line with the model and harness. Re-check the description after CI finishes and state the final check results.

Finishing Touches

Generate unit tests (beta)

  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Recent review info

Run configuration

Commits

Reviewing files that changed from the base of the PR and between e94db17 and 06ecc14.

Files selected for processing: 2

  • apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts
  • apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts

Limit details: You’ve used all 10 included reviews currently available.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:trusted Author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Repeated t3_thread_read approvals after session approval in Claude Plan mode with Full access

1 participant