fix(permission-broker): scope broker socket by bot id, not threadId alone - #1102
Conversation
…lone The Claude driver's session/permission-broker resource table is a single process-wide map keyed only on threadId. When a delegated child turn's threadId ever coincides with its still-open parent's — as reproduced repeatedly against a live @chief -> @cliff delegation on Windows (milind-soni#1017, "permission broker: ... is still held") — both turns collide on the exact same broker socket. On POSIX this gets papered over by unlinkSync stealing the socket file out from under the still-listening parent; on Windows, named pipes are exclusive and the collision surfaces as an outright bind failure, breaking the delegated tool-call channel itself (not just the approval card), even with Full access on both bots. Fold botId into the socket-path digest so a delegated child can never share a broker socket with its parent (or any other bot), regardless of the exact mechanism that produces the threadId reuse. Fixes milind-soni#1017. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
@buttonsjasper360-lang is attempting to deploy a commit to the SupaMaus Team on Vercel. A member of the Team first needs to authorize it. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (4)
Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review. 📝 WalkthroughWalkthroughThe PR propagates ChangesClaude turn and approval handling
Priority: ➖ Normal Estimated code review effort: 4 (Complex) | ~45 minutes Change: Bug fix · Severity of issue fixed: Medium Suggested reviewers: Merge Risk: ⚪ Minimal · up to Bot-specific broker paths are propagated through both turn-dispatch paths, with regression coverage for shared-thread bot collisions. No unresolved merge-blocking risk was identified. 🚥 Pre-merge checks | ✅ 2 | ❌ 3❌ Failed checks (3 warnings)
✅ Passed checks (2 passed)
Full details: Linked Issues checkExplanation Issue Resolution Implement and test broker cleanup for delegated-turn failure, timeout, and cancellation, or make approval-card handling use the broker's returned Full details: Out of Scope Changes checkExplanation The socket namespace changes and their collision test support issue Full details: Docstring CoverageExplanation Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 4 files. (1 skipped: 1 too large.) ✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…a for botId CI caught this on both macos-latest and ubuntu-latest: connectBroker() in this test reimplements permissionSocketPath/brokerSocketCandidates rather than importing them (DATA_DIR there is fixed at import time from this process's HOME, not the fixture's), so it fell out of sync when this PR folded botId into the digest. The test polled for the pre-fix socket path, which the real server no longer binds, and timed out. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…-scope-by-bot # Conflicts: # server/drivers/claude.ts
…d on main's own tip; looks like a CI flake, not a regression from this merge
Summary
Fixes #1017 — a delegated child turn's permission-broker socket can collide with its still-open parent's, breaking the tool-call channel itself (not just the approval card) even with Full access on both bots.
The Claude driver's session/permission-broker resource table (
sessions,activemaps inserver/drivers/claude.ts) is a single process-wide table keyed only onthreadId. Reproduced repeatedly live (@Chief→@Cliffdelegation, see comments on #1017): when the delegated turn's threadId coincides with the parent's still-open one, both bind attempts collide on the exact same broker socket path. POSIX papers over this —unlinkSyncsilently steals the socket file out from under the still-listening parent — but Windows named pipes are exclusive and the secondlisten()just fails, surfacing aspermission broker: ... is still held.Change
SendTurnInputgains an optionalbotIdfield (server/contracts.ts).botId: bot.id(server/index.ts).permissionSocketPath/brokerSocketCandidates(server/drivers/claude.ts) foldbotIdinto the socket-path digest alongsidethreadId.This namespaces the broker socket per bot, so a delegated child can never share a socket with its parent (or any other bot) regardless of the exact mechanism that produces the threadId reuse — the collision is ruled out by construction rather than chased at its source.
Test plan
pnpm exec tsc -p tsconfig.server.json --noEmit— cleanpnpm exec vitest run server/drivers/claude.test.ts— 104 passed, 1 skipped (pre-existing, unrelated)pnpm exec vitest run server/index.test.ts server/delegations.test.ts server/drivers— 1122 passed, 1 skipped🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes