Skip to content

fix(checkout-api): resolve checkout-race-condition#16

Open
Spkap wants to merge 1 commit intomainfrom
replayx/incident-checkout-race-001-mo6515ju
Open

fix(checkout-api): resolve checkout-race-condition#16
Spkap wants to merge 1 commit intomainfrom
replayx/incident-checkout-race-001-mo6515ju

Conversation

@Spkap
Copy link
Copy Markdown
Collaborator

@Spkap Spkap commented Apr 19, 2026

Summary

Resolve checkout-race-condition for checkout-api with a validated ReplayX patch candidate.

Changed Files

  • demo_app/src/inventory/reserve-stock.ts
  • demo_app/src/checkout/submit-order.ts

Validation

  • Concurrent checkout repro: exit 0
  • Sequential checkout sanity: exit 0

Rollback

Revert the live inventory guard and concurrent checkout settlement handling.

Copilot AI review requested due to automatic review settings April 19, 2026 19:07
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Resolves the demo app’s checkout-race-condition by preventing overselling during stock reservation and treating expected OutOfStock failures as non-fatal during concurrent checkout repro runs.

Changes:

  • Add a post-delay inventory availability guard in reserveStock to prevent committing negative inventory under concurrent requests.
  • Adjust reservation token/version to reflect the committed inventory record version.
  • Update concurrent checkout scenario runner to use Promise.allSettled, ignore OutOfStock rejections, and only fail on unexpected errors.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
demo_app/src/inventory/reserve-stock.ts Adds a post-delay availability check and aligns returned token/version with committed record state.
demo_app/src/checkout/submit-order.ts Switches concurrent mode to allSettled, filters expected OutOfStock failures, and returns only successful results.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 18 to 20
// Intentional bug: this delay makes the pre-check stale under concurrent checkout attempts.
await delay(25);

Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment above this delay says the pre-check becomes stale under concurrent checkouts, but the new post-delay record.available guard makes this no longer an intentional bug. Please update/remove the comment so it accurately describes the current behavior (e.g., that we re-check after the delay to avoid overselling).

Copilot uses AI. Check for mistakes.
Comment on lines +20 to +23
(result) =>
result.status === "rejected" &&
!(result.reason instanceof Error && result.reason.message.startsWith("OutOfStock:"))
);
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic treats "OutOfStock" as a non-fatal rejection by matching on Error.message.startsWith("OutOfStock:"), which is brittle and can easily break if the message changes or the error is thrown from a different realm/type. Consider using a dedicated OutOfStockError class (or an error.code/name field) exported from the inventory layer and checking that instead of parsing the message string.

Copilot uses AI. Check for mistakes.
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.

2 participants