Replies: 12 comments 5 replies
|
The distinction you draw at the end is the one that matters: "validating that the CartMandate and PaymentMandate are consistent and deciding whether a later version of the checkout is still within the authority the user originally granted" are two different checks that happen to run at the same moment. Consistency is an integrity question, is this the cart that was signed. Authority is a scope question, does the change stay inside what the user actually granted. Your question is really about the second, and it does not reduce to the first. Your subscription example is the one that shows why materiality cannot be a delta on the total. The immediate amount went down, yet the authority required went up, because a recurring commitment is a larger and different grant than a one-time purchase. So the test is not how far the amount moved, it is whether the change stays inside the dimensions the user's original authority actually covered. A tax move within whatever tolerance that authority allowed stays in scope. Introducing a recurring obligation crosses a dimension the original grant never spoke to, whatever the total does. That is why your options 2 and 4 are closer to the same answer than they look. A later checkout can be judged against the original authority declaratively only where the authority was expressed in terms that can name the dimension that changed. For any dimension the authorisation never named, the determination has nowhere to live but application policy, which in practice means the user never granted that dimension at all. So the lever is how expressive the authority declaration is allowed to be, and where the boundary of that expressiveness should sit. Which layer do you think should own it, the mandate that carries the authority, or the layer that knows which checkout changes are material? |
|
The four options are not really alternatives; they are layers, and the answer to "which layer decides" is: the layer that issued the authority decides, and it decides at issuance, not at checkout time. The subscription example is the tell. Total went down, authority required went up. So materiality cannot be a threshold on amount; it has to be a check per dimension of the grant: amount, currency, recurrence, counterparty, category, delivery window, whatever the grantor actually bounded. A change is inside authority iff every bounded dimension still evaluates true against the new checkout state. If the mandate never bounded "recurring", then either recurring is denied by default (fail closed) or the grant was underspecified, and the fix is at issuance, not in the agent's judgement. That gives clean answers to the list:
Two rules from A202, an open spec for exactly this seam that I maintain, as a reference shape: (a) a mandate carries a closed, typed constraint vocabulary evaluated deterministically; an unregistered constraint type evaluates to deny at runtime and fails schema validation, tested independently; (b) an approval binds to the hash of the exact action, so change one byte of the checkout and the approval is void, which makes "the cart moved" and "re-approve" the same event. https://github.com/a202-protocol/a202/blob/main/authority/commercial-mandate-v0.1.md (sections 4 and 8). Happy to compare with how AP2 wants to slice it. |
|
The framing that's helped us: treat "renewed authorization" as a deterministic function of the delta, not a per-field rule. Compare the executing action against the authorized envelope the mandate defines, and classify each change by whether it crosses a declared authority boundary:
Your tax $8.00→$8.17 and Fri→Sat cases are within-envelope iff the mandate declared a tolerance/window. The one-time→recurring case is the interesting one: it isn't "a lower price", it's a different authority class (an ongoing debit), so it should always require renewed authorization even though the upfront number went down. +1 to @The-JKR that the issuing layer decides — I'd add that this is exactly why provenance matters: the substitute-SKU case depends on whether the substitution authority was user-granted or merchant-asserted. A merchant-asserted change to a user-authorized cart is a different trust tier and shouldn't silently inherit the original authorization. Two things that made this operational for us:
We build this as a deterministic decision layer (Quesen — typed context in → PASS/REVIEW/BLOCK + receipt, no model in the scoring path); happy to share the delta-classification rules if a concrete reference helps. Either way, I think a small normative table of "boundary-crossing" dimensions in the spec would remove most of the per-implementation ambiguity here. |
|
Three sharp answers already — I'll add what these distinctions look like when they hit an actual implementation, since I've been testing exactly this boundary. |
|
I think there is one distinction here that may resolve the apparent tension between exact checkout binding and typed constraints: they seem to apply at different transitions. For a closed Checkout Mandate, I agree the The autonomous case seems different, though. There the user does not initially authorize a particular checkout hash; they authorize an open mandate, and the agent later creates/signs a closed mandate for a checkout derived from that authority. Suppose the open mandate constrains merchant and line items, but cannot express delivery timing. The agent receives a checkout with Saturday delivery and creates a closed mandate whose But there is still a separate question: what establishes that the user's open authority allowed the agent to choose Saturday delivery in the first place? So I think there may be two invariants:
On that reading, constraint vocabulary isn't latitude layered on top of a checkout hash. It defines delegated authority before the closed checkout exists; the hash then protects the result of that derivation. That leaves a fairly concrete normative question: if an authority-bearing checkout dimension cannot be expressed by the open mandate, what are the semantics — default-deny / renewed authorization, unconstrained delegation, or something defined by the commerce protocol? Is that the right way to read the open-vs-closed verification boundary? |
|
@arjun2075 the two-invariant split is the right decomposition — and I think it's worth making explicit that the two invariants are verified by different mechanisms. Conflating them is where implementations get stuck (as @felixpg13-glitch's "strict binding vs workable commerce" tension shows). closed → execution is an integrity check: the executing checkout must equal what the closed mandate bound. This is pure recomputation — normalize + hash the execution-time call and compare to the bound open → closed is an authority-derivability check, and it can't be a hash — the closed checkout didn't exist at authorization time. This is where the typed constraint vocabulary lives (+1 to @The-JKR): each dimension the open mandate bounded — merchant, line items, amount tolerance, currency, recurrence flag, delivery window — is evaluated against the derived checkout, fail-closed on any dimension the grant never named. Your Saturday-delivery case is exactly the failure mode: if the open mandate couldn't express delivery timing, the derivation isn't "authorized," it's unconstrained — and unconstrained ≠ permitted. The piece I'd add to your model: open → closed also carries an issuer/provenance question that closed → execution doesn't. When the agent fills an undeclared dimension, who asserted the value matters — a merchant-asserted substitution or delivery date derived under an open mandate is a weaker trust tier than a user-confirmed one, and shouldn't silently inherit the original authority. So the seam produces three outcomes, not two:
In our engine (2) and (3) surface as a decision state distinct from an integrity failure: an unattested/client-asserted grant on a sensitive dimension can't If useful, I'm happy to contribute this seam as a set of deterministic, reproducible test vectors (request → receipt, replayable offline) — we did the same for a UCP commercial-intervention lifecycle. Might give #211 and this thread a concrete conformance surface rather than prose. |
|
@Shxnque the two-invariant split with different mechanisms per invariant is the right decomposition, and it sharpens what I was reaching for with the binding/commerce tension: if closed→execution is pure recomputation, the amount-tolerance question never lives there — it belongs to open→closed, where the vocabulary can actually express it. Strictness at execution time becomes free; flexibility exists only where the grant declared it. From the implementation side, two confirmations and one addition:
|
|
Yes — I think deterministic vectors would be a useful way to make this concrete. One thing I’d keep explicit before turning the model into an AP2 conformance surface, though: I don’t think the expected result for the “authority-underspecified” case is established yet. That’s actually the normative question I’m trying to isolate here. For example, I think we can already write unambiguous vectors for:
But for:
the mechanism is now clear, but the expected AP2 verdict still seems unresolved. My preference is fail-closed / renewed authority, but I wouldn’t want a conformance suite to bake that in as an AP2 requirement before the protocol actually says whether omission means “not delegated”, “unconstrained”, or “delegated to semantics defined elsewhere.” So perhaps the useful test vector here is initially an ambiguity vector: same open mandate, same derived checkout, and ask what AP2 says the verifier MUST do. Once that semantic is specified, it becomes a normal pass/fail conformance case. I’d also keep the vectors AP2-native and implementation-neutral so they can be shared across #211/#332 without depending on Quesen, SpendShield, or another enforcement model. If that sounds right, I think we now have a fairly small set of cases that could turn this discussion into something executable. |
|
Yes — that sounds exactly right to me. I agree that we should keep the authority-underspecified case explicitly separate from the cases whose expected verdict is already established. My fail-closed / renewed-authority preference is a policy position, not something I want to smuggle into an AP2 conformance suite before AP2 actually defines the semantics of omission. So I think the initial set can be deliberately small:
For (4), the vector should not initially assert ALLOW or DENY. It should instead make the question executable and precise: given the same open mandate and the same derived checkout, what MUST an AP2 verifier do when authority over that dimension is not explicitly represented? As you say, once AP2 specifies whether omission means not delegated, unconstrained, or delegated to semantics elsewhere, that vector can become an ordinary pass/fail conformance case. Keeping these AP2-native and implementation-neutral also makes sense to me. That way the vectors are useful across #211/#332 and can help isolate the protocol semantics independently of Quesen, SpendShield, or any particular enforcement architecture. If useful, I can draft the four vectors in a minimal shared format next, with only mandate input, derived checkout/execution input, and expected status/question — no implementation-specific concepts. |
|
Yes — I think drafting those four vectors would be very useful. The minimal format you suggest sounds right: open/closed mandate input, derived checkout or execution input, and expected status/question, with no implementation-specific enforcement concepts. For (4), it may help to use one concrete checkout dimension so the ambiguity isn’t abstract — e.g. delivery timing/window — while keeping the expected result explicitly unresolved: expected: NORMATIVE_QUESTION rather than ALLOW/DENY. That should make the distinction quite crisp:
If we can get those into a small shared format, I think that gives #332 something much more actionable than another round of conceptual discussion, and it should also make it obvious exactly what normative decision is still missing. Please go ahead with the draft. |
|
Drafted — docs/conformance/ap2-authority-vectors.md Format as discussed: open/closed mandate input → derived checkout/execution input → expected status, with no implementation-specific enforcement concepts. C1–C3 are treated as established for this draft (integrity failure / valid derivation / authority violation). C4 uses your suggested concrete dimension: the mandate never names a delivery window, while the derived checkout specifies delivery = Saturday. Its expected status is the literal NORMATIVE_QUESTION, rather than ALLOW/DENY. The three candidate omission semantics (not delegated / unconstrained / delegated elsewhere) are listed as the fork points. Once AP2 specifies the semantic, C4 can split into ordinary pass/fail cases without changing the vector format. The file is intended as a neutral artifact that can be shared across #211/#332. Happy to adjust the format or C4 fixture if needed. |
|
This is exactly the shape I had in mind. Thanks for turning it into something executable. I especially like keeping C4 as One refinement that might make the normative fork even sharper: I think there are actually two omission cases worth keeping distinct:
Those do not necessarily have the same semantics. For this thread, the second case is the one I was trying to isolate, so delivery = Saturday is a good C4 fixture. Maybe keep the current case as something like C4: unexpressible authority dimension → NORMATIVE_QUESTION, and optionally add a sibling vector for supported constraint omitted. That would let the eventual AP2 answer distinguish the two without changing the vector format. C1–C3 otherwise look like a clean established baseline to me. This feels like a useful conformance artifact to put in front of the maintainers rather than continuing the question only in prose. |
Uh oh!
There was an error while loading. Please reload this page.
I’ve been looking at the CartMandate / PaymentMandate consistency discussion in #211, and there’s one related case I’m trying to understand.
How should an implementation handle normal checkout changes that happen after the user has authorized the checkout?
A few examples:
These all change the checkout the user originally authorized, but they don’t feel equivalent from an authorization perspective.
The tax change might reasonably still be within the user’s intent. A recurring commitment probably shouldn’t be, even if the immediate total is lower.
My question is: which layer is expected to make that determination in AP2?
Is the expectation that:
#211 talks about defining which differences are allowed versus which require renewed confirmation, so this seems related, but I think there may be a distinction between validating that the CartMandate and PaymentMandate are consistent and deciding whether a later version of the checkout is still within the authority the user originally granted.
Curious how the maintainers are thinking about this, and whether this is already covered somewhere in the spec or planned work that I’ve missed.
All reactions