Skip to content

Permission mode switch (Auto→Bypass) is not honored by the next turn #3349

Description

@Astro-Han

Switching the per-session permission mode from Auto to Bypass is not honored by the next turn. This reproduces in both a plain chat session (no Goal) and a running task. After the switch, the next turn still executes under the managed/ask boundary: Bash is still sandboxed and the model is still prompted for approval, even though the picker shows Bypass. The boundary the next turn actually runs under is not refreshed to the newly committed configuration before it executes.

Expected: a permission change is observed by the next turn that starts after it, before that turn's first tool call.

How to reproduce

  1. In any session (a plain chat, no Goal required), switch the permission picker from Auto to Bypass.
  2. Send / continue so a new turn runs; issue a Bash command or a filesystem write.
  3. Observed: the command is still sandboxed / the model is still asked to approve; the turn still runs under the managed boundary.

Note: more frequent on long-running/multi-turn tasks — under an active Goal the continuation keeps the session claim busy, which widens the failure window — but it also reproduces in a plain session, so this is not Goal-specific.

Environment

  • Maka version or commit: 98bdd6cf8 (main)
  • OS and version: macOS 26.5.2
  • Surface: Desktop
  • Node.js version, if running from source: v26.7.0

Logs, screenshots, or additional context

Root cause (code-traced, high confidence; a regression test is still needed to pin the exact sub-mechanism):

  • Tools decide sandboxing/approval from the executionBoundary they read at call time (packages/runtime/src/tool-runtime.ts readExecutionBoundary; packages/runtime/src/builtin-tools.ts boundary.kind === 'bypass').
  • The Auto → Bypass switch commits a new configuration via transitionSessionConfiguration, but the next turn does not observe it: ctx.permissionMode is frozen in the backend/composer at build time (tool-runtime.ts this.input.header.permissionMode; execution-model-composition.ts composer), and ensureActive reuses the backend generation across turns, only bumping cachedHeader (packages/runtime/src/runtime-kernel.ts).
  • Under an active Goal, the continuation's immediate next-turn admission is a frequent trigger: the switch can be dropped as session_busy while a successor claim is held. That is an amplifier, not the root cause.

Open question for the regression test: whether the next turn fails to see the new boundary because the boundary write is dropped/raced, or because tool-time reads are cached. See the assignee's plan in the comments for a full proposed fix (queued quiescent commit + boundary-derived permissionMode + revision guard).

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions