Mike Bennett

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

BUG-1142Blocker · P1

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

  1. Sign in as a new account with no stored payment method.
  2. Select the standard plan and enter test card 4242 4242 4242 4242, expiry 12/30.
  3. 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.
BUG-1156Major · P2

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

  1. Pin the sandbox clock to 1 January 2026 and create a monthly subscription on the standard plan.
  2. Advance the clock 12 days, to 13 January.
  3. 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.
BUG-1163Minor · P3

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

  1. Sign in and open the checkout page.
  2. Enter test card 4242 4242 4242 4242 and an expiry in the past, for example 01/22.
  3. 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.