Use Case: Team Debugging a Production Payment System Bug
⚠️ Note: This is a hypothetical use case intended to illustrate the workflow. AI responses in practice may differ from the examples below.
When a payment bug reaches production, the natural reaction is to fix it as fast as possible. Superpowers teaches you to slow down at the right moment to fix it the right way -- systematically, with evidence, with review.
Context
Imagine you're working on a small team of 2-3 devs, managing an e-commerce system. One day, the team receives a customer report:
"I bought a product with a 20% discount, used a 10% voucher, but the price wasn't right. I was charged more than what I expected."
After investigating, you discover:
- Product: T-shirt with original price of 500,000 VND, 20% discount
- Voucher: SAVE10, 10% off
- Expected: 500,000 x 0.8 = 400,000 -> 400,000 x 0.9 = 360,000 VND
- Actual: System calculated 350,000 VND
A 10,000 VND discrepancy. The customer was undercharged, but the flawed logic could cause much larger discrepancies with higher-priced products or bigger vouchers.
Tech stack: Node.js, TypeScript, calculateFinalPrice() function
What You'll Learn
Through this use case, you'll practice:
- Systematic Debugging 4 Phases -- a structured debugging process instead of guesswork (see Debugging & Verification)
- TDD Fix -- write a test to reproduce the bug BEFORE fixing it (see TDD)
- Two-way Code Review -- the submitter prepares context, the reviewer reads thoroughly before responding (see Code Review)
- Verification Gate -- only declare "fixed" when there's clear evidence (see Debugging & Verification)
Step-by-Step Walkthrough
Step 1: Phase 1 -- Investigate the Root Cause
Before fixing any code, you need to fully understand the problem. No guessing allowed.
1.1. Read the customer's bug report
The customer sent feedback:
"I bought a T-shirt priced at 500,000 VND, the product page showed a 20% discount. I applied voucher SAVE10 for an additional 10% off. I expected to pay 360,000 VND but the system charged 350,000 VND."
🧑 You provide the AI with the customer's bug report. Record the exact numbers -- don't reinterpret, work with the original data. Example prompt:
"Customer reports a payment bug: bought a T-shirt at 500,000 VND with 20% discount, used voucher SAVE10 for 10% off, expected 360,000 VND but system charged 350,000 VND. Help me debug this systematically."
🤖 AI receives the report, notes the specific numbers (original price, discount %, voucher, expected vs actual). AI does not guess the cause immediately but begins a systematic investigation process.
1.2. Reproduce the error
🤖 AI reads the file src/utils/pricing.ts -- the calculateFinalPrice() function that takes a Product (with discountPercent) and a Voucher (optional, with discountPercent), returning the discounted price. At first glance, the logic looks correct: apply product discount first, then voucher. But this is the code AI thinks is running. AI continues checking the actual code in production.
🧑 You observe AI reading the code and confirm this is the correct file/function to investigate. If AI reads the wrong file, redirect it.
1.3. Check recent changes
🤖 AI runs git log to view recent commits:
git log --oneline -10
Result:
a1b2c3d feat: add loyalty points calculation
f4e5d6a refactor: simplify discount calculation <-- THERE IT IS
b7c8d9e fix: update shipping fee for remote areas
...
🤖 AI notices commit f4e5d6a with the message "refactor: simplify discount calculation" looks suspicious, and checks the diff:
git diff f4e5d6a~1..f4e5d6a -- src/utils/pricing.ts
🧑 You review the git log results alongside AI. If you have additional context (e.g., "that commit was from a new dev, merged last week"), share it with AI to narrow the investigation scope.
1.4. Discover the actual code (buggy code)
🤖 AI examines the diff from commit f4e5d6a and discovers the actual production code was changed: instead of applying discounts sequentially (price x 0.8 then x 0.9), the person who refactored summed the percentages (20% + 10% = 30%) and applied them once (price x 0.7). AI reports the finding to the user.
🧑 You read AI's analysis and confirm: "That's right, the correct business logic should apply them sequentially." If the business rule is different (e.g., summing is actually correct), say so clearly so AI can adjust its investigation.
Issue: This is a logic error -- "simplifying" changed the calculation results.
1.5. Trace the data flow
🤖 AI traces the calculation with both approaches, presenting them clearly to the user:
With the buggy code (summed):
totalDiscount = 20 + 10 = 30
price = 500,000 * (1 - 30/100)
price = 500,000 * 0.7
price = 350,000 VND
Correct logic (sequential):
price = 500,000 * (1 - 20/100) = 500,000 * 0.8 = 400,000
price = 400,000 * (1 - 10/100) = 400,000 * 0.9 = 360,000 VND
Difference: 360,000 - 350,000 = 10,000 VND. 🤖 AI warns: with higher-priced products or larger vouchers, the discrepancy would be much larger.
🧑 You confirm AI's calculations are correct and agree with the conclusion. This is a critical checkpoint -- ensuring both sides agree on the cause before proceeding to the next step.
Note: At this step, you only investigate, you don't fix anything yet. Evidence before theory.
Step 2: Phase 2 -- Pattern Analysis
Once you've reproduced the bug, look for patterns.
2.1. Find examples that work correctly
🤖 AI automatically checks various scenarios to determine when the bug appears and when it doesn't:
Case 1: Product discount only (no voucher)
Input: product = { price: 500000, discountPercent: 20 }, no voucher
Code: totalDiscount = 20, price = 500000 * 0.8 = 400,000
Result: 400,000 VND -- CORRECT
Case 2: Voucher only (product has no discount)
Input: product = { price: 300000, discountPercent: 0 }, voucher = { discountPercent: 10 }
Code: totalDiscount = 0 + 10 = 10, price = 300000 * 0.9 = 270,000
Result: 270,000 VND -- CORRECT
Case 3: Both discounts at the same time
Input: product = { price: 500000, discountPercent: 20 }, voucher = { discountPercent: 10 }
Code: totalDiscount = 20 + 10 = 30, price = 500000 * 0.7 = 350,000
Result: 350,000 VND -- WRONG (expected 360,000 VND)
🧑 You review the cases AI listed. If there are special scenarios AI hasn't considered (e.g., "The system also has a third discount type for VIP customers"), add them so AI can analyze further.
2.2. Compare and conclude the pattern
🤖 AI synthesizes the results and identifies the pattern: the bug only appears when BOTH discounts are applied simultaneously. AI explains the mathematical reason:
- Summed:
price * (1 - (a + b) / 100) - Sequential:
price * (1 - a/100) * (1 - b/100)
These two expressions are NOT mathematically equivalent (unless a or b equals 0).
🧑 You confirm the pattern AI identified matches the system's actual behavior. If there are additional bug reports from other customers, provide them for cross-checking.
Step 3: Phase 3 -- Hypothesis and Testing
3.1. State the hypothesis clearly
🤖 AI states the hypothesis in a clear, structured way:
Hypothesis: The bug occurs because the
calculateFinalPrice()function sums discount percentages (20% + 10% = 30%) instead of applying them sequentially (price x 0.8 x 0.9). Commitf4e5d6a("refactor: simplify discount calculation") refactored the logic from sequential application to summing.
🧑 You read the hypothesis and evaluate whether it's reasonable. If you agree, confirm so AI can proceed with verification. If you disagree or have an alternative hypothesis, raise it. Write it down or add it as a comment -- don't let hypotheses exist only in your head.
3.2. Test one variable at a time
🤖 AI adds console.log to the calculateFinalPrice() function to trace each calculation step, then runs with input from the customer report:
[DEBUG] Initial price: 500000
[DEBUG] Product discount: 20
[DEBUG] Voucher discount: 10
[DEBUG] Total discount (summed): 30
[DEBUG] Final price: 350000
🤖 AI presents the debug results to the user, pointing out which line proves the hypothesis.
🧑 You review the debug output and cross-reference with data from the customer report. Confirm the results match the reported buggy behavior.
3.3. Confirm the hypothesis with specific numbers
🤖 AI creates a comparison table with multiple input sets to demonstrate the bug's impact:
| Case | Summed (bug) | Sequential (correct) | Difference |
|---|---|---|---|
| 500K, 20% + 10% voucher | 350,000 | 360,000 | 10,000 |
| 1,000K, 30% + 15% voucher | 550,000 | 595,000 | 45,000 |
| 2,000K, 50% + 20% voucher | 600,000 | 800,000 | 200,000 |
The discrepancy grows with product price and discount amount. 🤖 AI concludes: hypothesis confirmed.
🧑 You review the comparison table, assess the bug's severity based on real data (e.g., "Our most expensive product is 5 million, so the maximum discrepancy could be..."). Decide the priority for the fix.
Step 4: Phase 4 -- TDD Fix
Now you know the exact cause. Instead of jumping in to fix code, follow the TDD process: write tests first, fix code after.
🤖 AI asks before acting: "Hypothesis confirmed: bug caused by summing percentages instead of applying sequentially. Do you agree for me to proceed with a TDD fix -- write a test reproducing the bug first, then fix the code?"
🧑 You confirm: "Agreed, proceed."
RED: Write a Failing Test That Reproduces the Bug
🤖 AI creates the file src/utils/__tests__/pricing.test.ts with 5 test cases:
- Apply both product discount and voucher sequentially (expected 360,000)
- Product discount only (expected 400,000)
- Voucher only on non-discounted product (expected 270,000)
- No discounts at all (expected 200,000)
- Rounding with fractional prices (expected 263,500)
🤖 AI runs npm test -- --grep "calculateFinalPrice" -> 2 FAIL, 3 PASS. Test 1 fails exactly as predicted: expected 360,000 but received 350,000. Test 5 also fails because the summing logic calculates incorrectly.
Tests 2, 3, 4 pass because they only have one type of discount, so summing and sequential produce the same result.
🧑 You review the list of test cases -- add any if the system has special cases (e.g., "There's also a case where VIP customers get an additional 5% off").
GREEN: Fix the Function So All Tests Pass
🤖 AI fixes src/utils/pricing.ts -- restores the sequential discount application logic: product discount first, voucher discount second (applied to the already-discounted price). Runs tests again -> 5/5 PASS.
🧑 You read the fix diff, confirm the logic matches the system's business rules.
REFACTOR: Add Guard Clauses
🤖 AI adds validation for edge cases in src/utils/pricing.ts: price must not be negative, discount must be between 0-100. Adds 2 test cases for guard clauses to the test file. Runs the full test suite again -> all pass, no regression.
🧑 You review the guard clauses -- confirm the validation limits match business rules (e.g., can discount go up to 100%, or is the max 80%?).
Step 5: Two-Way Code Review
The bug is fixed and tests pass. But before merging, a code review is needed.
Dev A (the fixer) submits a review request
🧑 You ask AI to create a PR. 🤖 AI creates a pull request with well-structured information:
## WHAT
Fix incorrect price calculation when applying both product discount and voucher discount simultaneously.
## ROOT CAUSE
Commit f4e5d6a ("refactor: simplify discount calculation") changed the logic
from sequential application to summing discount percentages.
Summed: 500000 * (1 - (20+10)/100) = 350,000 (WRONG)
Sequential: 500000 * 0.8 * 0.9 = 360,000 (CORRECT)
## PLAN
- Restore sequential discount application logic
- Add 5 test cases covering: both discounts, product only,
voucher only, no discount, and rounding
- Add guard clause for input validation
## CHANGES
- src/utils/pricing.ts: fix calculateFinalPrice()
- src/utils/__tests__/pricing.test.ts: add 7 test cases
## BASE_SHA -> HEAD_SHA
f4e5d6a -> g7h8i9j
Note: Dev A provides complete context so Dev B can review effectively. The submitter is responsible for helping the reviewer understand the problem.
Dev B (reviewer) follows the review process
Dev B (or Dev B's AI) doesn't rush to respond. Instead, follows a 5-step process:
1. READ -- Read the entire PR description and diff
2. UNDERSTAND -- Understand the problem and the fix
Dev B recalculates independently:
Summed: 500000 * (1 - 30/100) = 500000 * 0.7 = 350,000
Sequential: 500000 * 0.8 * 0.9 = 400000 * 0.9 = 360,000
Confirmed: Dev A's calculations are correct.
3. VERIFY -- Check code and tests
Dev B reads the fix code, reads each test case, confirms each test case is meaningful and correct.
4. EVALUATE -- Assess edge cases
Dev B asks:
- What if total discount exceeds 100%? (Handled by guard clause)
- What if price = 0? (0 * anything = 0, ok)
- What if voucher.discountPercent = 0? (price * 1 = price, ok)
- Does this affect other functions? (Check callers of calculateFinalPrice)
5. RESPOND -- Respond with specific, constructive feedback
Dev B does not write:
"Looks good! LGTM"
Dev B writes:
## Review: Fix calculateFinalPrice
### Confirmed
- Sequential application logic is correct. I independently recalculated with 3 different input sets.
- Test cases adequately cover the basic scenarios.
- Guard clause for input validation is sensible.
### Suggestions
1. Should add a test case for voucher.discountPercent = 0
to ensure it doesn't affect the price.
2. Need to check the `applyPromotion()` function in promotion.ts --
it also calls calculateFinalPrice() and may have similar
logic that needs fixing.
3. Should add a comment explaining why discounts are applied
sequentially rather than summed, to prevent someone from
"simplifying" it again in the future.
### Conclusion
Approve with the 3 suggestions above. Suggestion 2 should be checked before merging.
Dev A responds
Dev A reads the feedback and addresses it:
- Added test case for voucher.discountPercent = 0 -- Done
- Checked
applyPromotion()function -- confirmed it only callscalculateFinalPrice()and has no independent discount logic -- No fix needed - Added explanatory comment -- Done
Dev A adds a comment to the calculateFinalPrice() function -- clearly explaining why discounts are applied sequentially rather than summed, to prevent someone from "simplifying" it again in the future. Pushes a new commit and replies confirming all 3 suggestions have been addressed.
Step 6: Verification Gate
Before declaring the bug fixed, apply the 5-step verification process.
🧑 You request: "Run full verification before merging."
1. IDENTIFY -- Which tests need to run
🤖 AI lists the tests to run:
- Unit tests for calculateFinalPrice: 7 test cases
- Integration tests for checkout flow: 3 test cases
- Regression test suite: all
🧑 You add more if needed (e.g., "Run the e2e test for the checkout page too").
2. RUN -- Execute tests
🤖 AI runs all tests:
# Unit tests
npm test -- --grep "calculateFinalPrice"
# Integration tests
npm test -- --grep "checkout"
# Full regression
npm test
3. READ -- Read results line by line
🤖 AI reads and presents the results:
Test Suites: 24 passed, 24 total
Tests: 187 passed, 187 total
Snapshots: 0 total
Time: 12.34s
All 187 tests pass. No regression.
4. CONFIRM -- Cross-reference results
🤖 AI compiles a confirmation checklist:
- 7 test cases for calculateFinalPrice: PASS
- 3 integration tests for checkout flow: PASS
- 187 total tests: PASS
- No tests skipped or pending
🧑 You manually test on the staging environment with the exact input from the customer report:
- Product 500,000 VND, 20% off, 10% voucher
- Result: 360,000 VND -- CORRECT
5. DECLARE -- Conclude with evidence
🤖 AI delivers the conclusion based on evidence:
Bug is fixed. The
calculateFinalPrice()function has been corrected from summing discounts to applying them sequentially. Verified with 7 unit tests, 3 integration tests, and manual testing on staging. No regression. Ready to deploy to production.
🧑 You give final confirmation and approve the merge/deploy.
Results
After applying the Superpowers workflow, the team achieved:
- Bug fixed properly -- not a temporary hotfix but a systematic fix with evidence
- 7 test cases added -- preventing this bug from returning in the future
- Team learned a debugging process -- from reaction mode ("fix as fast as possible") to systematic mode ("fix as correctly as possible")
- Comment added to code -- the next person reading it will understand why the logic must be sequential, and nobody will dare "simplify" it again
Total time: approximately 2-3 hours for the entire process. Seems longer than a "quick fix," but:
- Zero chance of the bug returning
- Zero chance of creating new bugs from a hasty fix
- The team has tests to confidently refactor in the future
Key Takeaways
1. Never guess when debugging
Follow the 4 systematic phases: Investigate -> Pattern Analysis -> Hypothesis -> TDD Fix. Each phase has specific output before moving to the next.
2. git log is your friend
The commit "refactor: simplify discount calculation" was the root cause. The habit of running git log --oneline -10 and git diff before guessing the cause will save you hours of debugging in the wrong direction.
3. Write a test to reproduce the bug BEFORE fixing
The test is evidence the bug exists. When the test fails (RED), you have evidence. When the test passes after the fix (GREEN), you have evidence the bug is fixed. No test = no evidence.
4. Two-way code review
- Submitter: Prepare complete context (WHAT, ROOT CAUSE, PLAN, CHANGES). Help the reviewer understand the problem quickly.
- Reviewer: Read thoroughly before responding. Don't write "LGTM" if you haven't actually checked. Give specific, constructive feedback.
5. Evidence before claims
Only declare "fixed" when you have clear verification evidence: tests pass, no regression, manual testing succeeds. A claim without evidence is a promise without a guarantee.
References
- Debugging & Verification -- The complete 4-phase debugging process
- TDD -- The RED-GREEN-REFACTOR cycle
- Code Review -- The two-way review process
- Iron Laws -- The inviolable rules of Superpowers