diff --git a/pkg/common/types.go b/pkg/common/types.go index 6c07d9c7..a0b47ba7 100644 --- a/pkg/common/types.go +++ b/pkg/common/types.go @@ -39,12 +39,16 @@ var ErrCurrencyNotAccepted = errors.New("currency not accepted") // contract until the platform persists a typed flag (platform #778). var ErrOutcomeUnknown = errors.New("purchase outcome unknown") -// ErrRefusedBeforePurchase wraps any error from the approved-upfront check or -// the purchase-count bounds check, both of which run before the purchase -// request is built or sent. Its presence is -// sufficient to know that this call sent no purchase request, but its absence -// proves nothing: other refusals do not carry it. It describes only the call -// that returned it and says nothing about earlier calls with the same +// ErrRefusedBeforePurchase wraps an error from a check that refused the +// purchase before the purchase request was built or sent. It says nothing +// about why: the cause may be an offering upfront above the approved amount +// (or one that cannot be compared with it), a count bound, a service-ownership +// rule, or a duplicate-purchase guard, and retrying or asking for approval may +// not help. Some producers wrap only the sentinel and carry the cause in the +// message, so callers cannot rely on unwrapping to tell the causes apart. Its +// presence is sufficient to know that this call sent no purchase request, but +// its absence proves nothing: other refusals do not carry it. It describes only +// the call that returned it and says nothing about earlier calls with the same // idempotency token. A wrapper that combines several purchase calls must not // propagate it unless none of them sent a request. Detect it with // errors.Is(err, ErrRefusedBeforePurchase).