Skip to content

Agent-facing docs state four numbers the code disproves, and root AGENTS.md predates the output-schema change its first recipe depends on #602

Description

@serge-ivo

Four numbers in the agent-facing docs are wrong against the code, and root AGENTS.md predates a contract change its own first recipe depends on

All verified against source 2026-08-15. pnpm docs:drift passes all 13 checks with these present — see the companion guard-gap issue.

Hard errors

location says actual
workers/mcp/AGENTS.md:15 "18 of the 124 registrations are gated" 19 of 136 (tool-count.ts: MCP_TOOL_COUNT = 136, MCP_TOOL_ALWAYS_ON = 117)
workers/mcp/CLAUDE.md:83 "31 in index.ts … 13 in storage-tools.ts, and 88 across instance-tools/" 31 + 13 + 92 = 136. The doc's own arithmetic gives 132 and never reaches its own headline
workers/mcp/CLAUDE.md:87,96 "86 instance tools", present tense 86 is historical. contract.test.ts:29 uses it correctly as history ("while 67 of the 86 … lived in one 1871-line file")
workers/mcp/CLAUDE.md:228 "server.json and platform-docs/mcp.md restate it and docs:drift fails when any of the three disagree" Four statements. The omitted one is store/.well-known/mcp-server.json
README.md:416 biome "packages workers/mcp: the two trees", listing workers/api ~234, store/** ~54, agents/coder 1 as blocked ci.yml runs packages workers store agents/coder; its own comment says "Every tree is now in." All three landed 2026-08-07

CLAUDE.md:228 is the sharpest: the statement it omits is the one #573's first pass already missed oncescripts/lib/wire-surface.mjs:285 exists precisely because of that miss. The doc reproduces the original bug in prose.

Root AGENTS.md — stale by omission, and standing on a changed contract

Last commit 2026-06-22. Nothing in it is false: every rule, tool name and both flows were traced and still behave as described; dry_run, the exact-confirm rule and mcp_audit_log are all correct. For a two-month-old contract that is a better result than expected.

The problem is what it cannot tell a caller, and one item is a contract change it sits directly on top of: its first recipe opens with list_agents, whose payload is now {"agents":[…]} and no longer a bare array (tool-metadata.ts:344, same for my_instances). A consumer following this file literally breaks.

Also absent, all verified present in code:

  • tool annotations readOnlyHint/destructiveHint (tool-metadata.ts:98) — these make its own rule "prefer read-only tools" mechanically answerable instead of a judgement call
  • the server instructions block sent on initialize (index.ts:45)
  • RUN_HEALTH_STATESfour members incl. ended (work-report.ts:93), and ended is the common answer since runHealth() returns it for any status !== "running"
  • lastAliveAt (heartbeat) vs lastProgressAt (instruction advance) as different facts; runHealth deliberately reads liveness only (work-report.ts:179)
  • TOOL_TIERSfour (builtin-tool-policy.ts:57); TOOL_REACHES — three, failing closed at internet (tool-reach.ts:71)

The verdict field lists omit the two fields that answer the questions

workers/mcp/AGENTS.md:62 lists (allowed, scope, disabled, reason, tier, invocableBy); workers/mcp/README.md:~340 lists (allowed, scope, disabled, reason). Both omit mutates and reach.

Neither recommends connector as the reach proxy — that specific wrong advice was removed by #585 and is genuinely gone. But naming scope while omitting mutates leaves the same wrong inference available, and tool-registry.ts:149 says outright that mutates is the field that answers it.

Already correct — leave alone

  • workers/mcp/README.md's tool table: 136 rows, exact match against registration per the gate; the coding_timeline row is present and accurate.
  • workers/mcp/AGENTS.md rule 3, "this server does not set isError": still true. registration.ts:114-116 attaches structuredContent: {error: …} rather than letting the SDK's validateToolOutput rejection fire, closing the one path that could produce it.
  • SECURITY.md:38's write-consent gate. Missing (additions, not corrections): the mutates/scope distinction, fail-closed reach, the append-only surface lock (The surface lock can be rewritten in place, so a silent surface change is still shippable #576), the status-domain guard.
  • README.md:331-332,358-359 correctly names the tool table and tool-count.ts as sources.

One documented behaviour narrower than the code

AGENTS.md:36 frames the runtime flow as "when local Playwright is needed". The flow and register_instance_runtime exist and work, but the transport is now the unconditional WebSocket relay and the runner serves coding engines as well as browsers. Narrower framing, not a false claim.

Acceptance criteria

  1. All five numeric errors corrected against their cited source.
  2. Root AGENTS.md states the {"agents":[…]} / {"instances":[…]} payload shape — this is the one that breaks a caller.
  3. Annotations, server instructions, and the mutates / reach / four-value tier and RunHealth vocabularies are documented where a calling agent will read them.
  4. reach and mutates added to both verdict field lists.
  5. The four security mechanisms added to SECURITY.md.
  6. README tool table untouched — it is exact.
  7. pnpm docs:drift and docs:build green. Baseline is green today, so any red is yours.

Verified vs inferred

  • Verified: every file:line; the per-file .tool( counts; the four-way version statement set from the gate's own output; ci.yml's biome invocation; both flows in root AGENTS.md traced end to end.
  • Inferred: nothing.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions