feat(ucp): identity capability is config-only static policy (1.6.0) - #17
Merged
Conversation
The UCP `sh.agentscore.identity` capability declares the merchant's gate policy as `config` (a static AgentScoreGatePolicy), not as runtime claims. Per-operator identity attestation lives at the AP2 risk-signal endpoint, not in the public profile. Breaking changes: - `build_ucp_profile`'s `data` kwarg removed; pass `agentscore_gate` instead - `_AGENTSCORE_CAPABILITY_VERSION` bumped to "2026-04-08" (date format) - `get_assess_data` adapter helpers renamed to `get_agentscore_data` for cross-language brand alignment with node-commerce - Cross-lang fixtures `data-driven-claims` / `typed-claims` removed; replaced with `agentscore-gate-full` / `agentscore-gate-blocked` Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A2AAgentCardCapabilities.endpoints was `list[dict[str, str]]` (arbitrary
key/value), now a `list[A2AAgentCardEndpoint]` TypedDict mirroring node's
`{ name: string; path?: string; method?: string }[]` contract. Dict literals
still satisfy the type so call sites are unchanged.
Also drops the stale "1.4.0" version pin from the README's stability note.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…mat version The `capability` cross-lang fixture's hand-crafted UCPCapabilityBinding for sh.agentscore.identity carried `version: "1"` (the pre-refactor scheme). Bumped to "2026-04-08" so vendor copies of our capability shape match what the SDK auto-injects today. Regenerated all 10 cross-lang fixtures (fresh keys + signatures) and mirrored both languages' fixture sets. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three spec-compliance fixes after auditing against the canonical UCP profile schema and A2A v1.0 proto definitions: 1. A2A AgentCard refactored to match the canonical proto at github.com/a2aproject/A2A/blob/main/specification/a2a.proto. Old shape used invented `protocol_version` / `card_version` / `endpoints[]` fields and put `extensions[]` at top level; spec puts extensions inside `capabilities`, uses `version` (agent semver), `supported_interfaces` (typed protocol bindings), top-level `skills` of `AgentSkill` objects, and required `default_input_modes` / `default_output_modes`. New dataclasses: `A2AAgentInterface`, `A2AAgentProvider`, `A2AAgentSkill`. The `data: AssessResult` parameter and `identity` block are removed; A2A spec uses a separate `AgentCardSignature` (RFC 7515 JWS) for identity. 2. `A2AAgentCardExtension` now carries `description` (required) and `required` (bool) per spec §4.4.4. `ucp_a2a_extension()` helper sets both. 3. `sh.agentscore.payment.stripe-spt` violated UCP reverse-DNS regex `^[a-z][a-z0-9]*(?:\.[a-z][a-z0-9_]*)+$` — hyphens forbidden in segment chars. Renamed to `sh.agentscore.payment.stripe_spt`. Schema URL slug, spec page slug, and JSON file path migrated to snake_case for consistency. Plus two runtime validators added: - `UCPServiceBinding.to_dict()` raises when transport is rest/mcp/a2a and endpoint is None (spec service.json business_schema requires endpoint for these transports; embedded MAY omit it). - `UCPPaymentHandlerBinding.to_dict()` drops `available_instruments` when the list is empty (spec payment_handler.json requires `minItems: 1`). Cross-lang fixtures regenerated (the `extras-int` fixture's stripe-spt key changed to stripe_spt; all 10 fixtures now carry fresh signatures). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The README's identity-publishing example for build_a2a_agent_card used the pre-refactor shape (capabilities=A2AAgentCardCapabilities(...) + data= assess_result + no version / description / skills). Update to the spec-compliant inputs (top-level description, version, skills as A2AAgentSkill objects, extensions inside capabilities via the helper). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ec re-audit Three more A2A spec items from re-reading the proto: - `skills` is REQUIRED per spec §4.4.1 (proto field 12, [field_behavior=REQUIRED]). Old code accepted empty list. Now build_a2a_agent_card raises ValueError when skills is empty/None; callers must declare ≥1 AgentSkill (or construct A2AAgentCard directly to bypass). - `icon_url` (proto field 14, optional) added to A2AAgentCard + build_a2a_agent_card. - `signatures` (proto field 13, optional, list of AgentCardSignature per §4.4.7) added to A2AAgentCard + build_a2a_agent_card. New A2AAgentCardSignature dataclass: protected (REQUIRED), signature (REQUIRED), header (optional). Verifiers compute over the canonical card body MINUS this field. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The UCP project publishes the MCP shopping openrpc at \`https://ucp.dev/services/shopping/mcp.openrpc.json\` (per github.com/Universal-Commerce-Protocol/ucp source/services/shopping/). Our SDK was emitting \`openrpc.json\` without the \`mcp.\` prefix. Cross-lang fixtures regenerated. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Activity, Classification, Identity, Reputation, ScoreDetail, Grade, ScoreStatus are reputation-API shapes that live in agentscore-py. python-commerce was duplicating them locally as @DataClass copies; agentscore-py has them as TypedDict. Vendors who need these should import from agentscore-py directly. Removes the duplicates from agentscore_commerce/identity/types.py and from the public __all__. Mirrors node-commerce's tighter module boundary (@agent-score/commerce doesn't re-export reputation types either). OperatorVerification, PolicyCheck, PolicyResult kept — those are gate-relevant (consumed by AssessResult and the policy module) and not reputation types. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Both within existing constraints. Lockfile-only change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
sh.agentscore.identityUCP capability now declares static merchant policy asconfig(anAgentScoreGatePolicy), not as runtime per-operator claims. Per-operator identity attestation lives at the AP2 risk-signal endpoint, never inside the public profile.get_agentscore_data(request)(per-operator runtime helper, renamed fromget_assess_datafor cross-language brand alignment with node-commerce'sgetAgentScoreData) is unchanged in behavior.Breaking changes
build_ucp_profile'sdatakwarg removed; passagentscore_gateinstead._AGENTSCORE_CAPABILITY_VERSIONbumped to"2026-04-08"(date format).get_assess_dataadapter helpers renamed toget_agentscore_dataacross all 6 framework adapters (fastapi, flask, django, aiohttp, sanic, middleware).data-driven-claims/typed-claimsremoved; replaced withagentscore-gate-full/agentscore-gate-blocked.Why
Mixing static merchant policy with per-request operator claims in one capability binding made the UCP profile drift on every request and conflated two layers. UCP is the public, cacheable declaration; AP2 is the per-operator runtime attestation. Profile must stay deterministic across requests.
Test plan
uv run pytest— 872 passing, 95.10% coverageuv run ruff checkuv run ty check agentscore_commerce/🤖 Generated with Claude Code