Service and family compatibility
Rendered from contracts/service/compatibility.md by connectors-docs; the source owns every rule on this page.
Status: proposed specification; the first v1alpha2 invoke binding (§2.1) is implemented, and no other new runtime codec or route is. This is the compatibility owner for story:contracts-wire-compatibility (E02), reviewed against 3ba2d29. It supersedes local “optional/additive/no wire change” and version/projection defaults in the family documents. Configured service v1alpha1 records the existing implementation; governed service v1alpha2 supplies the proposed admission semantics subject to this binding. Individual stories still own family behavior. A compatibility disposition is not implementation support.
1. Independent version axes
| Axis | Rule |
|---|---|
| Semantic family and profile | operations/v1alpha1 may gain a proposed mutation profile without becoming operations/v2. Each selected profile retains its stated meaning; a changed meaning needs an explicit new profile/version and refusal by readers that do not support it. |
| Service envelope | The implemented closed v1alpha1 envelope cannot accept new members or enum values, even optional ones. The proposed extended envelope is named v1alpha2 here. This selects the local specification's binding identifier, not a release or rollout. |
| Adapter authoring kind | connectors.adapter/v1 and /v2 are Connectors compiler input formats. Neither implies a service-wire version. No kind/schema is renamed or modified by this decision; future strict-reader extensions need their own compatibility decision and vectors. |
| Configuration and generated artifacts | Receiver configuration, bundle/index formats and generated manifests have their own readers/digests. A service-wire bump does not authorize a new field there. Reject unknown keys/formats; regenerate through their owning compiler. |
| Stream/control/data binding | A unary service envelope does not encode WebSocket control, media frames, callback proofs or secret entry. Each needs an explicitly selected, versioned binding with complete framing and limits. |
| CLI/product labels and historical protocols | Repository “v2”, a CLI migration name and old v0alpha* operation protocols are not any of the versions above. A client binary may implement several codecs; it selects exactly one per interaction, without fallback or resend. |
More columns: swipe horizontally, or focus the table and use the arrow keys.
Adding a new operation-local schema under the existing input/result JSON slots is representable without extending the envelope. It does not make the new profile understood by an old typed consumer. Such a profile must be explicitly supported by the caller and every selected hop; existing closed payload types (Page, QueryResult, observations) do not accept arbitrary new fields merely because their outer envelope uses JSON.
2. Deterministic binding selection
The proposed extended binding uses GET /v1alpha2/describe and POST /v1alpha2/invoke, with envelope/descriptor version: "v1alpha2". Existing /v1/describe and /v1/invoke remain the legacy v1alpha1 binding. Path selection resolves describe's missing request-version problem. A configured endpoint plus this fixed path identifies the binding; a discovery observation cannot switch the endpoint, credential, version or profile. No query/header/body override chooses a different codec on that path.
A client chooses its codec before describe. On the extended route, successful describe returns the common §5 Response with request_id: null, status: success and result containing the complete Descriptor; both version fields must equal v1alpha2. Describe failures use the same Response with status: error and no result. The legacy describe route retains its bare Descriptor success shape. The client checks the selected envelope and descriptor versions, exact schemas, instance/revision and required contract/profile support, then invokes that same binding. No client correlation id is invented for GET describe. /healthz establishes no version, profile, provider or admission support. Unknown/missing routes or incompatible descriptors stop selection; the client does not try a second route/version/credential or resend the request. A raw HTTP 404 or malformed response is not renamed into proof that a particular version is unsupported. An explicit operator reconfiguration is a new interaction.
A future v1alpha2 service exposes a legacy path only through the explicit projection in §3. With projection disabled, it may provide the legacy path's bare v1 Error with code unsupported, without provider dispatch; this small refusal endpoint advertises no legacy operations. Unrecognized paths may return ordinary HTTP route failures. Neither behavior describes today's old binaries as capable of negotiating the new codec.
On each invoke route, the selected codec strictly decodes the bounded envelope, then checks that its version equals the route's version before any policy-dependent business dispatch. Unknown/duplicate fields are refused; a decoded wrong version gives unsupported. Early errors on the proposed route use §5's explicit pre-envelope form. On the implemented legacy route, preserve the actual distinctions below.
| Bytes presented to current v1alpha1 implementation/reader | Actual baseline result |
|---|---|
| Unchanged descriptor, invocation, success or error | Accepted subject to existing auth/revision/input checks. |
Descriptor in old shape, version: v99 | Current client decodes the shape, then reports unsupported. |
| Descriptor with new root or operation member | Current client reports upstream_protocol before its version comparison. |
Invocation in old shape, version: v99 | Host returns correlated v1alpha1 Response, error.code: unsupported, zero adapter calls. |
Invocation with connection, approval, executor or another unknown member | Host returns bare Error, invalid_input, before dispatch, even if a different version is also supplied. |
| Missing/invalid service credential or malformed/oversized request | Existing admission/framing failure may be a bare Error rather than a correlated Response. |
| Success/error response with a new member, or nested unknown error code/member | Strict response/error decoding refuses it. The current client's fallback can report an HTTP-derived error or upstream_protocol; it does not generally translate invalid_input to unsupported. |
| Shape-compatible response with wrong version or request ID | Current client reports upstream_protocol for correlation/version mismatch. |
More columns: swipe horizontally, or focus the table and use the arrow keys.
Source: core, server, client. Decoding failure is not evidence about a provider effect. A new mutation client that has sent an invocation and lacks a valid definitive response reports outcome uncertainty and never retries automatically, even if an HTTP failure resembles a version problem.
The proposed read-refresh-once/v1alpha1 binding is an explicit observable change (F15/E05), available only on v1alpha2. An adapter authors the exact combined native profile P.read-refresh-once.v1alpha1 in the existing singular Operation.profile, with the complete native schemas, required managed auth profile and changed projection revision. Clients must support that complete profile before invocation. The suffix alone proves no support and introduces no retry flag, second profile member or adapter-kind field. Existing profiles retain their stated no-retry behavior; no current adapter selects this proposal. The first binding excludes generic, mediated/federated, anonymous/static-config, streaming and mutation execution.
2.1 First binding: POST /v1alpha2/invoke
Status: implemented. The host serves it and connectors-client reads it (Client::invoke_v1alpha2, and Client::invoke_v1alpha2_keyed to send a key to a host with standing grants). The first v1alpha2 binding a host serves is invoke alone, under the static-bearer admission profile or the service-account-token profile its configuration selects (Admission, below). It exists so that an admitted write names the attempt the host recorded for it. A host whose service configuration sets standing_grants also runs keyed writes under a standing grant (Keyed writes under a standing grant, below); a host without it follows every other rule of this section as written, and that row says where a host with it differs. The request and Response are connectors.service_wire.InvokeRequest and connectors.service_wire.InvokeResponse in service_wire.yaml; this section owns their rules on this binding, and the rest of this document applies wherever it does not narrow it.
| Concern | Rule on the first binding |
|---|---|
| Routes | Only POST /v1alpha2/invoke is served. GET /v1alpha2/describe is not served yet: it is an ordinary unrecognized route with no envelope (§5, last paragraph). Describe stays on the legacy GET /v1/describe and its bare Descriptor. A client describes there and invokes v1alpha2 with that descriptor's revision; this is the one exception to §2's "invoke that same binding", and it ends when the describe binding is specified. The legacy Descriptor carries no §4 metadata, so describe does not tell a client which operation writes. |
| Service configuration | The host reads its service configuration as urn:connectors:config:v3:service (connectors.declarations.ServiceHostConfiguration): urn:connectors:config:v2:service plus the optional admission members admission, audience, principal, principals, service_accounts and token_review (Admission, below), with service_credential present exactly under static-bearer, and the optional standing_grants, the path of a standing grant file, which requires state (start is refused without it; Keyed writes under a standing grant, below). urn:connectors:config:v2:service is urn:connectors:config:v1:service plus an optional state, a directory path. The v1 and v2 identifiers stay readable and unchanged, and a v1 or v2 document reads under v3 with the same meaning and the same serialized bytes; each reader stays closed, so state under the v1 identifier and any admission member under the v1 or v2 identifier are refused. An adapter that moves its import to v2 or v3 changes its descriptor revision (adapter v1 semantics, Shared configuration schemas). state is required to serve this route: the host keeps its audit anchors and its attempt records in the local metadata authority in that directory (audit §4 bounds and retention). A host without state serves only /v1/* and answers POST /v1alpha2/invoke with error/unavailable (HTTP 503), request_id: null, audit_status: unavailable, audit_ref: null, before decoding and with zero adapter calls. |
| Admission | The configuration selects one profile for the whole host. static-bearer, the default when admission is absent: the Authorization: Bearer value is compared in constant time with the bytes of service_credential, resolved at each request. service-account-token: the configuration names one audience (1 to 256 bytes), the TokenReview endpoint token_review: {api, ca_file, credential_file}, and the admitted service accounts in exactly one of three members: principal, one account of the form system:serviceaccount:<namespace>:<name> (a DNS-label namespace and a DNS-subdomain name, at most 128 bytes, the principal_ref bound of audit §4); principals, a list of 1 to 64 such accounts; or service_accounts: {namespace, name}, a literal DNS-label namespace and a name pattern of 1 to 128 bytes of a-z, 0-9, -, . and *, whose only wildcard * matches any run of characters, none included, and which must match the whole name; read with each * as one letter, the pattern must be a DNS-subdomain name and system:serviceaccount:<namespace>:<that name> must fit in 128 bytes, so a pattern no account name can match (-*, *-, a..b) is refused. None of the three, two or three of them, an empty or longer list, an entry not of the account form, and an empty or invalid pattern or namespace are refused at start, with a message naming the key; the configuration schema refuses the same documents, except that it bounds the namespace and the pattern each alone, and start checks that they fit in 128 bytes together. service_credential, audience, principal, principals, service_accounts and token_review are each absent or a value: a member present as null is refused by the schema and the reader alike, never read as absent. For each request the host takes the Authorization: Bearer token; a missing or empty one is unauthorized before any review. It then sends one TokenReview (apiVersion: authentication.k8s.io/v1, kind: TokenReview, spec: {token, audiences: [<audience>]}) by POST to <api>/apis/authentication.k8s.io/v1/tokenreviews, over HTTPS rooted only in ca_file, with no proxy, redirect or retry, authenticated by the instance's own token read from credential_file at each review (a regular file of at most 8 KiB, no symbolic link as the last path component, so a projected token is named <mount>/..data/token; private and owned by the effective user, or, for this file alone, exactly 0640 or 0440, owned by the effective user or root, its group the effective or a supplementary group of the process). It admits the call only when the answer is a 2xx whose status.authenticated is true, whose status.audiences contains audience, and whose status.user.username is an admitted account: equal byte for byte to principal or to an entry of principals, or, under service_accounts, of the account form within 128 bytes, with a namespace equal to namespace byte for byte and a name the pattern matches. A decoded answer that fails any of the three is unauthorized (HTTP 401). A review that cannot be sent, times out (5 seconds), answers any other HTTP status, exceeds 64 KiB or does not decode is unavailable (HTTP 503): admission fails closed, and an unusable instance token is unavailable too, never the caller's unauthorized. At most 8 reviews are in flight at once: a request that finds all 8 under way is unavailable (HTTP 503) at once, with no review sent and nothing queued, so callers presenting any bearer cannot drive unbounded reviews against the instance's own account. Each is a refusal before the anchor, with request_id: null, audit_ref: null, audit_status: unavailable and zero adapter calls; a host without state still answers its 503 before any review. No review answer is cached across requests, and the presented token is never logged, recorded or echoed. |
| Host start | A host with state records its instance as the connectors.declarations.ServiceConfiguration its anchors and attempts reference, before it serves this route, idempotently: absent, it records it; present with the same adapter and revision, it changes nothing; present with the same adapter and another revision, it advances the registry epoch; present with another adapter, start is refused. |
| Admitted members | The closed envelope admits the five original members with their v1alpha1 meaning and checks: version, request_id, operation, revision, input (service v1alpha1). A decoded version other than v1alpha2 gives unsupported with the request ID echoed and no adapter call (§2). |
| Refused §4 members | connection, idempotency_key, approval and executor are refused before dispatch with unsupported (HTTP 400), request_id: null, no mutation and no recorded attempt. Any other unknown member is invalid_input with request_id: null. Neither is a valid envelope of this binding, so neither echoes caller bytes (§5). A host with standing grants admits idempotency_key instead (Keyed writes under a standing grant, below); connection, approval and executor stay refused there. |
Why idempotency_key is refused | Replay under a key needs the receiver-owned keyed reservation, its atomic Prepared attempt and current replay admission of operations §5.1. The HTTP host has no keyed reservation store, so accepting a key would promise a replay it cannot give. Because a keyed operation requires a key and an approval-gated operation requires approval (operations §5.2, §3), an operation whose idempotency kind is keyed or whose approval mode is required or event_claim is not invocable here: unsupported before its attempt is recorded, no mutation. A host whose configuration sets standing_grants keeps that keyed reservation in its state and admits the key under the next row; there the standing grant is the approval of every write. |
| Keyed writes under a standing grant | Only on a host whose service configuration sets standing_grants; a host without it is unchanged, so a write there is dispatched with no key and a key is refused as in the rows above. On a host with it, the reader admits the optional §4 member idempotency_key, a string of 1 to 256 UTF-8 bytes compared as opaque bytes (operations §5.1): an empty or longer key is invalid_input with the request ID echoed, and a null one is not a valid envelope (invalid_input, request_id: null). A key on an operation that is not a write (its host declaration lacks external_write) is unsupported (HTTP 400) with the request ID echoed, before the anchor: only a write's attempt can be replayed. Every operation whose host declaration includes external_write is keyed there, and the operator's standing grant is its approval: the checks below replace operations §4 steps 5 and 8 (architecture-decision-record:standing-scoped-approval; connectors.standing_approvals in standing_approvals.yaml). Before the anchor, in this order, a write meets these refusals, each with the request ID echoed, audit_ref: null, audit_status: unavailable, no mutation, no recorded attempt and zero adapter calls: no idempotency_key is invalid_input (HTTP 400); a key live in the caller's namespace for another request (other input, operation or revision) is idempotency_conflict (HTTP 409) and names neither the stored request nor the differing member; a key reservation store that cannot be read is unavailable (HTTP 503); a grant file that cannot be read safely is unavailable (HTTP 503); a write no grant covers is approval_required (HTTP 403), naming no grant and no axis; a write whose covering grants each admitted max_per_hour writes in the last 3,600 seconds is rate_limited (HTTP 429) with retry_after_seconds, when the earliest slot frees; a use count that cannot be kept is unavailable (HTTP 503). Within one host process, requests with the same caller and key are admitted one at a time: each waits until an earlier one has reserved the key with its attempt or was refused, so a concurrent duplicate of an admitted request is a replay and never rate_limited, even after its grant is revoked, and a concurrent request with other input is idempotency_conflict before the anchor; neither takes a grant use. Before approval_required or rate_limited the key is looked up again, so a request in another process sharing the state directory that reserved it first is replayed instead; one that reserves it between this request's grant check and its attempt makes this request a replay, or idempotency_conflict with its audit_ref, after the anchor. A grant covers a write when it names this host's instance and this operation, every target member it lists (an RFC 6901 pointer into input and its exact JSON value) is present in input with that value, now is before its not_after_unix_ms, and its id is not listed as revoked. The grant file is {format: "connectors.standing-grants/1", grants: [{id, instance, operation, target: [{pointer, value}], not_after_unix_ms, max_per_hour}], revoked: [id]}: at most 64 KiB and 256 grants, each with 1 to 16 target members and max_per_hour 1 to 10,000, ids unique; the host reads it at every write and follows no symbolic link, except, on Linux, the layout a Kubernetes Secret or ConfigMap volume presents: the name is a link owned by root or the host's user whose target is exactly ..data/<name>, resolved through ..data under the checks the mounted_secret custody binding applies to it (custody §5.2). It refuses a parent directory not owned by root or the host's user or writable by group or others (the file's own directory may carry those bits only on a read-only mount), a file that is not regular, group- or world-writable, or owned by another user than the host's or root, an oversized file and any document outside this shape. No file at the configured path admits no write. A changed file takes effect from the next write, with no restart: a grant removed or listed as revoked admits nothing more. An admitted write counts one use of a covering grant in the state directory (standing-grants.sqlite3); its attempt records the key (the keyed reservation of operations §5.1, reserved with the attempt in one transaction) and the grant id. A use for which no attempt is recorded (the anchor or the attempt store refused, or a concurrent request reserved the key first) is released and not counted; a use whose attempt was recorded stays counted, dispatched or not. Replay: the same key with the same operation, revision and input in the caller's namespace is answered from the original attempt with mutation.replayed: true, its attempt and its original_request_id, and with no grant check, no count and no adapter call, under the request's own anchor: a Completed original with its retained result (applied; a result over 64 KiB was not retained and is capacity with applied), an Aborted one unavailable with not_attempted (send the write again under a new key), a Failed one, which the provider definitely refused, its original code and message with refused, an Indeterminate one outcome_unknown. A Prepared or Dispatching original is never dispatched again. If this host process runs it, the replay gives back its in-flight slot and waits for at most 25 seconds, then answers outcome_unknown with cause: {code: timeout, stage: observation}; at most 4 replays wait on one original, and a further one answers outcome_unknown at once with cause: {code: capacity, stage: observation}. Keys, attempts and use counts survive a restart. The host does not recover a pending attempt after a restart, so the replay of an original a crash or restart interrupted answers outcome_unknown at once with cause: {code: unavailable, stage: observation}, never a second provider request. A key is not expired by this host: once used, it replays for as long as its attempt is retained and is never admitted for another request. POST /v1/invoke records no attempt and reads no grant, so on such a host it refuses a write (Legacy binding, below). |
| Response | Every application answer is the §5 Response: version: v1alpha2, request_id (the decoded request's ID, otherwise null), status, exactly one of result/error, audit_ref, audit_status, with the §5 HTTP mapping. The binding emits the 13 base error codes and outcome_unknown; no other extended code. A host with standing grants also emits approval_required and idempotency_conflict (Keyed writes under a standing grant, above). |
| Audit anchor | Every admitted invocation on this binding, read or write, is audited. §5 says admitted reads are "audited under the selected admission policy just like other admitted reads; explicit unaudited static reads alone use not_required", and no explicit unaudited static read profile is selected for this binding, so reads are not exempt. After the pre-dispatch checks pass, the host acknowledges an admitted_execution anchor (audit §1) with hop_role: execution, activity: invoke, access (write exactly when the operation's host declaration includes external_write, otherwise read), the admitted service principal, the operation and the descriptor revision. Under static-bearer the principal's principal_ref is the fixed text static-bearer, qualified by the anchor's instance_id: a static-bearer credential authenticates one receiver-configured service principal (§4, last paragraph), and rotating the credential does not change it. Under service-account-token it is the status.user.username of the review that admitted the request, verbatim, whichever of principal, principals and service_accounts admitted it; a write's attempt records the same principal as its caller. Only then does it record a write's attempt, link it to the anchor (audit §1, Attempt link) and dispatch (v1alpha2 §4, rule 4). A link that fails aborts the prepared attempt as not_attempted and answers error/unavailable (HTTP 503) with zero adapter calls; the anchor stays, its final observation records the refusal, and the response carries its audit_ref and audit_status and the mutation with classification: not_attempted. An anchor write that fails, is ambiguous or meets capacity grants no dispatch. The answer is then error/unavailable (HTTP 503), audit_status: unavailable, audit_ref: null, no recorded attempt, no mutation and zero adapter calls (audit §2, §5). |
audit_status | After an acknowledged anchor, the response carries that record's public audit_ref. It answers complete when the final observation append is acknowledged, and incomplete when the append fails (audit §2; recovery of that one append follows audit §3). incomplete keeps the known read result or mutation classification and grants no redispatch. A refusal before the anchor (pre-envelope, version, member, identifier, revision, lookup, input, the adapter's admission, keyed or approval-gated operation) writes no record on this binding and answers unavailable with audit_ref: null. On a host with standing grants, a key on a read and each write refusal of Keyed writes under a standing grant are refusals before the anchor too. A served catalog instance with catalog.repositories refuses a repository not on its list at the adapter's admission, after input validation, with not_found. not_required is never answered here. |
source_audit | Always omitted: no trustworthy leaf audit observation exists on this binding (§5). Federated invocation is not selected for this binding. |
mutation | Present exactly when the operation's host declaration includes external_write and the invocation passed every pre-dispatch check, so that the host recorded its connectors.mutations.AttemptRecord (operations §4). From that record on, every response carries it: attempt is {instance, id} of that record, original_request_id is this request's ID, replayed: false (no replay on this binding, except on a host with standing grants), and classification/cause follow the §5 table. On a host with standing grants, a replay under a key carries the original attempt, the original request's ID as original_request_id and replayed: true, and each refusal of Keyed writes under a standing grant is a refusal before the record. Absent for reads and for every refusal before the record: version, member, identifier, revision, lookup, input, keyed or approval-gated operation, refused audit anchor. A dispatched write whose answer is lost is error/outcome_unknown/unknown with its attempt and is not retried. The provider's definite refusal of the write, which the adapter answers as refused through its write port (invoke_write_at; a served catalog instance answers so a 4xx its engine classifies as a refusal, such as 405, 409 or 422 to a merge), is error with the refusal's safe code (one of the 13 base codes) and a message that carries the provider's admitted reason, and mutation.classification: refused with its attempt, settled Failed (operations §4 rule 11), cause: null unless the settlement was not stored ({code: unavailable, stage: attempt_store}); a replay of its key answers the same code and message. An adapter that does not override that port answers only a value or a generic error, so after dispatch an adapter error, the deadline, a value its output schema refuses or a value over the result limit is that same unknown with cause: {code, stage} (dispatch for the error and deadline, response for the value); so is a 5xx or a cut connection, which never says the write was not performed. Only a deliverable value is applied. A refused attempt store (capacity, unavailable) is a refusal before the record. A caller that disconnects does not cancel a dispatched write: its settlement and final observation still run. |
| Legacy binding | Under static-bearer, /v1/describe and /v1/invoke are unchanged: no new member, route behaviour or error code, and the same bytes on the existing wire vectors. Under service-account-token, GET /v1/describe admits by the same review as POST /v1alpha2/invoke, because a client describes there (Routes, above); its refusals are the legacy unauthorized (HTTP 401) and unavailable (HTTP 503). POST /v1/invoke answers the legacy unsupported (HTTP 501) before any review and with zero adapter calls: every invocation under this profile is anchored with its service account as the principal, and /v1/invoke writes no anchor. On a host whose configuration sets standing_grants, POST /v1/invoke answers a write (an operation whose host declaration includes external_write) with the legacy unsupported (HTTP 501) before any adapter call, because that route records no attempt and reads no grant; its reads are unchanged. A host without standing_grants is unchanged. |
More columns: swipe horizontally, or focus the table and use the arrow keys.
Conformance scenarios for this binding:
v1alpha2-describe-not-served:GET /v1alpha2/describe→ ordinary route failure, no envelope;GET /v1/describeanswers the unchanged bare Descriptor.v1alpha2-invoke-wrong-version-unsupported:version: v1alpha1on/v1alpha2/invoke→unsupported, request ID echoed, zero adapter calls.v1alpha2-invoke-refuses-connection,v1alpha2-invoke-refuses-idempotency-key,v1alpha2-invoke-refuses-approval,v1alpha2-invoke-refuses-executor: each member alone → HTTP 400unsupported,request_id: null,audit_status: unavailable, nomutation, no attempt recorded, zero adapter calls.v1alpha2-invoke-unknown-member-invalid-input: an unknown member →invalid_input,request_id: null, zero adapter calls.v1alpha2-invoke-keyed-or-approval-operation-unsupported: a keyed write and an approval-gated write →unsupportedbefore dispatch, nomutation, no attempt recorded.v1alpha2-invoke-keyed-write-under-standing-grant: on a host with standing grants, a write withidempotency_keythat a standing grant covers → one provider request,mutation: {classification: applied, attempt, original_request_id: <request_id>, replayed: false}; the attempt records the grant id.v1alpha2-invoke-keyed-replay: on a host with standing grants, the same key, operation, revision and input again under another request ID → the original result,mutation.replayed: truewith the original attempt andoriginal_request_id, its ownaudit_ref, no second provider request and no second count againstmax_per_hour; the same key with other input → HTTP 409idempotency_conflict, nomutation, zero adapter calls.v1alpha2-invoke-write-outside-grant-refused: on a host with standing grants, a write of another operation or instance, to another target, missing a target member, afternot_after, of a revoked or removed grant, or with no grant file at the path → HTTP 403approval_required; a write overmax_per_hour→ HTTP 429rate_limitedwithretry_after_seconds; a write withoutidempotency_key→ HTTP 400invalid_input; a grant file that is a symbolic link, writable by others, oversized or malformed → HTTP 503unavailable;idempotency_keyon a read → HTTP 400unsupported. Each with the request ID echoed,audit_ref: null, nomutation, no attempt recorded, zero adapter calls. A write onPOST /v1/invokethere → HTTP 501unsupported, zero adapter calls.v1alpha2-invoke-read-audit-complete: a successful read →status: success, non-nullaudit_ref,audit_status: complete, nomutation, nosource_audit; the anchored record has its final observation.v1alpha2-invoke-write-audit-complete: a successful write → non-nullaudit_ref,audit_status: complete; the anchor is acknowledged before the attempt is recorded and before the one provider request.v1alpha2-invoke-write-audit-incomplete: the final observation append fails after a successful write →status: success, the same non-nullaudit_ref,audit_status: incomplete,mutation.classification: appliedunchanged, one provider request.v1alpha2-invoke-audit-anchor-refused: the anchor write fails, for a read and for a write → HTTP 503unavailable,audit_status: unavailable,audit_ref: null, nomutation, no attempt recorded, zero adapter calls.v1alpha2-invoke-without-state-unavailable: a host configured withoutstate→POST /v1alpha2/invokeanswers HTTP 503unavailable,request_id: null,audit_ref: null, zero adapter calls, for any body;/v1/invokeanswers as before.v1alpha2-config-v1-service-still-read: aurn:connectors:config:v1:serviceconfiguration is read unchanged;stateunder v1 is refused; the same configuration withstateunderurn:connectors:config:v2:serviceis read.v1alpha2-host-start-records-instance: two starts of the same configuration → oneServiceConfigurationfor the instance; a start naming another adapter for a recorded instance is refused.v1alpha2-invoke-anchor-principal-static-bearer: an admitted invocation → its anchor'sprincipal_refisstatic-bearerunder the host's instance, and stays so after the credential bytes rotate.v1alpha2-invoke-write-link-failed-not-attempted: the attempt link fails after the write's attempt is prepared → HTTP 503unavailable,mutation.classification: not_attemptedwith the attempt, the attempt aborted, zero adapter calls; the anchor's final observation records the refusal.v1alpha2-invoke-write-applied-names-attempt: a successful write →mutation: {classification: applied, attempt: {instance, id}, original_request_id: <request_id>, replayed: false, cause: null}; the host'sAttemptRecordunder that id reads back.v1alpha2-invoke-write-refusal-before-attempt-has-no-mutation: a write refused for stale revision, unknown operation or invalid input → error, nomutation, no attempt recorded.v1alpha2-invoke-write-lost-answer-outcome-unknown: the provider fixture drops the write's answer → HTTP 502outcome_unknown,mutation.classification: unknownwith the recorded attempt, one provider request.v1alpha2-invoke-write-provider-refusal-refused: the provider answers a served catalog merge 405, 409 or 422 with amessagebody → the refusal's code (forbidden, HTTP 403, for 405;invalid_input, HTTP 400, for 409 and 422) with a message carrying the provider'smessage,mutation.classification: refusedwith the recorded attempt, one provider request; the same key and input again → the same error,replayed: true, no request; a 502 answer or a connection cut before the answer → HTTP 502outcome_unknown,unknown, one provider request.v1alpha2-invoke-read-has-no-mutation: a read, success or error → nomutation.v1-invoke-unchanged-by-v1alpha2: the existing/v1/invokewire vectors → byte-identical answers to the previous release.v1alpha2-service-account-token-admitted: a host underservice-account-tokenwhose review authenticates the presented token for the configured audience as the configured principal → the invocation is admitted and answers as understatic-bearer; the one review names that token and exactlyaudiences: [<audience>]and carries the instance's own token; the anchor'sprincipal_refis the configured principal.v1alpha2-service-account-token-other-principal: the review authenticates the token as another service account, does not authenticate it, or authenticates it for another audience → HTTP 401unauthorized,request_id: null,audit_ref: null, no anchor, zero adapter calls; a request without a bearer is the sameunauthorizedbefore any review.v1alpha2-service-account-token-review-unavailable: the review answers an error status or its endpoint is unreachable → HTTP 503unavailable,request_id: null,audit_ref: null, no anchor, zero adapter calls; the next request sends a new review.v1alpha2-service-account-token-review-bound: 8 reviews in flight → the next request on/v1alpha2/invokeor/v1/describeis HTTP 503unavailableat once,request_id: null,audit_ref: null, no review sent, no anchor, zero adapter calls; once a review is answered, the next request is reviewed again.v1alpha2-service-account-token-listed-accounts: a host whoseprincipalslists two accounts → a review naming either is admitted, for a read and a write, and the anchor'sprincipal_refis that reviewed username; a review naming a third account, a longer name with a listed one as its prefix, an account of another namespace, or a listed one in another case or with surrounding bytes → HTTP 401unauthorized, no anchor, zero adapter calls.v1alpha2-service-account-token-account-pattern: a host whoseservice_accountsis{namespace: agents, name: "*-agent"}→ a review naming an account ofagentswhose whole name matches is admitted, and the anchor'sprincipal_refis that reviewed username; a name the pattern does not match end to end, another namespace, a namespace in another case, and a username not of the account form or over 128 bytes (also under the bare*) → HTTP 401unauthorized, no anchor, zero adapter calls.v1alpha2-service-account-token-account-set-config: none ofprincipal,principalsandservice_accounts, two or three of them, an empty list or one of 65 entries, an entry not of the account form, an empty pattern or one with another wildcard, an upper-case letter, a:or over 128 bytes, a pattern no account name can match (a dot or hyphen at a label's edge, an empty label, a label over 63 bytes), and a namespace that is empty or holds*→ refused by the configuration schema and at start, with a message naming the key; a pattern one byte past the namespace's share of 128 bytes → refused at start; any ofservice_credential,audience,principal,principals,service_accountsandtoken_reviewpresent asnull, under either profile → refused by the schema and the reader; a one-entry list, 64 entries, the bare*and a pattern without*are read.
3. Legacy projection and federation intersection
Projection is off by default, permitted only for an explicitly configured static-bearer read surface whose complete semantics are unchanged. The receiver maintains an explicit eligible operation set. Eligibility requires the original input/output schemas, implicit configured connection, auth behavior, error vocabulary, no-retry policy, limits, cursor/provenance meaning and result visibility to remain valid. An absent external_write flag alone is not proof: exclude every mutation, managed/governed operation, effectful process/local-system/send/session operation and every profile requiring unavailable metadata or behavior. New generation-validation or refresh/retry requirements cannot be silently imposed while calling this the unchanged configured profile.
The extended visibility/refusal matrix applies only to v1alpha2. Its admitted private registry lookup must never be reused to bypass this legacy eligible operation set. A guessed hidden legacy mutation remains not_found, including when a private extended implementation exists but is disabled.
The legacy descriptor uses only the six original Operation fields and the original Descriptor/Error/Response shapes. It has its own projection revision, bound to the exact visible operation set, schemas, eligible binding/configuration and selected wire profile. The legacy invoke path resolves only against that set and revision. A guessed hidden operation is not_found before dispatch; a full/new descriptor revision is not a valid legacy revision. Do not accept a mutation through a hidden name, alternate connection, omitted approval or direct handler lookup. Projection strips new metadata only after proving its absence loses no required meaning; otherwise the operation is unavailable on that binding.
Each gateway route explicitly selects the downstream codec and supported profile intersection. A v1alpha1 leaf cannot perform governed or keyed mutation dispatch on the strength of a broad static credential. No gateway translates unknown outcomes into generic read errors, silently strips approval/context, or retries on a lost answer. The current one-hop read federation remains as documented. The F03 one-hop proposal now selects canonical preparation/approval subjects, receiver/request binding, proof types and nonce versus leaf-only redemption ownership. It remains unadvertisable until its actual binding and conformance exist; the withdrawn HMAC sketch is not a substitute.
4. Extended descriptor and invocation surface
These are closed objects. The original required fields remain; added fields are admitted only by the proposed codec. Optionality here controls emission by new readers/writers, never compatibility with an old reader.
| Object | Added field and exact disposition |
|---|---|
| Descriptor | admission: {profile, audience?} is required; profile selects static-bearer / identity-audience / service-account-token / delegated, and audience is present only for identity-audience and service-account-token. Profile support is advertised only after its binding exists. |
| Descriptor | auth_profiles? is a safe array of {id, purpose, subject, scheme, flow, capabilities, evidence}. All values come from auth.profile/auth.capability/auth.evidence vocabularies. Do not publish provider token/authorize/revocation URLs, registration secrets, credential references or the entire authored profile. |
| Descriptor | connections? is a boolean capability flag, true only when the managed connection surface is implemented and selected. The safe management operations still require their own schemas and admission. |
| Descriptor | provides? is an array of {contract, profile, targets?}; targets is a finite adapter-name array only for mediated-route capability advertising. This metadata does not expose a forward operation. |
| Operation | effects, semantic_effects, risk, idempotency, approval are required in the extended binding, including reads; their value shapes come from operations §3. Unsupported combinations are rejected before advertisement. |
| Operation | requires_auth? is one alternatives array of {profile, scopes} with scopes an array of strings. Its absence means no public auth-profile selector is provided by the configured binding, not anonymous access. Anonymous/parent-auth behavior still requires its explicitly selected profile. |
| Operation | realization? is generic or implemented when catalog curation is provided. unresolved belongs in catalog inventory only and is never callable. |
| Operation | limits is required: {request_bytes, result_bytes, execution_ms, provider_ms, connect_ms} positive integer ceilings; §7 defines first profiles. These are receiver declarations, not caller overrides. |
| Operation | profile remains singular. Generic read uses generic-http; generic mutation uses mutation with realization: generic; generic page uses datasource.records + generic-http-page. Catalog inventory also uses the selected singular profile. profiles[] is not a second runtime field. |
| Invocation | connection? is a nonempty safe managed connection string, never explicit null. It is omitted only when the selected business profile resolves one implicitly, or the selected host-management profile is explicitly instance/acquisition-scoped and rejects a selector. Describe/revoke/repair management requires the exact string. It never supplies credentials or a destination. |
| Invocation | idempotency_key? and approval?: {reference, evidence} follow mutation admission and replay rules. Neither can be smuggled inside business input as envelope authority. |
| Invocation | executor? is an assertion with {agent, revision, authority_snapshot:{id,sha256}}; validation compares it to trusted credential/configuration/grant bindings. It cannot overwrite tenant, principal, realm or authority. |
More columns: swipe horizontally, or focus the table and use the arrow keys.
Static bearer authenticates one receiver-configured service principal, not individual humans sharing its bytes. Its stable principal and configured local tenant/realm absence are independent of credential rotation. An explicit configured local policy supplies its permitted operations/connections; an unavailable governed policy never falls back to it. Governed authentication first establishes tenant/principal/optional realm/current authority and any credential-verified executor. After strict decode, policy verifies any supplied executor assertion and constructs the admitted invocation context. An absent credential executor does not make a body assertion trusted; policy must establish that binding or refuse it. Where an executor was credential-verified, the assertion must match exactly.
5. Extended responses, audit and mutation observation
The durable anchor, single final observation, idempotent append recovery, capacity and retention rules are owned by the proposed execution audit contract. This section remains the public projection owner.
Successful describe is audited under the selected admission policy just like other admitted reads; explicit unaudited static reads alone use not_required. Every extended application response has version, nullable request_id, status (success/error), exactly one of result/error, audit_ref (nullable opaque string), audit_status and optional source_audit. A decoded valid invoke request echoes its request ID. GET describe has no request envelope and always uses request_id: null, including success. Before a valid bounded invoke envelope exists, request_id is null; never invent a correlation or copy malformed input into it. source_audit, when present after a verified downstream response, is {instance, audit_ref, audit_status} identifying the selected origin; it does not replace the gateway's own audit fields. Omit it when no trustworthy leaf audit observation exists.
audit_status is complete (durable final observation), incomplete (durable admission/anchor exists but final observation is unconfirmed), unavailable (no acknowledged durable record, ref null), or not_required (explicit unaudited static read profile, ref null). complete and incomplete require a non-null acknowledged reference; unavailable and not_required require null. Apply the same reference/status consistency to source_audit. References identify only acknowledged records. “Complete” describes the audit observation, not certainty about the business effect: an unknown business outcome can have a complete audit record. Record absence is never replaced by a plausible opaque string.
For audited operations, append/acknowledge an admission record before dispatch for reads as well as mutations; append the final observation separately, linked to that admission. For refusals before valid authentication/decoding, record the known stage and leave unverified tenant/principal/operation/input coordinates absent. Caller data never fills trusted audit coordinates. No single append-only row is claimed to contain a future result before dispatch. Optional mutation-attempt correlation is a reference from audit to the existing attempt; neither ledger owns or cascade-deletes the other.
An unacknowledged admission audit prevents dispatch and gives safe unavailable with audit_status: unavailable, audit_ref: null (or transport failure if no reply can be sent). This is the explicit exception to the former impossible “every refusal has a durable ref” promise. After dispatch, final-audit failure gives incomplete and preserves whatever business outcome is actually known; it cannot turn an applied mutation into not_attempted, or claim a performed read never ran. The durable anchor remains correlatable for idempotent final-observation recovery under the audit contract. Lost/ambiguous acknowledgement is not proof of no record, and neither append recovery nor readback permits redispatch.
After current operation/result admission, a mutation observation is encoded under mutation:
{
"classification": "applied",
"attempt": { "instance": "selected-origin", "id": "00000000-0000-4000-8000-000000000001" },
"original_request_id": "original-request",
"replayed": false,
"cause": null
}
All five fields are required when mutation is present. classification is the settled not_attempted | refused | applied | unknown. attempt and original_request_id are both null until an original attempt identity is safely known and disclosable, otherwise both identify the same original attempt/request; the outer request ID still correlates this delivery. replayed is a boolean, never a classification: true means returning an existing durable outcome under current replay admission. replayed: true requires both original identity fields; it cannot name an undisclosed or hypothetical original. An unresolved waiter may have original correlation with replayed: false. cause is null or {code, stage}: code is a base error code and stage is preflight / attempt_store / approval / dispatch / response / observation / audit. It carries a secondary safe cause such as timeout or failed outcome persistence, without provider messages or private ledger identifiers.
Denied current caller/result admission returns a safe ordinary error without mutation; it says nothing about a possibly existing original effect, record or key. Absence of mutation metadata is never interpreted as not_attempted. After admitting the observation, a preflight/prepare refusal can report not_attempted with null attempt identity; an uncertain lookup may report unknown with null identity. Do not invent an original attempt ref to make the schema look complete.
| Observed business fact | status / error.code | Mutation fields |
|---|---|---|
| Definitive success, result deliverable | success / no error | applied; original attempt identity; optional secondary persistence/audit cause |
| Definitive effect applied, result cannot safely be delivered | error / safe delivery failure such as capacity or upstream_protocol | applied, never changed to unknown merely to fit an error shape |
| Definitive provider refusal proves no business effect | error / original safe refusal code | refused; optional secondary persistence cause preserves the original refusal |
| This admitted new attempt definitely did not cross dispatch gate | error / specific safe cause, such as unavailable or approval_refused | not_attempted; no claim that an approval remains unspent |
| Relevant attempt may have dispatched; no definitive observation | error / outcome_unknown | unknown; optional cause {code: timeout, stage: observation}; missing response is treated conservatively by the caller |
| Exact admitted replay of Completed/Failed/Aborted/Indeterminate | preserve original status/result/code and classification | replayed true; original attempt/request identity; no new spend or dispatch; current delivery audit is separate |
| Pending duplicate waiter expires | error / outcome_unknown unless an authorized definitive original observation exists | unknown with original correlation when known; replayed false; no mutation of the original lifecycle |
More columns: swipe horizontally, or focus the table and use the arrow keys.
Known provider success/refusal remains known even when terminal-store/audit writes fail. Conversely HTTP success or an ordinary provider 5xx does not establish effect certainty. New readers validate these combinations. Success with mutation metadata requires applied; refused/not_attempted/unknown require error. classification: replayed, success+unknown, or unknown without outcome_unknown is a protocol violation. A protocol violation after possible dispatch supplies no retry authority.
The new closed error-code set is the 13 existing codes plus: approval_required, approval_refused, approval_replayed, idempotency_conflict, outcome_unknown, not_granted, stale_authority, connection_not_ready, route_unavailable, route_refused, insufficient_scope, session_not_ready, session_lost, offer_expired, offer_rejected, lease_expired, revoked, conflict. A profile may emit only its declared subset. conflict is the explicit reader contract of catalog v1alpha1's generic mutations: the provider answered a write that its target changed since the caller read it, so nothing was applied (a declared conflict_status, such as Zendesk's 409 to a stale safe_update). It is not the receiver's idempotency_conflict. Only the local CLI carries it, as Failure.service_code; neither service binding emits it, and both carry it as invalid_input, the code that answer had before, so the legacy bytes and the first v1alpha2 binding's emitted set are unchanged. Payload state/reason enums (acquisition failures, connection state, evidence results, media terminal reasons, private refresh outcomes) are not additional ErrorCode members. Future additions require a new explicit reader contract, not an untyped error string. Error remains {code,message,retry_after_seconds?} with a safe message of at most 512 UTF-8 bytes; metadata is never hidden in message text.
HTTP success uses 200 and status: success. An application error uses status: error and the following exact HTTP mapping on the extended routes (including GET refusal and pre-envelope invoke refusal):
| HTTP status | Error codes |
|---|---|
| 400 | invalid_input, unsupported |
| 401 | unauthorized |
| 403 | forbidden, approval_required, approval_refused, not_granted, route_refused, insufficient_scope |
| 404 | not_found |
| 409 | stale_description, stale_cursor, approval_replayed, idempotency_conflict, stale_authority, connection_not_ready, session_not_ready, offer_rejected, conflict |
| 410 | session_lost, offer_expired, lease_expired, revoked |
| 413 | capacity |
| 429 | rate_limited |
| 500 | internal |
| 502 | upstream_protocol, outcome_unknown |
| 503 | unavailable, route_unavailable |
| 504 | timeout |
More columns: swipe horizontally, or focus the table and use the arrow keys.
The selected client validates the closed envelope and this consistency mapping. Neither an HTTP error nor a mismatch proves non-dispatch: a mutation with no valid definitive observation remains uncertain and is never automatically retried. An error with known mutation.classification: applied retains that knowledge regardless of HTTP status. Ordinary unrecognized-route or transport failures outside this application binding need not manufacture an envelope. Legacy HTTP mapping is unchanged.
6. Complete family disposition matrix
“Payload” below means only the selected operation's input/result with its own declared closed schema. A payload-compatible shape is still unavailable until that family/profile's behavior is implemented and explicitly selected. Each row selects the shared wire disposition; the linked shared and native binding owns its complete closed schema, including nested fields and enums. No row grants arbitrary JSON extensions or makes provider semantics a shared wire dependency.
| Family / proposed profiles | Public payload and metadata disposition | Errors / private / other binding disposition |
|---|---|---|
| operations: mutation | Operation curation and invoke authority fields use §4; exact observation/replay encoding uses §5. Existing configured read profiles retain their old binding. The host-owned approval-subject preparation read has the exact closed input/result and dedicated limits in delegation §3, with no provider use, spend or business reservation. | New approval/idempotency/unknown codes require v1alpha2. Attempts, gates, reservation namespaces/fingerprints and raw approval state remain private; safe original correlation is §5 only. |
| auth.connection: configured, managed | Only unchanged implicit configured behavior is legacy-compatible. Managed connection selection and Descriptor.connections use §4; list/describe/revoke payloads retain connection/instance/profile/scope/actor/external_identity/route/status/revision/created fields under their own schemas. | connection_not_ready / route_unavailable use extended errors. Safe status enums stay payload values. No credential/snapshot/custody reference is public. Revoke requires the selected mutation/management binding. |
| auth.profile | Descriptor.auth_profiles safe projection and Operation.requires_auth alternatives use §4. The complete authored acquisition/scopes/identity/revocation/source declarations are specification/configuration data, not copied into describe. | insufficient_scope is an extended error where declared. Schemes/purposes/subjects/flows/capability/evidence names remain their own enums; a reserved name grants no support. |
| auth.acquisition: static_entry, authorization_code, client_credentials | Safe begin/status results carry acquisition/expires/action/state/connection/reason under admitted management schemas. Ordinary action contains only its kind. An actionable URL and protected-entry schema are delivered only through the separately admitted trusted UI channel; they are not generic begin/status output or replayable result data. | Protected entry/completion evidence uses a separately specified trusted callback/entry binding, not generic unary invoke input. Private exchange/refresh/revoke and their failure enums are not new public errors. The management boundary selects ownership/admission; concrete payload/effect/approval and protected acquisition bindings remain advertisement prerequisites. |
| auth.custody: read_only, versioned | No public secret-store operation or value projection. Existing read-only use may keep its exact legacy behavior. | SecretVersionRef, SensitiveMaterial, scope, CAS/publication and Missing/Denied/Conflict are private port values. Versioned custody is an explicitly supported infrastructure binding; service-wire selection does not provide it. |
| auth.capability | Safe capability names are in Descriptor.auth_profiles; that field needs v1alpha2. Retaining the existing configured HTTP port without public/behavior changes can remain legacy. The explicitly authored read-refresh-once combined profile changes behavior and is excluded from legacy projection; a capability rename does not select it. | Capability objects, destination/limits bindings, pins, material/leases and verifier outcomes remain private. The read retry binding maps private refresh failures to existing extended errors and adds no response member. Session authority proof/redemption has its own dedicated transport binding; AlreadyRedeemed is not automatically an ErrorCode. |
| auth.evidence | connections.describe.evidence retains connection/collected/checks/state and check/result/expiry/source/external_identity/missing/subject fields in the selected managed payload schema. Optional new payload members still require the matching schema reader. | connection_not_ready / insufficient_scope require extended errors. Evidence enums stay payload values; private generation/source-generation/snapshot/admission refs are never exported. |
| datasource.records: documents and search | Detail/body and document-list results require their explicitly selected closed native profile schemas. None extends today's closed Page. Native selections, representations, byte counts and continuation are owned by the native profile that selects them; none is authored today. | The selected reader must support declared errors and semantics; framing grants no retrieval, cache or authority guarantee. |
| datasource.logs: adapter-owned native profiles | Log results require the selected lines/selection/order/completeness/truncation/cursor/provenance schema and explicit profile support. Native input, metadata, precision and continuation codecs belong to each adapter binding. | Existing typed consumers do not automatically accept logs. Header placement is separately admitted configuration; service framing grants no provider authority or continuation guarantee. |
| datasource.series: adapter-owned native profiles | Series schemas require explicit selected-profile support; native query, sample encoding, result kinds and resolution constraints belong to the adapter binding. Profile constraints are not extra Operation.limits fields. | Native errors must map to the selected shared error set. No implicit coercion to other datasource payloads or silent clipping to legacy limits. Reserved profiles are not advertised. |
| resource discovery: candidate profiles | Observation identity/source/type/locator/candidate/auth_requirement/reachability/generation/withdrawal plus page generation/cursor/completeness/provenance are their own selected payload. Public observation generation is not a credential-generation identifier. | Base errors and the already selected auth connection_not_ready/not_granted refusals require a supporting auth/wire binding; a new root generation/coverage field is not accepted by the existing typed Page reader. Existing endpoint/host discovery does not silently change shape. Coverage/profile behavior remains with its owners. Private provider locator/route authority remains private. |
| mediated route: adapter-owned parent bindings | Safe {contract,profile,targets} advertising uses Descriptor.provides. Child results retain the selected child family schema and admission. | Forward/binding/parent/generation/target routing is a private same-composition port, with no public generic-forward operation. route_refused / route_unavailable require the extended set; a legacy projection that loses promised failures is ineligible. Native proxy construction belongs to the parent adapter. |
| sessions: outbound, inbound_offer, duplex_transport | Establishment uses mutation envelope §5 with the selected session/streams/transport result. Safe session record/terminal fields are a separate selected payload. | Six session error codes above need the extended set. Request/response/event/offer/accept/reject/cancel/close/lease/revoke/ping messages, authenticated live authority and their correlation need a complete versioned duplex binding before advertisement. Unary version alone is insufficient; no ready session until all selected control/data bindings are supported. |
| catalog: index/service, generic-http, generic-http-page | Providers/provider/operations/bundle/sources inventory shapes are selected payload schemas; a nested bundle descriptor is inventory, not this service's callable descriptor. Runtime curation, singular profile and auth alternatives use §4. | Base inventory errors; mutation realizations also use §5 extended errors/observations. Sources/curation/license/realization, index/bundle formats and configuration have independent strict readers. Generic profile limits use §7, not unchanged legacy defaults. Reserved OCI/AsyncAPI/header/query-auth vocabulary remains unbound. |
More columns: swipe horizontally, or focus the table and use the arrow keys.
The auth families share the host management boundary. Safe management may use selected extended operation payloads while the coordinator owns dispatch; protected completion and continuation delivery remain separately bound. Instance-scoped create/list never fabricate a selected business connection. The connection status vocabulary is the ordered eight-state viability reduction, with separate observation/validity times and nullable identity before activation; insufficient_scope remains an operation/acquisition refusal. The authored evidence_requirements value separates baseline from operation checks and needs its own supporting strict profile reader; it is not added to the public Descriptor.auth_profiles projection or current adapter schema.
The selected auth vocabulary now distinguishes direct anonymous/none/http-anonymous from child mediated_access/parent/mediated-http (purpose/scheme/capability; subject none for both). Safe auth-profile metadata reflects that distinction; a reader must explicitly support these enum values. Neither mode fabricates a child credential generation or provider identity: external_identity remains required-null when ready. The complete authored/configuration representation needs its own strict reader; the current host's required credential field has not become optional/null. static_config is deployment activation/materialization with no acquisition id/action; coordinator begin/status is unavailable for that path. Acquisition §4.0 owns required/forbidden OAuth fields and reserved-flow refusal. Generic service-wire selection grants none of these behaviors.
The proposed multi-target authorization-coverage payload in evidence §4.4 adds a closed authorization field with complete and ordered target/result entries. Each adapter owns the exact typed target codec and native scope interpretation, including the Kubernetes binding. Results are allowed/denied, never unchecked-as-denied; any denial also makes the overall result incomplete. Existing strict Page readers do not accept the field. Partial denied-target support requires the selected schema/reader; unavailable required evidence, target overflow and all-denied refusal use the selected shared errors. Private checking capabilities/cache keys remain private. Authorization coverage does not prove provider exhaustion or disappearance; comparable provider coverage remains a separate discovery obligation.
The selected resource-discovery view additionally carries required-null recognition (closed provider/confidence when present), required-null candidate, scope_ref/selection_revision, provider coverage partitions (complete/capped/denied/unavailable/not_scanned), retained-history truncation, and per-row observed/stale/withdrawn evidence with last positive generation/deadline. Concrete adapter-chosen operation ids fix one receiver-selected profile/source rule; the closed limit/cursor input rejects request-side profile/source overrides. Exact field and null/omission rules are owned by resource discovery; current Page accepts none implicitly. Permission authorization coverage remains a separate F08 payload field. Mediated composition is one process with injected private ports; same-target route revalidation is a separately admitted host configuration/validation binding, not a new generic invoke operation or a service-wire provider proxy.
Deferred execution, events, resource management and live configuration families gain no binding through this matrix. A supported payload profile may use legacy framing only when its complete advertised semantics, error set, auth and limits satisfy §3; no new envelope member may appear there. Families needing extended metadata/errors use v1alpha2; their old-reader behavior is refusal, not information-dropping coercion.
7. Limits and compatibility obligations
For the proposed extended binding, ordinary configured/read and non-generic mutation operation ceilings are the existing 64 KiB request / 4 MiB result, 20 s execution / 15 s provider / 5 s connect. Every operation with realization: generic (generic-http reads, mutation writes, and generic-http-page reads) deliberately selects 256 KiB request / 4 MiB result, 40 s execution / 30 s provider / 5 s connect to accommodate its authored 30 s provider budget without placing it behind a 20 s service cutoff. This is a new profile requirement, not a claim that the current host accepts larger requests or longer work. A receiver unable to supply the declared limits refuses the profile; it cannot silently clip it and advertise conformance.
Request/result byte ceilings include the service envelope; the binding reserves space for bounded metadata/error replies and refuses an oversized object explicitly. The host enforces a bounded aggregate framing ceiling before the operation is known, then that operation's declared lower ceiling before dispatch. Policy, admitted preflight, audit and provider work share the operation execution budget; they do not each receive a fresh deadline. Connect is inside provider time. The gateway's end-to-end budget must accommodate its selected downstream profile; no hop can silently reset it. A separate conformance binding must cover deadline/cancellation and outcome knowledge, rather than assuming these advertised numbers execute themselves.
The proposed read-refresh-once combined profile retains the ordinary descriptor limits and gives its whole provider sequence one cutoff, measured from the original execution start: at most 15 s provider work inside 20 s execution, with 5 s connects bounded by the remaining time. At most two business requests, one coordinated token exchange and the original F08 authorization ledger are available; refresh never resets consumed per-target call slots, response bytes or deadlines. Its binding owns the complete eligibility, count/buffer and refusal rules. Unknown/failed refresh publication grants no redispatch and no new public error enum.
The approval-subject helper is a distinct selected profile: 272 KiB request / 64 KiB result / 20 s total / 15 s downstream-control / 5 s connect. Its provider_ms ceiling is unused for provider I/O, which the helper forbids; the profile explicitly applies that field to downstream control. It is neither an ordinary nor generic execution limit. Signed one-hop requests additionally require the bounded Authorization proof and Connector-Dispatch-Id response correlation specified by delegation.md; no new public Response member is added.
The following remain implementation obligations: separate strict codecs/routes; old-byte vectors; exact profile support/projection/invoke checks; schemas for all selected public payloads; safe error and observation combination validation; receiver-owned auth configuration; audit failure framing; and complete selected stream/callback/delegation codecs. Proposed context verification, audit/attempt atomicity and the selected F03 delegation protocol are not implemented by ESS value types.
The verification record records old-reader evidence, selected outcome vectors, matrix coverage and independent rechecks. It must distinguish declaration/schema checking from executing a service or sequential ESS trace. Runtime implementation and external publication remain outside this story.
Persistence ownership is consolidated in design §31. ExecutionAuditPort remains independently acknowledged at each admitting hop; private ledger ports and their atomic groups gain no public service methods. This inventory does not supply a backend or execute its atomicity predicates.