Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions docs/development/agent-experience-audit.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 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.

**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 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.
Loading