## Dispatch Desk\:&#32;device and path gates

At Dispatch Desk\,&#32;Nia sees a call named&#32;`write`\.&#32;She initially assumes it is a generic filesystem write\.&#32;The address changes the question\:&#32;the call targets&#32;`xd://seed_slot`\,&#32;so&#32;`write`&#32;is carrying an invocation of another tool\.

The operator must identify both the&#32;**outer transport**&#32;and the&#32;**inner operation**\.

### Read the envelope and its payload separately

This is the fictional envelope used for a reservation case\.&#32;Inspect it\;&#32;do not submit it to a running agent\.

~~~json
{
  "path": "xd://seed_slot",
  "content": "{\"action\":\"reserve\"}"
}
~~~

The&#32;`content`&#32;field is a JSON string containing the inner argument object\.&#32;In the private verifier\,&#32;the only mounted recording tool is&#32;`seed_slot`\.&#32;Its declaration returns read for&#32;`inspect`\,&#32;write for&#32;`reserve`\,&#32;an explicit exec\-tier deny for&#32;`blocked`\,&#32;and exec for other action strings\,&#32;including&#32;`publish`\.&#32;The executor merely appends an in\-memory record\.

`WriteTool.approval()`&#32;parses the device payload and calls&#32;`resolveToolTier()`&#32;on the target\.&#32;It returns the borrowed tier with&#32;`policyKey: "seed_slot"`\.&#32;It does&#32;**not**&#32;copy the target’s entire policy decision into the outer declaration\.

During execution\,&#32;`dispatchXdevTool()`&#32;resolves the enabled canonical tool and validates the decoded arguments before invoking the executable instance\.&#32;The inner wrapper can still enforce a tool\-owned deny or other applicable gate\.

### Predict an inspection and a reservation

`dispatch-inspect-no-ui`&#32;supplies&#32;`action: inspect`\,&#32;always\-ask mode\,&#32;and no UI\.&#32;`dispatch-reserve-once`&#32;supplies&#32;`action: reserve`&#32;in always\-ask and one recorded&#32;`Approve`&#32;answer\.

**Recorded answers\:**&#32;the inspection produced no prompt and one inert execution\.&#32;The reservation produced one prompt and one inert execution\.&#32;Both produced two&#32;`tool_call`&#32;events\:&#32;one for&#32;`write`\,&#32;one for&#32;`seed_slot`\,&#32;under the same outer call ID\.

The reservation’s outer prompt was\:

~~~text
Allow tool: write
Path: xd://seed_slot
Content:
{"action":"reserve"}
~~~

The available responses were exactly&#32;`Approve`&#32;and&#32;`Deny`\.

After the outer gate\,&#32;`WriteTool.execute()`&#32;forwards&#32;`xdevApproved: true`&#32;when a context is available\.&#32;For unchanged inner input\,&#32;the wrapper can suppress the duplicate mode\-tier prompt\.&#32;Two wrapper layers therefore do not necessarily mean two questions\,&#32;and two events do not mean two executions\.

### Policy identity can replace the generic write fallback

Compare these recorded cases\:

| Case | Applicable policy data | Recorded outcome |
| --- | ---: | --- |
| `dispatch-fallback-deny` | No device policy\;&#32;`write: deny`\;&#32;yolo | Outer throw\;&#32;zero prompts\,&#32;zero&#32;`tool_call`&#32;events\,&#32;zero inert executions\. |
| `dispatch-specific-allow` | `seed_slot: allow`\;&#32;`write: deny`\;&#32;always\-ask\;&#32;no UI | Exec\-tier fictional action returned\;&#32;zero prompts\,&#32;two&#32;`tool_call`&#32;events\,&#32;one inert execution\. |
| `dispatch-explicit-prompt-twice` | `seed_slot: prompt`\;&#32;yolo\;&#32;two Approve answers | Two prompts\,&#32;two&#32;`tool_call`&#32;events\,&#32;one inert execution\. |
| `dispatch-inner-tool-deny` | Inner action&#32;`blocked`\;&#32;yolo | Error result with tool\-policy refusal\;&#32;one outer&#32;`tool_call`\,&#32;no inner execution\. |

The device\-specific allow is a valid replacement for the invoking\-tool fallback\.&#32;It is not an instruction to widen a real device policy\.&#32;The explicit device prompt is consulted at both outer and inner layers in the recorded path\,&#32;so the current implementation can ask twice for one action\.&#32;Do not interpret that as two successful reservations\.

The inner\-deny case explains why borrowing a tier is not borrowing the whole decision\.&#32;The outer gate permits exec under yolo\,&#32;but the inner declaration still denies\.&#32;The dispatcher converts that ordinary inner error into a result carrying&#32;`isError: true`\.&#32;A returned result is not necessarily success\.

### Know the exact forwarded\-prompt predicate

The relevant source expressions in&#32;`ExtensionToolWrapper.execute()`&#32;are\:

~~~ts
const explicitPrompt = resolved.override || Object.hasOwn(userPolicies, resolved.policyKey ?? this.tool.name);
const xdevBypass = context?.xdevApproved === true && effectiveParams === params;
~~~

An ordinary resolved prompt is required when&#32;`explicitPrompt`&#32;is true or&#32;`xdevBypass`&#32;is false\.&#32;Pending provider safety checks independently require approval\.

Two limits follow directly from this source\:

- Raw own\-property presence is not the same as a normalized valid policy\.&#32;An invalid entry can still affect this predicate for the key it checks\.
- The unchanged\-input test is object identity\,&#32;not a deep content comparison or revision hash\.&#32;The recorded replacement cases use new argument objects\.

There is also a source\-derived edge case\:&#32;an unchanged forwarded inner decision that resolves to prompt but has neither a surviving override nor an own user\-policy entry can be suppressed by this predicate\.&#32;Do not generalize the tested explicit&#32;**user**&#32;prompt case into a claim that every possible tool\-owned prompt produces an inner dialog\.&#32;This edge case is not a separately executed Dispatch Desk scenario\.

### A revised input must be explained again

In&#32;`dispatch-rewrite-prompts`\,&#32;the outer input is&#32;`inspect`\.&#32;The recording handler supplies this replacement for the inner tool\:

~~~json
{
  "action": "publish",
  "note": "Revised fictional card"
}
~~~

**Prediction\:**&#32;can the replacement ride the original read\-tier admission\?

**Recorded answer\:**&#32;it cannot use the unchanged\-input bypass\.&#32;The inner wrapper reclassifies it as exec\,&#32;prompts with the revised action\,&#32;and records one inert execution after Approve\.&#32;The returned dispatch tier is exec\.

A useful diagnostic qualification appears in the same record\:&#32;`details.xdev.args`&#32;still contains the dispatcher’s original validated&#32;`inspect`&#32;input\,&#32;while the effective tier and inert execution ledger reflect the replacement\.&#32;The tier callback updates the tier\;&#32;it is not a general rewrite of every dispatch metadata field\.&#32;Do not treat that nested metadata as a universal final\-input audit\.

`dispatch-rewrite-denies`&#32;replaces&#32;`inspect`&#32;with&#32;`blocked`\.&#32;**Recorded\:**&#32;two&#32;`tool_call`&#32;events\,&#32;no prompt\,&#32;no inert execution\,&#32;and an error result naming tool policy\.&#32;A previously admitted input does not authorize a newly denied one\.

`dispatch-malformed-json`&#32;carries&#32;`{not-json`&#32;in yolo\.&#32;**Recorded\:**&#32;one outer event\,&#32;no prompt\,&#32;no inner execution\,&#32;and an error result explaining that the device expects a JSON args object\.&#32;The outer declaration falls back to exec for malformed JSON\;&#32;yolo admitting that tier does not make the payload valid\.&#32;In a prompting mode\,&#32;the outer gate can be reached before this dispatch validation failure\.

### Ordinary paths have different rules

The device story does not replace path analysis\.

- `WriteTool`&#32;unwraps a hashline path header before classification\.&#32;SSH\-shaped targets escalate to exec before ordinary handler\-backed write classification\.
- `resolveFileWriteApprovalTier()`&#32;returns write for ordinary filesystem paths\.&#32;For recognized internal\-resource paths\,&#32;a writable handler keeps write tier\;&#32;absence of a handler write method can yield read tier\.
- `local://`&#32;can subsequently resolve to session artifact storage and be written\.&#32;Thus this classification is not proof of zero file effects\.
- A device\-only&#32;`write`&#32;transport is not a general file\-write grant\.&#32;The existing dispatch tests verify refusal of filesystem targets\,&#32;with the source’s specific active\-plan local\-sandbox exception\.&#32;A fuller displayed description alone does not relax that execution guard\.
- `ReadTool`&#32;and&#32;`GrepTool`&#32;use&#32;`pathTargetsSsh()`&#32;to escalate SSH\-containing arguments\.&#32;The substring scan can catch a remote entry before later path\-list expansion\.&#32;It does not authenticate to the host or grant access there\.

The existing&#32;`ssh-url-approval-gate.test.ts`&#32;rejects remote\-shaped read\,&#32;grep\,&#32;and write calls at the wrapper before an SSH connection\,&#32;while exercising local counterparts\.&#32;That proves the tested gate boundary\,&#32;not remote execution\.

**Paper checkpoint\:**&#32;explain&#32;`dispatch-reserve-once`&#32;as one outer prompt\,&#32;two tool\-call events\,&#32;and one inert execution\.&#32;Then explain why&#32;`dispatch-explicit-prompt-twice`&#32;has two prompts without two executions\.&#32;**Worked answer\:**&#32;the first uses forwarded duplicate\-tier suppression\;&#32;the second retains an explicit device user policy at the inner gate\.

**Failure boundary\:**&#32;this route is not a model for every nested call\.&#32;Same\-tool native delegation through&#32;`ExtensionRunner.invokeNativeTool()`&#32;calls an unwrapped native implementation without another approval gate\.&#32;Other bridges and direct calls have their own wiring\.&#32;`xd://`&#32;is a dispatch address\,&#32;not a new source of authority\.

**Source anchors\:**&#32;`packages/coding-agent/src/tools/write.ts`&#32;—&#32;`WriteTool.approval`\,&#32;`WriteTool.execute`\;&#32;`packages/coding-agent/src/tools/xdev.ts`&#32;—&#32;`parseDeviceArgs`\,&#32;`resolveXdevTool`\,&#32;`dispatchXdevTool`\;&#32;`packages/coding-agent/src/extensibility/extensions/wrapper.ts`&#32;—&#32;`ExtensionToolWrapper.execute`\;&#32;`packages/coding-agent/src/tools/path-utils.ts`&#32;—&#32;`resolveFileWriteApprovalTier`\,&#32;`pathTargetsSsh`\;&#32;`packages/coding-agent/test/write-xdev-dispatch.test.ts`\;&#32;`packages/coding-agent/test/tools/ssh-url-approval-gate.test.ts`\.
