Hints and failure semantics
Scope
This page defines how to interpret gate hints and failure modes across authorize, commit, and ingest.
Hint families
- Quota and rate:
quota.remainingrate.limit
- Funding and budget:
funding.xusd_shortfallbudget.shortfallbudget.low_headroom
- Feature/meter mapping:
feature.meter_not_allowedpolicy.window_not_found
- Pricing:
pricing.not_configuredpricing.changedpricing.meter_price_missingpricing.contract_term_invalid
- Lease:
lease.expiredlease.closed_at_commit
Recommended actions by hint
Treat hints as machine-readable policy signals. Build a deterministic handler per hint type.
| Hint type | Fields to read | Recommended action |
|---|---|---|
rate.limit | seconds, until, remaining | Delay retry by seconds (or until until if present). Queue work instead of immediate retry bursts. If remaining is 0, stop same-window retries for this key path. |
quota.remaining | max_quantity_minor | Downscale requested quantity to max_quantity_minor, or split into smaller chunks. If zero, block this action and ask user to upgrade plan. |
funding.xusd_shortfall | shortfall_xusd | Interrupt paid operation and prompt top-up. If your product supports graceful degradation, switch to a lower-cost path and show the shortfall amount. |
budget.shortfall | budget_id, shortfall_xusd | Ask user/admin to refill the specified budget or switch to another budget policy before retry. Keep the budget id in UI/logs for direct remediation. |
budget.low_headroom | headroom_xusd, threshold_xusd | Allow current request but raise warning state. Prompt proactive top-up or upgrade before hard shortfall occurs. |
pricing.not_configured | feature_code, meters | Do not treat priced output as production-ready for these meters. Escalate to operators to complete pricing configuration before broad rollout. |
pricing.meter_price_missing | meter_code, contract_id, term_key | Keep operation observable, then route to pricing owners to add missing base meter price for the referenced contract term. |
pricing.contract_term_invalid | meter_code, contract_id, term_key, message | Keep operation observable, then fix the invalid contract term definition and re-verify pricing. |
pricing.changed | previous_fingerprint, current_fingerprint | Mark response as repriced relative to client expectation. Refresh client-side quote/preview and display updated price before next high-value action. |
feature.meter_not_allowed | feature_code, meters | Stop commit for this payload shape. Correct meter selection for the feature mapping, then retry with a new idempotency key. |
policy.window_not_found | feature_code | Treat as missing policy coverage. Do not keep retrying; configure policy windows for the feature first. |
lease.expired | expires_at, delta_ms, grace_ms, exceeded_grace | If still within accepted late-arrival window, retry commit once with the same key and monitor outcome. If exceeded_grace=true, create a new authorize/commit cycle and send old event to reconciliation flow. |
lease.closed_at_commit | state | Treat commit as finalized for this lease. Do not create duplicate business effects; fetch/reuse prior outcome via idempotent replay path. |
Failure classes
- Hard rejection (operation fails before commit fact is applied)
- Accepted with quarantined application (commit fact written, settlement/applied quantity is neutralized)
- Replay success (idempotent same request)
- Conflict rejection (same key, different request)
Status-code semantics
400: required protocol input missing (for example idempotency key).401: missing auth context.402: policy/funding/budget blocked admission.403: entitlement required/denied.409: idempotency conflict.422: invalid payload, invalid lease/token, or invalid feature-meter mapping.429: rate-limited.
Quarantine vs rejection
- Rejection (
4xx) means no successful commit response was produced for that request path. - Quarantine applies to commit-time application semantics:
- response is returned
- rating facts are recorded
- applied quantity and settlement are neutralized
- reason codes and hints explain the quarantine cause
Retry guidance
- Safe retry with same idempotency key:
- network ambiguity after request sent
- timeout after server may have completed
- Do not reuse the same key with changed payload.
- For true reattempt with changed business input, use a new idempotency key.
- For
429, preferRetry-Afterresponse header first. If absent, use bounded exponential backoff.
Verify checklist
- Alerting routes
pricing.not_configured,feature.meter_not_allowed, and lease hints to operations. - Product-facing policy differentiates:
- admission failures (
authorizerejected) - post-admission quarantines (
commitapplied as quarantined)
- admission failures (
- Logs include operation, idempotency key, feature, meters, and returned hints.