Skip to content

Hold the carried-channel matrix to what go-sdk does, so an SDK bump that changes a refusal channel fails its own pull request #997

Description

@jmrplens

The tenant policy register that lands with #565 carries a carried-channel matrix, tenancy.Carriages() in internal/tenancy/channels.go: for each MCP method and protocol era, the channels a refusal can reach a caller through (a JSON-RPC error and its code, a tools/call result with isError, an HTTP status from the gate, a closed stream). Its own comment says what it is: "what go-sdk v1.8.0 does rather than what the protocol would permit", and "an SDK upgrade that changes what is carried edits this table in the same pull request".

Nothing enforces that sentence. The matrix was written from a probe I ran by hand against go-sdk v1.8.0 (nine tests driving an SDK server in process over httptest, both eras, stateless and stateful, logging what arrived on the wire and asserting nothing), and that probe is not in the repository. Dependabot bumps go-sdk weekly, and a bump that changes a channel would merge green with a matrix that no longer describes the server; the register's Validate would then accept or refuse rows against channels the SDK no longer carries.

The ground is moving. Three of our own go-sdk pull requests and one issue touch how a request is answered or ended, and #961 tracks them:

What to do

Turn the probe into an asserting integration test in the main module that holds tenancy.Carriages() to what the pinned go-sdk actually does, so the pull request that bumps go-sdk fails when a channel changes and names the row.

  • Place it beside the matrix, as internal/tenancy/channels_integration_test.go in package tenancy_test (the external-package qualifier the test-file naming rule allows). go-sdk is already a dependency of the module, and a test import does not reach the server binary, so internal/tenancy stays a leaf in production; TestDependencies_TestSupport_NeverReachesTheServerBinary keeps holding.
  • For every Carriage row, drive the SDK in the era the row names and assert that each listed channel is observed and that no unlisted refusal channel is. The pseudo-methods the SDK does not own (http, startup, eviction) stay out; expiry is the SDK's and is in.
  • Keep as assertions the facts the probe observed that other decisions rest on without being matrix rows: which middleware error codes reach the client unchanged, how load shedding answers, that a typed nil result is handled the way the register assumes (the probe isolates that one in a subprocess of the test binary, and the test should too), and that SubscriptionsListenResult cannot be constructed by application code, which listenStreams and CLAUDE.md rely on.
  • On failure, the message names the row, the era, the channel expected and the channel observed, and says that the fix is an edit to channels.go in the same pull request.

Done when

  • The test runs in the ordinary unit suite (go test ./internal/...), in process, with no Docker and no network, and passes against go-sdk v1.8.0.
  • Changing one channel in Carriages() makes it fail with a message naming that row.
  • docs/development/tenant-policy-spec.md (Refusal channels) and the comment on Carriage say that the matrix is now checked against the SDK rather than asserted by it.

Sequenced after the #565 stack merges, since the matrix arrives with it, and before the work on #961, where it pays off first.

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

    enhancementNew feature or requestmcpMCP capabilities beyond tools: resources, prompts, completions, subscriptions, elicitationtransportstdio and HTTP transports, the server process, and the transport e2e modulesv3.1.0Targeted at the 3.1.0 release

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions