From 64ff9bda7c8cd56a712dca059064ae7e6822d220 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Sun, 1 Nov 2026 16:51:08 -0800 Subject: [PATCH 1/2] docs(ax): entries 91 and 92, a status message and a gate that each read the wrong thing 91: "upstream no longer lists X" named a vendor removal the check cannot see; a connection's tools/list follows its owner's consent (#3286). 92: the cloud-entitlement gate read the install's host label before the runtime type that dispatch actually reads (#3287, now live). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015AKgpQ2pr6xRMhN5mcfoHF --- docs/development/agent-experience-audit.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docs/development/agent-experience-audit.md b/docs/development/agent-experience-audit.md index 5dad1b18c4..dfe73e687d 100644 --- a/docs/development/agent-experience-audit.md +++ b/docs/development/agent-experience-audit.md @@ -4273,3 +4273,23 @@ Two different things went into that 191 s, and neither was a 120 s window. First **Lesson:** a default in a shared package is not the value its consumer runs. Read the consumer's override, or the log line that names the number, before measuring against it. + +## 91. "Upstream no longer lists X" named a cause the check cannot see (2026-11-02, cto) + +*Origin: the first draft of #3283, on 2026-11-01, said a vendor had removed a hosted-MCP tool. It had not.* + +When a pinned hosted-MCP tool was missing from a connection's `tools/list`, the `tool_unavailable` detail read `upstream no longer lists X`. That reads as a vendor removal. But the check only sees one connection's list, and the list depends on what that row's owner consented to. Sentry offers `update_issue` only with its Triage skill. The Linear smoke row lists 26 pins as absent because its scope is read-only. The tool was there; that connection had not been granted it. + +**Repair:** #3286 rewords the detail to `this connection's tools/list does not include X`. For the same reason an absent tool files no drift card. Only a schema that moved under its pin does. + +**Lesson:** a status message should name what was observed, not a cause the check cannot observe. A reader takes the named cause as established. + +## 92. A cost gate read a label the caller writes, not the field that decides where the agent runs (2026-11-02, cto) + +*Origin: a code read during the entitlement-gate work (F51). Fixed in #3287; this entry was held until that deploy was live.* + +`isCloudRuntime` (`backend/services/agentIdentityService.ts`) decides which installs need the `cloudAgents` entitlement. It returned "BYO" for any install whose `config.runtime.host` was `'byo'`, before it looked at `runtimeType`. The install route stores the caller's `config.runtime` as given, `host` included. Dispatch decides where a turn runs from `runtimeType` alone (`inProcessInstallationFrom` in `agentEventService.ts`) and never reads `host`. So the gate and the runtime read two different fields, and the gate trusted the one the caller writes. A read of every active install after the fix deployed found none that had used the gap. + +**Repair:** #3287. The four types only Commonly runs (`moltbot`, `internal`, `native`, `managed-agents`) are cloud whatever `host` says. `host: 'byo'` still marks every type that has a real BYO variant: codex, webhook, claude-code and unknown types. + +**Lesson:** a gate must decide on the field the enforcing path reads. A label the caller supplies may narrow a decision, never override it. Before trusting a field in a gate, read what the consumer, here dispatch, actually reads. From 7fc58293a03e958888ae1f1d3d0a845ababa1375 Mon Sep 17 00:00:00 2001 From: Lily Shen <115414357+lilyshen0722@users.noreply.github.com> Date: Sun, 1 Nov 2026 16:52:05 -0800 Subject: [PATCH 2/2] docs(ax): state which types host: 'byo' still affects, and mark the Sentry consent as inferred Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_015AKgpQ2pr6xRMhN5mcfoHF --- docs/development/agent-experience-audit.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/development/agent-experience-audit.md b/docs/development/agent-experience-audit.md index dfe73e687d..feaff37694 100644 --- a/docs/development/agent-experience-audit.md +++ b/docs/development/agent-experience-audit.md @@ -4278,7 +4278,7 @@ Two different things went into that 191 s, and neither was a 120 s window. First *Origin: the first draft of #3283, on 2026-11-01, said a vendor had removed a hosted-MCP tool. It had not.* -When a pinned hosted-MCP tool was missing from a connection's `tools/list`, the `tool_unavailable` detail read `upstream no longer lists X`. That reads as a vendor removal. But the check only sees one connection's list, and the list depends on what that row's owner consented to. Sentry offers `update_issue` only with its Triage skill. The Linear smoke row lists 26 pins as absent because its scope is read-only. The tool was there; that connection had not been granted it. +When a pinned hosted-MCP tool was missing from a connection's `tools/list`, the `tool_unavailable` detail read `upstream no longer lists X`. That reads as a vendor removal. But the check only sees one connection's list, and the list depends on what that row's owner consented to. Sentry appears to offer `update_issue` only with its Triage skill (inferred from a captured list, not recorded). The Linear smoke row lists 26 pins as absent because its scope is read-only. The tool was there; that connection had not been granted it. **Repair:** #3286 rewords the detail to `this connection's tools/list does not include X`. For the same reason an absent tool files no drift card. Only a schema that moved under its pin does. @@ -4290,6 +4290,6 @@ When a pinned hosted-MCP tool was missing from a connection's `tools/list`, the `isCloudRuntime` (`backend/services/agentIdentityService.ts`) decides which installs need the `cloudAgents` entitlement. It returned "BYO" for any install whose `config.runtime.host` was `'byo'`, before it looked at `runtimeType`. The install route stores the caller's `config.runtime` as given, `host` included. Dispatch decides where a turn runs from `runtimeType` alone (`inProcessInstallationFrom` in `agentEventService.ts`) and never reads `host`. So the gate and the runtime read two different fields, and the gate trusted the one the caller writes. A read of every active install after the fix deployed found none that had used the gap. -**Repair:** #3287. The four types only Commonly runs (`moltbot`, `internal`, `native`, `managed-agents`) are cloud whatever `host` says. `host: 'byo'` still marks every type that has a real BYO variant: codex, webhook, claude-code and unknown types. +**Repair:** #3287. The four types only Commonly runs (`moltbot`, `internal`, `native`, `managed-agents`) are cloud whatever `host` says. `host: 'byo'` still makes a codex install BYO; webhook, claude-code and unknown types are BYO either way. **Lesson:** a gate must decide on the field the enforcing path reads. A label the caller supplies may narrow a decision, never override it. Before trusting a field in a gate, read what the consumer, here dispatch, actually reads.