You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit a1c65ef
Browse filesBrowse the repository at this point in the historyBrowse files
docs: correct A2A signing docs and supported versions; drop em-dashes (#152)
## Summary
Doc corrections from an audit of every repo's docs against code, plus an
em-dash sweep.
- **SECURITY.md** listed 2.x as the supported line; the package is on
3.x.
- **README A2A example** called the card a "Signed Agent Card" whose
identity claims live in a separate JWS wrapping it.
`build_a2a_agent_card` returns the card unsigned, and an A2A 1.0 card
carries its JWS entries in its own `signatures` field. The comment now
says that.
- **A2A module docstring** said to "wrap" the card in a signature and
called the spec "Google A2A"; it now says to attach the JWS entries as
`signatures`.
- **"the 2.0 high-level surface"** removed from the README and CLAUDE.md
(version-introduction text, and the package is on 3.x).
- **CLAUDE.md** `/api` row now lists the four names
`agentscore_commerce.api` re-exports, not one.
- **examples/README.md**: the compute-first example uses
`compute_first_checkout`, which is backed by `create_quote_cache`; it
does not import the cache itself.
- A broken `# ,` comment in the README UCP example is fixed.
- **Em-dashes** removed everywhere except the one test that asserts
`skill.md` output contains none. A spaced em-dash became a colon; dashes
used as a pair became parentheses. This touches agent-facing strings
(denial instructions, `skill.md` text), which ship in the next release;
no release is cut for this alone.
## Type of change
- [ ] Bug fix (no breaking change)
- [ ] New feature (no breaking change)
- [ ] Breaking change (existing callers must update)
- [x] Docs, tests, or internal maintenance only
## Public API
None. No exported name, signature or value changed. String content in
agent-facing text changed punctuation only.
## Test plan
`ruff check`, `ruff format --check`, `ty check` and `pytest` (1892
passed, 4 skipped) all exit 0. Repo-wide em-dash count afterwards: 1,
the assertion in `tests/test_skill_md.py`. The sweep kept `# noqa` codes
parseable and the Sphinx `#:` attribute comments intact.
## Checklist
- [x] Tests cover the new behavior, and the suite passes locally (no
behavior changed; suite passes)
- [x] Lint, format, and type checks pass
- [x] Docs and README examples updated if the public surface changed
- [x] No secrets, credentials, or personal data in the diff or the tests
| `agentscore_commerce` (top-level) | `Checkout` orchestrator + `CheckoutContext` + `CheckoutGateConfig` + `CheckoutValidationError` + `DiscoveryProbeConfig` + `SettleOutcome` + `MppxComposeOutcome` + `PricingResult` (the 2.0 high-level surface: one config object, hooks for pre_validate/compute_pricing/on_settled/mint_recipients/compose_mppx, auto-derived x402+mppx servers, per-framework adapters `handle_fastapi`/`handle_flask`/`handle_django`/`handle_aiohttp`/`handle_sanic`, signed UCP routes via `mount_ucp_routes_{fastapi,flask,django,aiohttp,sanic}`); `create_result_cache` (neutral keyed JSON-value cache with a stable body-hash key builder; cache a probe-leg result, e.g. a paid upstream call made in `pre_validate`, and replay it on the settle leg) plus the compute-first-shaped `create_quote_cache` built on it; `pricing_result` (factory: cents-denominated → typed `PricingResult` with embedded `PricingBlock`); `validation_response_{fastapi,flask,django,aiohttp,sanic}` (per-framework 4xx envelope wrappers); `make_mppx_compose_hook` (canonical pympp compose adapter). |
27
+
| `agentscore_commerce` (top-level) | `Checkout` orchestrator + `CheckoutContext` + `CheckoutGateConfig` + `CheckoutValidationError` + `DiscoveryProbeConfig` + `SettleOutcome` + `MppxComposeOutcome` + `PricingResult` (one config object, hooks for pre_validate/compute_pricing/on_settled/mint_recipients/compose_mppx, auto-derived x402+mppx servers, per-framework adapters `handle_fastapi`/`handle_flask`/`handle_django`/`handle_aiohttp`/`handle_sanic`, signed UCP routes via `mount_ucp_routes_{fastapi,flask,django,aiohttp,sanic}`); `create_result_cache` (neutral keyed JSON-value cache with a stable body-hash key builder; cache a probe-leg result, e.g. a paid upstream call made in `pre_validate`, and replay it on the settle leg) plus the compute-first-shaped `create_quote_cache` built on it; `pricing_result` (factory: cents-denominated → typed `PricingResult` with embedded `PricingBlock`); `validation_response_{fastapi,flask,django,aiohttp,sanic}` (per-framework 4xx envelope wrappers); `make_mppx_compose_hook` (canonical pympp compose adapter). |
28
28
|`agentscore_commerce.identity.{fastapi,flask,django,aiohttp,sanic,middleware}`| Trust gate middleware: KYC, sanctions (account name + signer wallet), age, jurisdiction. `AgentScoreGate(...)` (or `agentscore_gate(app, ...)` on Flask/Sanic), `get_agentscore_data(...)`, `capture_wallet(...)`, `get_signer_verdict(...)`. The gate extracts the payment signer pre-evaluate and passes it to `/v1/assess`, so the API composes both wallet-binding (`signer_match`) and OFAC SDN wallet-address (`signer_sanctions`) verdicts on one round trip. |
29
29
| `agentscore_commerce.identity` (package level) | Re-exports the denial helpers: `denial_reason_status`, `denial_reason_to_body`, `build_signer_mismatch_body`, `build_contact_support_next_steps`, `verification_agent_instructions`, `is_fixable_denial`, `FIXABLE_DENIAL_REASONS`. The per-framework adapter modules also expose `get_gate_quota_info(request)` for surfacing X-RateLimit info from gate state. Also re-exports the per-product policy helpers: `PolicyBlock`, `GateResult`, `EnforcementMode`, `IdentityStatus`, `build_gate_from_policy`, `run_gate_with_enforcement`, `shipping_country_allowed`, `shipping_state_allowed`, `validate_shipping_against_policy` (one-call country+state validator that raises `CheckoutValidationError` with the canonical envelope on miss), for multi-product merchants where each product carries its own compliance config: hard gate vs soft vs none, per-product shipping allowlists. Key + token helpers: `load_ucp_signing_key_from_env` (cached env-driven loader for the UCP signing key, reads `UCP_SIGNING_KEY_JWK_PRIVATE` JSON JWK, detects alg from shape, falls back to ephemeral when unset, sanitizes errors so key bytes never reach logs, concurrent-safe via `threading.Lock`; env-var names and `default_kid` / `default_alg` are overridable as kwargs); `hash_operator_token` (sha256 hex of plaintext `opc_...`, for merchants persisting `operator_token_id` to their own DB without ever storing the plaintext); `extract_owner_scope(headers) -> OwnerScope` (canonical owner-identity extractor for caller-scoped resource queries, reads `X-Wallet-Address` / `X-Operator-Token`, hashes the token so plaintext never leaves the request); `default_read_only_on_denied(reason)` (canonical `on_denied` for read-only resource gates: 401 + `Cache-Control: no-store` while still spreading `denial_reason_to_body`. Returns a `DefaultOnDeniedResult(body, status, headers)`; FastAPI / Flask / aiohttp / Sanic `on_denied` callbacks accept an optional 3-tuple `(body, status, headers)` to carry headers through; wrap with `lambda req, reason: (lambda r: (r.body, r.status, r.headers or {}))(default_read_only_on_denied(reason))`). |
30
30
| `agentscore_commerce.payment` | `networks`, `USDC`, `rails` registries; `payment_directive`, `build_payment_directive`, `www_authenticate_header`, `payment_required_header`, `alias_amount_fields` (opt-in v1↔v2 amount-field shim that adds both `amount` and `maxAmountRequired` to an entry. The 402 builders do NOT apply it by default, strict x402 v2 settlement matches the agent's echoed requirement by exact comparison, so an extra field the server's rebuilt requirement lacks breaks settle; use only when you know a client is hardcoded to read `maxAmountRequired`), `settlement_override_header`, `dispatch_settlement_by_network`, `extract_payment_signer` (accepts positional `x402_payment_header` AND/OR `authorization_header=` kwarg; recovers signer from x402 EIP-3009 `payload.authorization.from` OR MPP `Authorization: Payment <base64>` `did:pkh:eip155:<chain>:<addr>` / `did:pkh:solana:<genesis>:<addr>` source DID), `detect_rail_from_headers` (returns `"x402"` / `"mpp"` / `None` from inbound headers), `register_x402_schemes_v1_v2`; drop-in x402 helpers: `validate_x402_network_config` (boot-time guard), `verify_x402_request` (parse + validate inbound X-Payment), `process_x402_settle` (verify-then-settle with one call), `classify_x402_settle_result` (maps the tagged settle result to a recommended HTTP status / code / next_steps so merchants get a controlled envelope without coupling to facilitator-specific error text), `classify_orchestration_error` (same `ClassifiedX402Error` shape but for uncaught exceptions thrown elsewhere in the orchestration; returns `None` for unknown errors so merchants rethrow instead of swallowing); `zero_amount_carve_out` (skip CDP / pympp upstream verify+settle for $0 settles where the upstream rejects value=0 payloads, including credentials signed against a nonzero quote the merchant re-priced to $0 at settle; parses the credential, lifts signer + network, returns a `ZeroSettleResult` shaped identically to the success path so callers branch on rail, not on result shape), `malformed_payment_credential` (wire-shape gate: payment headers that are not base64 JSON and not token-shaped are rejected before merchant hooks run; `Checkout` applies it by default, opt out with `credential_pre_check=False`); `usd_to_atomic` (Decimal-based USD → atomic int, ROUND_HALF_UP, for Tempo / Solana / Base USDC amount construction). |
## Checkout orchestrator (the 2.0 high-level surface)
96
+
## Checkout orchestrator
97
97
98
98
`Checkout` is the canonical merchant surface: one config object, hooks for the merchant-specific pieces, and the SDK handles 402 emit, identity gating, x402 verify+settle, mppx compose, $0 carve-out, and the per-framework adapter. Most merchants reach for `Checkout` first and drop to lower-level helpers only when they need custom flows.
99
99
@@ -315,12 +315,12 @@ from agentscore_commerce.identity import (
315
315
ucp_a2a_extension,
316
316
)
317
317
318
-
#Google A2A v1.0 Signed Agent Card. Publish at /.well-known/agent-card.json.
318
+
# A2A v1.0 Agent Card. Publish at /.well-known/agent-card.json.
319
319
# Per UCP §A2A binding the card MUST declare the canonical UCP extension URI in
320
320
# `capabilities.extensions[]`; pass `ucp_a2a_extension()` with empty capabilities
321
321
# until you bind formal UCP capabilities (dev.ucp.shopping.checkout, etc.).
322
-
# Skills are top-level AgentSkill objects; identity claims live in a separate
323
-
#AgentCardSignature (RFC 7515 JWS) wrapping the serialized card.
322
+
# Skills are top-level AgentSkill objects. The card is returned unsigned: to sign it,
323
+
#compute RFC 7515 JWS entries over the card body and pass them as `signatures`.
324
324
card = build_a2a_agent_card(
325
325
name="My Service",
326
326
description="Buy products via agent payments.",
@@ -340,7 +340,7 @@ card = build_a2a_agent_card(
340
340
# Google Universal Commerce Protocol. Publish at /.well-known/ucp.
0 commit comments