feat(protocol): the principal layer — unified webhooks, declarations, principal.changed - #7020
feat(protocol): the principal layer — unified webhooks, declarations, principal.changed#7020bokelley wants to merge 2 commits into
Conversation
Allow caller-level webhook subscribers to carry account-anchored event types with fire-time authorization scoping — each fire covers only accounts the caller is authorized for at fire time — plus an explicit include_future_event_types opt-in instead of a wildcard. Add the declarations section: buyer-declared consumption facts (async payload versions, verifiable webhook signing algorithms, experimental opt-ins) with a seller-computed accepted intersection that gives webhook fires the version-negotiation channel synchronous requests get from the envelope. Add the caller-anchored principal.changed invalidation webhook for seller-driven principal-state transitions, repaired through get_principal. Report the seller-resolved principal_kind (buyer_agent or operator) on every readback with an expected_principal_kind assertion fence, and add the agent-scoped operator_id destination label with a normative cross-principal non-alignment rule. Advertise caller_event_types in capabilities so buyers select from the offering instead of probing by rejection, and gate the destination storyboard phases on section support. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
8f0ea08 to
c9f2f43
Compare
| { | ||
| "$schema": "http://json-schema.org/draft-07/schema#", | ||
| "$id": "/schemas/core/principal-changed-webhook.json", | ||
| "title": "Connection Changed Webhook", |
There was a problem hiding this comment.
(non-blocking) Title is "Connection Changed Webhook" — the old entity name in the PR that renames connection→principal. Sibling schemas already landed as "Principal State" / "Sync Principal Request"; this new schema (and principal-declarations.json → "Agent Declarations", principal-declarations-state.json → "Agent Declarations State", plus the new index.json "connection configuration" / "connection-state" descriptions) ships under the pre-rename name. Published title is a spec-facing symbol; worth aligning before the layer leaves experimental.
There was a problem hiding this comment.
Ladon verdict: Escalate to human review
Escalate — gated schema paths require human/CODEOWNERS approval.
This PR modifies and adds files under static/schemas/source/**, which is a hard, deterministic approval gate (gated_paths: true). The required review_decision is not APPROVED (currently unknown/none), so the gate is not satisfied and the outcome cannot be approve or plain comment per decision-table row 2.
The reviewer found the change coherent: a connection→principal rename plus additive experimental extensions (principal.changed webhook, declarations negotiation, principal_kind + assertion fence, operator_id label, caller_event_types offering, account-anchored subscriptions). Schema↔docs coherence holds, the minor changeset is correctly scoped, oneOf disjointness is preserved, and the released-surface event_types widening is an additive loosening with the notification-type enum updated in lockstep. No Critical/High/Medium findings — only one non-blocking Low naming-drift straggler (new schemas titled under old "Connection"/"Agent" names) posted inline.
No blocking findings exist, but the schema-source hard gate stands until a human/CODEOWNERS approval is recorded. A human should confirm the wire-shape changes and that these additive extensions carry the appropriate Editorial/Normative (non-breaking) classification before merge.
Why human review
- Touches gated schema-source paths under static/schemas/source/** (modified: agent-notification-config-state.json, agent-notification-config.json, agent-reporting-destination.json, principal-state.json, notification-type.json, index.json, get-adcp-capabilities-response.json, get-principal-request.json, get-principal-response.json, sync-principal-request.json, sync-principal-response.json; added: principal-changed-webhook.json, principal-declarations-state.json, principal-declarations.json) with review_decision not APPROVED — human/CODEOWNERS approval required (decision-table row 2).
- This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/core/agent-notification-config-state.json (modified) matches
static/schemas/source/**; static/schemas/source/core/agent-notification-config.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/agent-reporting-destination.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/principal-changed-webhook.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/principal-declarations-state.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/principal-declarations.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/principal-state.json (modified) matchesstatic/schemas/source/**; static/schemas/source/enums/notification-type.json (modified) matchesstatic/schemas/source/**; static/schemas/source/index.json (modified) matchesstatic/schemas/source/**; static/schemas/source/protocol/get-adcp-capabilities-response.json (modified) matchesstatic/schemas/source/**; static/schemas/source/protocol/get-principal-request.json (modified) matchesstatic/schemas/source/**; static/schemas/source/protocol/get-principal-response.json (modified) matchesstatic/schemas/source/**; static/schemas/source/protocol/sync-principal-request.json (modified) matchesstatic/schemas/source/**; static/schemas/source/protocol/sync-principal-response.json (modified) matchesstatic/schemas/source/**) and the current GitHub review decision is 'unknown', not APPROVED. This is a hard gate enforced in code — Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.
…ontract State explicitly that the layer begins after authentication — AdCP defines no credential-registration protocol — and add the normative "Establishing a connection" lifecycle joining authentication, principal configuration, account binding, and readiness. Require the explicit all_authorized_accounts acknowledgment for account-anchored event types on caller-level subscribers, with authorization evaluated at each delivery attempt so revocation suppresses queued retries carrying that account's data. Restrict include_future_event_types to types classified invalidation-only, so the flag can never silently opt a caller into payload-bearing events. Persist the full declarations negotiation record: declared set, accepted intersection, the seller's selected_async_adcp_version, and per-value exclusion reasons. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Commit
🤖 Generated with Claude Code |
There was a problem hiding this comment.
Ladon verdict: Escalate to human review
Escalate — gated schema-source paths require human/CODEOWNERS approval.
This PR modifies and adds files under static/schemas/source/**, which are under a hard, non-overridable approval gate (gated_paths: true). The current review_decision is unknown/none, not APPROVED, so decision-table row 2 fires: Ladon cannot auto-approve until a human/CODEOWNERS approval is recorded, regardless of how clean the diff is.
The reviewer's delta pass found no Critical/High/Medium findings — the new all_authorized_accounts if/then gate fails closed over exactly the 15 account-anchored types, the added principal-declarations-state fields are schema↔docs coherent with the sync_principal.mdx updates, the changeset is appropriate for the additive experimental surface, and tests exercise the gate both directions. The diff itself is mechanically clean, but the gate is deterministic and path-based, not diff-quality-based.
Escalation reasons
- Modifies/adds gated schema-source paths under
static/schemas/source/**(modified: agent-notification-config-state.json, agent-notification-config.json, agent-reporting-destination.json, principal-state.json, notification-type.json, index.json, get-adcp-capabilities-response.json, get-principal-request.json, get-principal-response.json, sync-principal-request.json, sync-principal-response.json; added: principal-changed-webhook.json, principal-declarations-state.json, principal-declarations.json) withreview_decisionnot APPROVED — human/CODEOWNERS review required (row 2).
The gate lifts the moment review_decision becomes APPROVED; a human approval on the thread will let a re-run fall through to a normal approve.
Why human review
- Touches gated schema-source paths under static/schemas/source/** with review_decision not APPROVED — human/CODEOWNERS approval required (decision-table row 2). Modified: agent-notification-config-state.json, agent-notification-config.json, agent-reporting-destination.json, principal-state.json, notification-type.json, index.json, get-adcp-capabilities-response.json, get-principal-request.json, get-principal-response.json, sync-principal-request.json, sync-principal-response.json. Added: principal-changed-webhook.json, principal-declarations-state.json, principal-declarations.json.
- This PR touches a path under a hard, non-overridable approval gate (static/schemas/source/core/agent-notification-config-state.json (modified) matches
static/schemas/source/**; static/schemas/source/core/agent-notification-config.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/agent-reporting-destination.json (modified) matchesstatic/schemas/source/**; static/schemas/source/core/principal-changed-webhook.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/principal-declarations-state.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/principal-declarations.json (added) matchesstatic/schemas/source/**; static/schemas/source/core/principal-state.json (modified) matchesstatic/schemas/source/**; static/schemas/source/enums/notification-type.json (modified) matchesstatic/schemas/source/**; static/schemas/source/index.json (modified) matchesstatic/schemas/source/**; static/schemas/source/protocol/get-adcp-capabilities-response.json (modified) matchesstatic/schemas/source/**; static/schemas/source/protocol/get-principal-request.json (modified) matchesstatic/schemas/source/**; static/schemas/source/protocol/get-principal-response.json (modified) matchesstatic/schemas/source/**; static/schemas/source/protocol/sync-principal-request.json (modified) matchesstatic/schemas/source/**; static/schemas/source/protocol/sync-principal-response.json (modified) matchesstatic/schemas/source/**) and the current GitHub review decision is 'unknown', not APPROVED. This is a hard gate enforced in code — Ladon cannot auto-approve
…(truncated)…
Implements RFC #7015. Stacked on #6966 — the base branch is
feat/agent-configuration; retarget tomainafter #6966 merges. Draft until the WG weighs in on the RFC's questions.The model
Three-tier hierarchy: principal (who you are, resolved from transport;
buyer_agentoroperator) → the principal's standing configuration with one seller (webhooks, destinations, declarations) → accounts (principal × advertiser authority). Operators an agent serves are agent-scoped labels inside that agent's principal space — each agent maps its operators its own way, so matching labels across principals confer nothing. The model composes per hop: buyer agent → Interchange → seller is two independent principal relationships, and a person in Claude buying through Interchange is one operator principal there.What this adds
1. Principal-level webhook subscriptions. Caller-level
notification_configssubscribers may carry account-anchored event types (creative.status_changed,account.change_recorded,product.*, …) with fire-time authorization scoping: each fire covers only accounts the caller is authorized for at that moment. No wildcard — enumerateevent_typesor set the explicitinclude_future_event_types: trueopt-in. Caller-level and account-level subscriptions are independent; receivers dedupe bynotification_id. A subscriber'sactive: falsehalts all fires across every account within the advertisedsuspension_interval_seconds. This flips the caller-level rejection rule #6966 ships — which is why it should be decided while the surface is experimental.2.
declarationssection. Webhook fires have no request context to negotiate payload versions against; the durable declaration is that channel. The caller declares bounded consumption facts (async_adcp_versions,webhook_signing_algorithms,experimental_features); the seller returns the accepted intersection governing asynchronous interactions. Unknown experimental identifiers are excluded, not rejected; an empty signing intersection with an active subscriber fails withUNSUPPORTED_FEATURE;{}clears.3.
principal.changedwebhook. Caller-anchored invalidation for seller-driven principal-state transitions (destinationvalidating→ready, setup expiring, proof invalidated, accepted intersection changed), repaired by re-readingget_principal— closing the poll loop for destination setup. Payload:principal-changed-webhook.json.4. Resolved
principal_kind+ assertion fence. Every applied/current readback carries the seller-resolved party kind (buyer_agent|operator), resolved solely from the authorization system so per-party policy (e.g. billing gates) can rely on it. Requests may carryexpected_principal_kind— an assertion fence rejected withCONFLICTon mismatch, never identity input.5. Agent-scoped
operator_iddestination label. Per-operator isolation, audit, and one-call offboarding under an agent principal, with a normative cross-principal non-alignment rule: matching operator labels or domains across principals MUST NOT be linked, deduped, or granted shared authority.6. Two-sided event offering. Capabilities advertise
caller_event_typesso buyers select from the offering instead of probing by rejection.Also in this PR
supported_sections(a notifications-only seller previously failed them), plus gateddeclarations_lifecycleandprincipal_kindgrading.principal.changedemission grading are fixture-dependent → Fixture-dependent conformance for agent configuration lifecycle #7010.Verification
16/16 principal contract tests; 28/28 MCP schema projection/analysis; schema build; compliance symbol check; storyboard lints; JSON-schema docs validation; full precommit suite; pre-push storyboard matrix with all tenants above floors.
🤖 Generated with Claude Code