Skip to content

A token answer names no tenant_id when the credential opens no single account, and the root lists the tenants it opens - #117

Closed
riccardone wants to merge 1 commit into
mainfrom
spec-37-root-credential-tenant
Closed

riccardone wants to merge 1 commit into
mainfrom
spec-37-root-credential-tenant

Conversation

@riccardone

Copy link
Copy Markdown
Contributor

Entries 2 and 23 on #37 (#37), proven by best-peer 0.0.22 and best-mcp 2.6.0 in #62's run.

Why

The token answer's tenant_id is "the account the credential opens", and the credential block's endpoint is "the tenant endpoint on a multi-tenant host". A credential can open no single account, though. One case is a service without tenants (entry 2). The other is a credential admitted at the root of a host where one identity holds as many tenants as it creates or is invited into, or none yet (entry 23, a best-peer workspace). best-peer used to answer the host as tenant_id. A consumer expanding tenants.manifest with it reached no account and got NO_SUCH_WORKSPACE. best-mcp and best-cli worked around it.

Since behavioralstate/best-peer#51 the root's token answer names no tenant_id. best-mcp 2.6.0 (#84) works at the root's endpoint and reaches each workspace the credential opens as <name>/<tenantId>. The acceptance run in #62 drove a workspace that way from the manifest alone, and #73 is closed on it.

What

  • Agent Registration: a new paragraph, after the credential block. A credential that opens no single account has no tenant_id, its endpoint is the root service's, and tenant_id is never the host or another stand-in. A service with tenants that answers this way must list, at its root, the tenants such a credential opens, each with tenant_id, endpoint and manifest. It does so through its tenants root (rule 6), or, where the root is itself a surface, through a query of its own catalogue. This is required from 0.10.0. Where rule 6 points an error at the token answer, such a credential's answer is its endpoint.
  • Agent Navigation Guide: the multi-tenant router row and step 3 cover the answer with no tenant ID.
  • specs/identity-and-registration.md: the walkthrough gains the same case.
  • specs/conformance.md: a new Root Manifest Rule 8, also named in the list of what 0.10.0 makes required.
  • protocol/v1/schemas/discovery.json: the tokenUrl description says when tenant_id is absent.

This change states the catalogue-query case in its own words, the same words as #104 (entry 25), and does not touch rule 6. It reads the same whichever of the two lands first, and it merges clean with every open PR.

No version bump and no release notes here: the PRs from #37 do not collide that way, and the release that gathers them does both.

🤖 Generated with Claude Code

… account, a service without tenants or a root credential of a host where one identity holds several tenants or none yet, and its endpoint is then the root's (entries 2 and 23 of #37)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
riccardone added a commit that referenced this pull request Oct 22, 2026
… account, and the root lists the tenants it opens

Entries 2 and 23 on #37 (#37), proven by best-peer 0.0.22 and best-mcp 2.6.0 in #62's run. Landed from #117.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
riccardone added a commit that referenced this pull request Oct 22, 2026
… that states it, dates each new obligation Required from 0.10.0 and lists it in both conformance lists, and settles the clashes between its changes

Findings of the four spec-reviewer runs on main (the batch of #87 to #117):
- fixed: the agent guides (specs/agents commands, events, queries, workflows), discovery.md, design-decisions.md, identity-and-registration.md, the transport table, the conformance status table, the OpenAPI document, cloudEvent.json and best-mcp's tool text still said what the batch changed in SPEC.md (the state refusal, restarts, idempotency, correlation for life and by sender, completes, no event catalogue, an unknown Last-Event-ID, RFC 3339 bounds, the parameters schema, workflows active only with a recipe, a credential's end).
- fixed: new obligations had no Required from version and no conformance line (correlation on later facts, writeOnly, waiting, forgetting, workflows active, a credential's end, cleartext refusal and outbound calls, request records, the 413 forwarding and 429 rules); each is dated 0.10.0 and both conformance lists gain item 12 (correlation ownership, which the conformance page lacked) and item 13, with one aligned sentence on what 0.10.0 requires.
- fixed: step 4 refused a command with no room while Commands That Wait accepted it; step 4 now refuses only what no capacity could ever hold, a caller asks to wait by naming a bound, a service that lets commands wait lets the caller bound it, a waiting command waits again after a restart, and the stop command's antecedent is stated.
- fixed: "BEST defines no timeout protocol" now excepts Commands That Wait; completes lists every outcome, a failure included, and a document without it leaves every produces event a possible outcome; progress_pct is defined (in data, 0 to 100).
- fixed: idempotency is scoped to the credential in SPEC.md and security.md (no more "authenticated source"); a safely ignored duplicate keeps the original's status; a rejected one is a 409 naming the id; the condensed replay bullet agrees; the no-collision parenthetical is qualified by correlation ownership; writeOnly fields are left out of the payload comparison and a resend takes a new id.
- fixed: http.events in the credential block is the event log, not a catalogue.
- fixed: the TLS paragraph no longer contradicts its own exceptions, and the operator's statement covers outbound calls too.
- fixed: a credential's end (streams ended, approver's bound refused not shortened, expires_in for a bounded durable credential) is normative in Agent Registration, not only in the non-normative section.
- fixed: Root Manifest Rule 3 carries the own-authentication discriminator and Rule 2's example is qualified; rule 6 and Rule 7 require a tenants root (or a catalogue query) for a credential answered with no tenant_id, never the cannot-tell error, and the error points at the answer's tenant_id only where it has one; the no-tenant_id paragraph defers to rule 6; the navigation row is conditional on the answer.
- fixed: events are immutable but for forgotten content; a forgotten event keeps every required envelope attribute and carries forgotten: true, its schema allowing the removed content to be absent.
- fixed: the query string's values are strings, so a parameters schema declares strings; the envelope time is RFC 3339.
- fixed: the SDLC no longer has a minor version go up on its own: a release is a patch unless the owner asks.
- set aside, to spec#37 as new entries: how a generic client finds a root's tenant-listing query; event types no command produces; a correlation that outlives its credential; token_type for a query-borne or non-Bearer credential; the shortest retention window; the port in a default connection name.
- answered: mcp in the credential block is `{ "<name>": { ...server entry } }` as written, no mcpServers wrapper; the bound on pending registrations behind a proxy is the proxy's, and a refusal is a 503 with Retry-After; a stream bound is stated in the service's documentation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@riccardone

Copy link
Copy Markdown
Contributor Author

Landed on main as 2ac0122 under the repository's new process (SDLC.md: every change on main after the local gate and the review). The review of the whole batch is in the Review: commits after it, up to 5603cb1. Closing this pull request.

@riccardone riccardone closed this Oct 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant