Replies: 14 comments
|
Strong support for a neutral, independently-checkable verifier role. The invariant that matters, a verdict that is a signed credential anyone can verify against the verifier's published keys without trusting the issuer, is the right one, and it's the property we design our own identity and response layers around. One dimension worth widening in the role definition: this proposal scopes the verdict to transaction risk. There's a parallel, equally-neutral verifier need on the agent-identity axis, who is this agent, is it who it claims to be, what is its standing over time. That's a different claim from "is this transaction risky," but it's the same structural pattern: neutral third party, signed verdict, published keys, offline-verifiable. We operate an agent-identity issuer and a reputation registry keyed on a stable agent id, and I'd want the External Verifier role defined generally enough to cover identity and reputation verdicts, not only transaction-risk ones, so the ecosystem lands on one verifier role instead of two incompatible ones. Worth coordinating with #534 (a standard envelope for third-party verifier attestations). That thread and this one are the same delivery problem stated twice: a third party signs something about an agent or transaction, and any party verifies it offline against published keys. If the trust-verdict signal here rides #534's envelope, we get one verifier role plus one envelope plus N claim types (risk, identity, reputation, decision-provenance), instead of a new signal shape per vendor. One neutrality point worth making normative: for the role to be credibly neutral, a verifier attesting about a transaction shouldn't also be a party to it (not the merchant, PSP, or platform). The proposal gestures at this; worth stating as a conformance requirement. |
|
Weston, thanks, this is the conversation I was hoping the proposal would start. On widening the role: agreed. One verifier role, defined generically, with the axis carried by a claim type. Who an agent is, how it has behaved over time, and whether a given transaction is within policy are different claims with the same delivery shape: a third party signs, anyone verifies against published keys. Two incompatible roles would be a worse outcome for everyone, so I support folding identity and reputation in. Also agreed on coordinating with #534. Our On making neutrality normative: yes, and I would make it precise while we are at it. Neutrality is a property of a specific claim about a specific transaction. Suggested conformance language:
Evaluated per transaction and per claim type. Under this rule an identity issuer can attest who an agent is on any rail, including one it operates, because that claim is about the agent and holds independently of the flow. A transaction-risk verdict is different: when the signer profits from the settled volume, the verdict turns from evidence into testimony, and an auditor or an insurer will discount it for that reason, whoever the signer is. The clause should apply to us too: if Fidacy ever operated a rail, it would disqualify Fidacy on that rail. Two conformance requirements so the role can be checked rather than merely declared:
To make the one-role picture concrete: a checkout where an identity verdict and a risk verdict ride the same signals array, each under the #534 envelope, each verified against its issuer's published keys, would demonstrate the whole proposal end to end. Glad to build that demo against a live Terminal if you are up for it. |
|
Let's do it. Our identity attestation would be a signed verdict over the agent id, no checkout session binding needed since who an agent is doesn't depend on any single transaction, verified against our published JWKS. Your risk verdict stays scoped to the session. Both fit in the same signals array once #534 settles on field names. For the demo: one real checkout on our live Terminal, an agent shows up holding both verdicts, the merchant verifies each offline (two kid lookups, two JWKS fetches, neither issuer has to be online or cooperate at verify time), and we publish the whole flow plus conformance vectors, valid, expired, wrong session, bad signature, rotated key, so someone reading the spec cold can reproduce it without asking either of us. I'd start by trading JWKS URLs and the exact shape each of us issues today, then wire up the real checkout once #534's fields lock. Where's easiest to hash out the details, here or somewhere else? |
|
Let's do it. Here's our half so you can start today. JWKS: https://api.fidacy.com/.well-known/jwks.json Send me your JWKS URL and the exact shape of your identity attestation: the On channel: let's stand up a shared public repo as the place to both hash And let's not block on #534: we both already ship signed JWS, so we start with Shared repo under a neutral name, or one of ours to kick off? Either works, I |
|
Our JWKS is at issuer.facet.llc/.well-known/jwks.json. Different shape from yours though, worth flagging early: we sign ES256 over EC P-256, not EdDSA, and it's a standard compact JWS rather than JCS-canonicalized bytes. Two verifiers, two algorithms, is exactly the kind of thing #534 needs to settle or explicitly allow either. Claim shape: header carries alg, typ (kya+jwt), kid. Payload has iss, aud, aid, iat, nbf, exp, and optionally apd (an agent platform handle), a nonce, and a tier. aid is a cryptographic identity derived from a key thumbprint, never PII. Default TTL is one hour, hard ceiling at 24, and low-trust self-enrolled agents get capped at one hour no matter what they ask for. On the repo: Facet will put its name behind this officially. Stood one up under our org just now, github.com/Facet-llc/ucp-verifier-envelope, seeded with a README pointing back to this thread and #534. Open to you as a contributor, add your side whenever you're ready and we'll build the demo out from there. |
|
This is exactly the split I was hoping we'd land on. Identity and risk are different attestations answering different questions, and the checkout you describe, an agent presenting both and each verifiable offline, is the right shape for the whole ecosystem, not just for the two of us. On the two-verifier, two-algorithm point: I'd make that a first-class feature of the envelope, not something #534 has to reconcile away. Your claim is ES256 over P-256 with typ kya+jwt; ours is EdDSA over Ed25519 with typ application/vc+jws. Both are compact JWS resolvable against a published JWKS by the kid in the protected header. So the envelope never has to pick a winner: it names the issuer, the verifier resolves that issuer's JWKS and dispatches to the right verify routine by alg, and neither issuer is online at verify time. Algorithm agility is what keeps this neutral and keeps it alive past today's two verifiers. To get us out of design and into something testable, I just opened the first PR with the risk half: Facet-llc/ucp-verifier-envelope#1 It brings a real production verdict that verifies offline against our live JWKS at api.fidacy.com, plus five deterministic vectors (valid, expired, bad-signature, rotated-key, wrong-session) anyone can regenerate with npm i and node gen-vectors.mjs, each self-validated by the published @fidacy/verify. One deliberate detail: the wrong-session vector verifies as authentic on purpose. The verifier proves the verdict is real and untampered; binding it to the checkout in hand is the consumer's check. Authenticity and scope are different questions, the same way identity and risk are, and the envelope should keep them separate too. The canonical spec for the risk half stays in fidacy-open/spec so there's one source of truth for that side. Happy to move or rename anything to match how you want the repo laid out. Your identity-side vectors drop in next to these and the conformance pack covers both claim types: one envelope, two issuers, two algs, both verify. From there the demo builds itself. One governance thought: the envelope itself is the neutral piece that belongs to neither of us, so it may be worth mirroring the envelope spec into #534 on the UCP repo, so it lands as a community artifact rather than a single vendor's. The issuer-specific halves (your identity spec, our risk spec) stay in each repo and the envelope references both. |
|
Identity half is up: Facet-llc/ucp-verifier-envelope#2. Agreed on algorithm agility as a first-class envelope property, not a #534 cleanup. The verifier resolves JWKS by One deliberate difference from your five: our fifth vector is And yes on mirroring the envelope spec into #534 as the neutral community artifact, with each issuer half staying in its own repo. Happy to co-author that #534 post once the field names settle here. The pack now stages both claim types: one envelope, two issuers, two algs, both verify offline. |
|
@westonale-facet Ran your identity half cold: npm i, node gen-vectors.mjs, 8 for 8, including the jose audience pin. wrong-audience as the identity analog of wrong-session is exactly the right mapping, and a KYA verifying with any JOSE library is a real strength of that side. Then I closed the loop. I minted a fresh KYA through your public enroll and mint path (agent fidacy-cross-verify-demo, signed by facet-1b644cbb), paired it with our live production verdict, composed one envelope, and verified both halves offline: ES256 via plain jose against your JWKS, EdDSA via @fidacy/verify against ours. Two kid lookups, two JWKS fetches, dispatch on alg, neither issuer online at verify time. 4 for 4. As far as I know that is the first time the envelope has run end to end. PR: Facet-llc/ucp-verifier-envelope#3 The envelope.json it writes doubles as a concrete field-name proposal so #534 has something executable to react to: a signals map keyed by reverse-domain signal name, each entry carrying format, jws, kid and provider_jwks, everything outside jws an untrusted hint until the signature verifies. Adding a third issuer is adding one more entry, nothing else changes. If that shape works for you I would call the field names settled, and I am in on co-authoring the #534 post: the envelope as the neutral community artifact, each issuer half referenced from its own repo. |
|
Merged. Both halves are on main now (identity #2, risk #1), so the two claim types sit side by side with their generators, and the conformance pack covers both. Ran yours cold the same way first: #3 is the one I want to land next, since it's the first time the envelope runs end to end: one checkout, two live-signed verdicts from two production issuers, two algs, both verified offline with neither of us online. Main just moved under it, so go ahead and rebase One design call worth settling before |
|
Rebased on top of the merged halves and re-ran the whole thing cold from the branch: fresh KYA minted through your public path, our production verdict, 4 for 4 offline. #3 is ready for your review. On provider_jwks: I land where you do, with one sharpening about where the pin lives. The envelope names the issuer; key resolution is out of band; provider_jwks stays as a non-normative convenience hint that MUST NOT override the verifier's pinned source. The sharpening: the pin belongs in each claim type's public spec, not in each verifier's private config. Ours pins the canonical JWKS URL and the issuer is a did:web, so resolution also falls out of the DID document for anyone who prefers that path; yours pins issuer.facet.llc. A verifier's trust list then seeds from the specs it accepts, which keeps the trust decision auditable instead of buried in config. It also matches what the vectors already assume: everything outside the jws is an untrusted hint until the signature verifies, and a hint pointing at the wrong key set simply fails against the pinned source. Already reflected in #3's README so the field-name proposal that goes to #534 says exactly that. |
|
Agreed, and your sharpening puts the pin in the right place: in each claim type's public spec, not per-verifier config, so the trust decision stays auditable instead of buried. Reviewed #3 and merged it, so the envelope runs end to end on main now: identity (#2), risk (#1), cross-verify (#3) all landed. That README framing is what should carry into #534 as the field-name proposal. |
|
Status from the envelope side, and then a process question I would rather ask now than later. Both claim types are written down as prose profiles, not just as running code. The identity profile ( Running both cold before writing the prose turned up something worth flagging beyond that repo, because it is a trap any profile using compact JWS can fall into. Both conformance suites built their The question. The envelope now has two independent claim types, from two independent issuers, on two different algorithms, verifying end to end from committed bytes with neither issuer online, in a single reproducible script. That was the bar this thread set for the shape being real rather than theoretical. What is the path from here to normative text? Concretely: does a proposal like this become spec through a PR against this repo, and if so who ratifies it, or does it stay a referenced external profile? I have not found the process documented publicly, and I would rather build toward whatever it actually is than guess. Happy to do the work in whichever shape is useful, including splitting the envelope out from a vendor namespace if neutral ownership is the blocker. |
|
No public process doc that I've found either, so this is my honest read rather than a citation. My guess: this repo's Discussions are explicitly pre-normative, the actual mechanism is probably a PR against the spec repo once a proposal has enough independent implementations to de-risk it, and the Governing Council or a relevant Technical Council ratifies from there (the Payments TC nomination thread that's open right now is presumably the body that would own this one). Two independent issuers, two algorithms, verified cold from committed bytes is a stronger evidence bar than most spec PRs ship with, so I don't think we're blocked on more running code, and #5 plus your #6 are both merged as of today. I'd rather ask a maintainer directly than keep guessing, happy to open an issue asking the process question plainly if you haven't already. On splitting the envelope out of a vendor namespace: agreed that's probably table stakes before anyone proposes it as normative, want to sketch what that repo structure looks like before we ask? |
|
Yes. I think we should separate the neutral contract from issuer-owned profiles before asking maintainers to ratify anything. Each issuer-owned profile remains external and versioned in its own public repository. Facet owns its identity profile; Fidacy owns risk and decision-provenance. The neutral registry references profiles that meet the conformance bar without transferring ownership of their semantics. The shared repository remains the executable proving ground: cross-issuer vectors, independent consumer verification, and a profile test harness. It should not become the normative home simply because it started under either vendor’s organization. I agree that we should ask a maintainer now instead of guessing. I would frame the question narrowly: what is the path for an independently implemented, backward-compatible extension to become normative UCP text, and which body owns the decision? |
Uh oh!
There was an error while loading. Please reload this page.
Motivation
UCP's signals schema already states that signal values must not be buyer-asserted and may be
"independently verifiable third-party attestations", keyed by reverse-domain identifiers. But there
is no standard 'role' for a neutral risk/trust verifier, and no standard 'signal' for a verifiable
trust verdict. Today each platform or PSP embeds its own risk view, or each vendor defines its own
signal, which fragments how trust is expressed and verified across the ecosystem.
Proposal
(not the merchant, platform, or PSP) that issues a signed, independently verifiable trust verdict
about a transaction.
dev.ucp.shopping.trust_verdict) carrying a signed credential verifiable against the verifier'spublished key set, so any party can check it without trusting the issuer.
com.fidacy.trust_verdictsignal (Apache-2.0, public JSONschema, open-source verifier
@fidacy/verify), which already conforms to the signals schema andships in production.
Why a neutral verifier matters
Risk embedded only in the PSP or platform is not neutral and is not independently checkable. An
independent verifier whose verdict is a signed credential preserves interoperability and lets any
party (merchant, platform, buyer's agent, auditor) verify the decision directly.
Compatibility
Fully opt-in and backward-compatible. A trust verdict is already a valid
signalsentry, so nothingchanges for implementations that do not consume it. No change to existing capabilities or the
checkout schema.
References
All reactions