Deliverable
Defect reports
Three reports in the form I file them, each one reproducible from the demo repo on build 4.2.1-rc3. The test of a good defect report is whether a developer who has never seen it can reproduce the problem without asking a question.
Sample deliverable. Written for this site against a fictional product with no client data and no confidential material.
Reports
Duplicate charge when the payment form is submitted twice in quick succession
- Environment
- Build 4.2.1-rc3 · Chromium via Playwright · sandbox payment processor
- Frequency
- 5 of 5 attempts
- Reproduce
- pytest -k double_click · Postman: "Processor view: charges for the subscription"
Steps to reproduce
- Sign in as a new account with no stored payment method.
- Select the standard plan and enter test card 4242 4242 4242 4242, expiry 12/30.
- Double-click Confirm, so the second click lands before the first response returns.
- Expected
- One charge. The second submission should be idempotent and return the result of the first.
- Actual
- The processor captured two charges of $99.00. The app shows one subscription and one paid invoice, so the customer is billed twice with no in-app trace.
- Impact
- Money movement defect. Reaches the customer statement before anyone internal sees it, and refunds must be issued manually.
- Notes
- The server recognises the repeated Idempotency-Key and returns the original response, but calls the processor again first. The front end makes it easy to hit: the Confirm button is disabled when the response arrives, not on the click.
- Evidence
- Playwright trace and screenshot from the failed run, the processor view showing both captures, and the database total of paid invoices for comparison.
Proration on mid-cycle upgrade is calculated against the wrong period length
- Environment
- Build 4.2.1-rc3 · API direct · sandbox clock pinned to the start of a 31-day month
- Frequency
- 5 of 5 attempts, on 31-day months only
- Reproduce
- pytest -k 31_day · Postman: "Upgrade to the pro plan"
Steps to reproduce
- Pin the sandbox clock to 1 January 2026 and create a monthly subscription on the standard plan.
- Advance the clock 12 days, to 13 January.
- Upgrade to the pro plan with PATCH /v1/subscriptions/:id/plan.
- Expected
- Prorated amount calculated across 31 days: $47.42, matching the value finance supplied for this scenario.
- Actual
- Prorated amount is $49.00, calculated as though the period were 30 days. The difference scales with plan price and is always in the vendor’s favor, which makes it a compliance question rather than a rounding annoyance.
- Impact
- Every upgrade in a 31-day month overcharges. Silent — no error, no alert, and the invoice looks plausible.
- Notes
- Reproduced against the API directly to rule out the UI. The same upgrade in a 30-day month calculates correctly ($46.42), which points at a hardcoded 30 in the proration helper rather than the real period length.
- Evidence
- Postman run of the upgrade request with the request and response bodies, the finance-supplied expected values, and the same request against a 30-day period for contrast.
Card expiry field accepts a past date
- Environment
- Build 4.2.1-rc3 · Chromium via Playwright
- Frequency
- 5 of 5 attempts
- Reproduce
- pytest -k past_expiry
Steps to reproduce
- Sign in and open the checkout page.
- Enter test card 4242 4242 4242 4242 and an expiry in the past, for example 01/22.
- Click Confirm.
- Expected
- Client-side validation rejects the expiry before the request is sent.
- Actual
- The form submits. The processor rejects the charge and the user sees “Your payment could not be processed.”, which reads as a bank problem rather than a typo they can fix.
- Impact
- Low severity, but it converts a self-correcting user error into an abandoned signup. Worth fixing on conversion grounds more than correctness ones.
- Notes
- The field validates the format only, through the input’s pattern attribute, and never checks the date. Server-side validation is present and correct — this is a front-end gap only.
- Evidence
- Screenshot and page source after the submit, and the Playwright trace showing the request that should never have been sent.
On severity
Severity describes the damage; priority describes the schedule. They are separate fields because they answer separate questions, and collapsing them is how a cosmetic issue on the checkout page ends up ranked above a silent overcharge.
I set severity from the impact on the business and leave priority to the product owner, with a recommendation attached. That keeps the argument about the release plan rather than about the bug.
Reproduce them
All three defects are seeded in the demo repository. Run make test for the browser and API suite or make newman for the Postman collection, and the failures map back to the IDs above. The same commands with -fixed pass, which is how a fix gets verified. The test strategy shows how these three roll up into a release recommendation.