Skip to content

docs(purchase): a player whose own limit ran out gets a limit decline, not an inventory one - #83

Merged
dinosoeren merged 2 commits into
mainfrom
soeren/limit-decline-status-quantity-aware
Oct 31, 2026
Merged

dinosoeren merged 2 commits into
mainfrom
soeren/limit-decline-status-quantity-aware

Conversation

@dinosoeren

@dinosoeren dinosoeren commented Oct 31, 2026 •

Copy link
Copy Markdown
Collaborator

Why

A game backend asked which decline status to send from ConfirmPayment when a player has no purchases of a price point left. The published comment for FAILED_INSUFFICIENT_INVENTORY ("due to insufficient inventory") reads as a fit for that case, but Stash shows the player "This offer just sold out" for it. A per-player limit should get "Purchase limit reached". On 29 Oct we agreed with that game's engineers that PURCHASE_CONFIRMATION_STATUS_FAILED_PURCHASE_LIMIT_EXCEEDED is the right status: https://stashgg.slack.com/archives/C0BTY2W7NGN/p1793292550487739

This PR writes that rule into the enum comments, so every integrator reading the API reference picks the same status. Soeren Walls approved this exact text, including narrowing INSUFFICIENT_INVENTORY to a stock shared across players, on 31 Oct 2026. Review round 1 made the shared-stock comment quantity-aware as well (lower than the quantity, for example 0), so a purchase larger than the shared stock left still has a documented status.

Grounding (pie-mono main):

  • go_workspace/pkg/integrations/generic/checkout_failure_reason.go, confirmationStatusToReason (L128-147): INSUFFICIENT_INVENTORY maps to OFFER_OUT_OF_STOCK, and both PURCHASE_LIMIT_EXCEEDED and PACK_LIMIT_EXCEEDED map to PURCHASE_LIMIT_REACHED. registrationStatusToReason (L83-101) maps the register statuses value for value.
  • The purchase carries a quantity, so a count of 0 is not the only limit decline: ConfirmPaymentRequest.PurchasedItem.quantity and RegisterPaymentRequest.PurchaseRegistration.quantity in purchase/v1/service.proto, and PurchasableItem.max_purchasable in catalog/v1/service.proto ("refuses a purchase whose quantity exceeds it"). The comments say "lower than the quantity purchased, for example 0", which covers a purchase of 2 with 1 left and does not decline the purchase that uses up the last unit.

What changed

server/egress/shop/purchase/v1/enums.proto, comments only:

  • PurchaseConfirmationStatus: FAILED_INSUFFICIENT_INVENTORY (a stock shared across players is lower than the quantity purchased, for example 0), FAILED_PURCHASE_LIMIT_EXCEEDED (the item's max_purchasable is lower than the quantity purchased) and FAILED_PACK_LIMIT_EXCEEDED (the same, for the pack's max_purchasable).
  • PurchaseRegistrationStatus: the same three statuses, worded to match, since the two enums map value for value.
  • docs/gen/swagger.v1.json regenerated. A structural diff shows only the title text of these two enums changed (8 and 4 paths); no per-value docs were dropped (no comment ends in a period).

The wire contract is unchanged. These comments reach docs.stash.gg through the usual publish chain: this PR, then the pie-mono proto/public bump and swagger regeneration, then the docs deploy. stashgg/stash-docs#189 updates the ConfirmPayment section of the real-time catalog endpoints page.

Intent

flowchart LR
  C{{"Confirm-time check<br/>in the game backend"}}:::existing
  C -- "shared stock<br/>lower than quantity" --> I["FAILED_INSUFFICIENT_INVENTORY<br/>comment: stock shared across players"]:::this
  C -- "item max_purchasable<br/>lower than quantity" --> L["FAILED_PURCHASE_LIMIT_EXCEEDED<br/>comment: quantity-aware"]:::this
  C -- "pack max_purchasable<br/>lower than quantity" --> P["FAILED_PACK_LIMIT_EXCEEDED<br/>comment: quantity-aware"]:::this
  I --> S1(["Player: offer sold out"]):::existing
  L --> S2(["Player: purchase limit reached"]):::existing
  P --> S2
  classDef this fill:#ffd8a8,stroke:#e8590c,stroke-width:4px,color:#111
  classDef existing fill:#dbe4ff,stroke:#4263eb,stroke-width:1px,color:#111
Loading

Legend: orange = changed here, blue = existing behaviour; hexagon = rule, rounded = what the player sees where the checkout renders the reason.

Big Picture

flowchart LR
  A["public-api<br/>this PR: enum comments"]:::this --> B["pie-mono<br/>proto/public bump +<br/>swagger regen"]:::todo
  B --> D["docs.stash.gg<br/>API reference"]:::todo
  E["stash-docs<br/>endpoints page paragraph"]:::open --> D
  classDef this fill:#ffd8a8,stroke:#e8590c,stroke-width:4px,color:#111
  classDef open fill:#e5dbff,stroke:#7048e8,stroke-width:1px,color:#111
  classDef todo fill:#f1f3f5,stroke:#868e96,stroke-width:1px,stroke-dasharray:5 5,color:#333
Loading

Facts only: Stash already handles all three statuses on main; this PR changes no behaviour, only which status the reference tells integrators to send.

🤖 Generated with Claude Code


Tip

💥 Blast Radius — No Risk

Intent: Help integrators choose the decline status that gives players the appropriate message when a purchase limit or shared stock runs out.

The change updates shared guidance without changing runtime behavior or wire values.

Overview
server/egress/shop/purchase/v1/enums.proto clarifies the inventory, item-limit, and pack-limit statuses for registration and confirmation.

Shop reach: none — no shop runtime behavior changes; the revised guidance is available to all integrators.

Payments path: The catalog's max_purchasable informs the game backend's limit check, which selects a registration or confirmation decline status. The reference now directs per-player limits to purchase-limit statuses and shared stock shortages to insufficient inventory; the PR describes the existing status-to-player-message mapping.

Scope is the purchase enum comments and one generated output; enum values and request and response fields are unchanged.

Not reviewed: 1 generated file(s) — marked linguist-generated in .gitattributes: docs/gen/swagger.v1.json.

Ripley Review v0.1.0 · f2e573c · Report Issue

…it runs out

The comments on the inventory and limit statuses of PurchaseConfirmationStatus
and PurchaseRegistrationStatus now say when each applies:

- FAILED_INSUFFICIENT_INVENTORY: a stock shared across players has run out
- FAILED_PURCHASE_LIMIT_EXCEEDED: the item's own remaining count
  (max_purchasable) is lower than the quantity purchased, for example 0
- FAILED_PACK_LIMIT_EXCEEDED: the same, for the pack's remaining count

Comments only; the wire contract is unchanged. docs/gen/swagger.v1.json is
regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FAILED_INSUFFICIENT_INVENTORY now applies when a stock shared across
players is lower than the quantity, for example 0, so a purchase of 2
with 1 shared unit left still has a documented status.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dinosoeren
dinosoeren merged commit 6dbca14 into main Oct 31, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant