-
Notifications
You must be signed in to change notification settings - Fork 3
plat 355
| Coordination | Value |
|---|---|
| Assigned agent | Claude Code |
| Ticket state | fixed; live-verified 2026-09-23 |
| Last synchronized | 2026-09-23 |
| Priority | P0 execution |
| Category | security-sandbox (runner-up: step-execution) |
A scripted step or a delegated call occasionally fails with
<tool> caller does not own this tool session, and then passes on retry.
Two cases were seen on 2026-09-23:
-
websiteaeo, stepcollect-goal-observations, 11:08:26:query_workflow_db caller does not own this tool session. The self-repair wrapped the script's tool helper in six-attempt retries, which hides the bug but does not fix it. -
substack, 11:01:58:get_human_input_requestfailed 16 times in a row.
Both failures came minutes after the scheduled runs of salesoutreach,
substack and social-media started at 11:01:43–59.
This is the variant of PLAT-338 that PLAT-338
left open. PLAT-338 taught the ownership check to accept a registered
session-group-* child of the parent run. But the child never reached the
parent's executor.
- A workflow script calls platform tools through its
session-group-<group>-<ns>bridge session. No agent runs under that ID, so no per-session tool registry is ever created for it. -
codeexec.CallCustomToolWithSessionfinds no registry for the session, so it falls back to the globalcustomToolsmap. The log showsSession registry not found, falling back to global, thenUsing global custom tool (no session scope). -
InitRegistryWithVirtualToolsreplaces every global executor whenever any agent starts, so the last agent to start wins. Each executor is a closure frombindToolExecutionContextForSessionand is bound to the session that registered it. - When a concurrent run registered last, the executor's bound session is not the child's parent, so the ownership check rejects the call. That is correct behaviour, but it makes the feature fail at random. A retry passes once the owning run happens to register again.
mcpagent/agent/codeexec/registry.go: a new function,
registryScopeForSession. When a session has no registry of its own and
mcpclient knows it as the live child of a parent run (RegisterHTTPSession),
the call uses the parent's registry and allow list. That parent executor is
bound to the parent session, so PLAT-338's check admits the call with the
parent's identity.
The existing safeguards still hold:
- Unregistered, stopped and ambiguous children resolve to themselves, never by name, so they keep the legacy global path.
- A session that has its own registry is unchanged.
- The no-borrow rule for existing registries still holds.
A self-review found that the first version could turn a working call into a failure, in two ways:
- It also applied the parent chat's per-turn allow list to the step script.
- It returned "not registered" for a tool the parent never registered, where
the legacy lookup had resolved it (for example
record_goal_observationsorget_human_input_request).
The parent is now used only after the calling session's own allow-list check,
and only when the parent actually registered that tool. Otherwise the call
behaves exactly as before. TestCallCustomToolWithSessionParentResolutionIsConservative
fails on 445e64f and passes on af11626.
TestCallCustomToolWithSessionUsesRegisteredParentRegistry (mcpagent
agent/codeexec) sets a different run's global executor and checks two cases:
- A registered child reaches its parent's executor.
- An unregistered child with a similar-looking name keeps the legacy path.
The test fails without the fix (child call = "other-run") and passes with
it. The full agent/codeexec suite and the virtual-tools package are green.
TestToolExecutionContextTopologyMatrix (cmd/server) fails when run together
with other ToolExecutionContext|WorkflowDB tests, with or without this fix,
and passes on its own. It is an existing shared-state/ordering problem, not
caused by this change.
Verified on 2026-09-23 on the local server (restarted 11:51:44 with mcpagent
445e64f; the refinement is not live-run yet), in websiteaeo run workflow-full-mudpu2g001, launched from the
builder chat:
- Step
collect-goal-observationsis the scripted step that failed at 11:08. It ran at 12:05:19. Every tool call on its bridge sessionsession-group-default-1790144533809580000loggedResolved child session to its parent run's tool registry(parent6eaa17e1-…). - There were zero
falling back to globallines and zero ownership errors. - The script exited 0 on its first attempt in about 2s and passed validation. Its retry helper never retried.
The six-attempt retry wrapper that the self-repair added to
Workflow/websiteaeo/code/collect-goal-observations/main.py is no longer
needed. code-authoring.md now tells scripts to fail fast on tool-boundary
errors instead of retrying them.
Auto-synced from docs/ on main. Edit there, not here.