Review: Fix Stripe SDK v15 webhook crash + add webhook Prometheus metrics

review-856-2026-04-04-r2 Doc

review ready

Verdict: READY

Re-review after refinement. Previous review review-856-2026-04-04 returned NEEDS_REFINEMENT with 5 BODY fixes. All 5 have been addressed in the updated issue body.

Template Completeness

  • [x] Type -- Bug
  • [x] Lineage -- references #343, #346, supersedes #719
  • [x] Repo -- forgejo_admin/basketball-api
  • [x] What Broke -- detailed root cause with error message, SDK version mismatch, live test confirmation
  • [x] Repro Steps -- 5 clear steps
  • [x] Expected Behavior -- clear, includes metrics expectation
  • [x] Environment -- cluster, SDK versions, pin info
  • [x] Acceptance Criteria -- 5 items, all verifiable
  • [x] Related -- present with issue links, project reference, downstream dependency, key files
All required bug template sections present and complete.

Traceability

  • [x] story:WS-S18 -- "As a parent, I want to receive a branded email with jersey ordering link so that I can order without bringing cash"
  • [x] story note verified -- found in project-westside-basketball user-stories section (Parent stories list)
  • [x] arch:basketball-api label present
  • [ ] arch note MISSING -- [SCOPE] Create architecture note arch-basketball-api for component basketball-api (carried forward from first review)
  • [x] Forgejo issue -- forgejo_admin/basketball-api#350, open

File Targets

  • [x] src/basketball_api/routes/webhooks.py -- verified: file exists (412 lines), contains exactly 23 Stripe object .get() calls. 2 additional .get() calls are on Python dict (_STRIPE_STATUS_MAP) and SQLAlchemy (db.get) -- correctly excluded in issue body. Line 301 confirmed as first .get("metadata") in main handler.
  • [x] pyproject.toml -- verified: line 16 shows "stripe>=11.0" with no upper bound. No prometheus_client dependency present yet.
  • [x] src/basketball_api/routes/health.py -- verified: file exists. Issue correctly mentions it as candidate location for Prometheus counters.

Repo Placement

OK. Issue filed on forgejo_admin/basketball-api, fix is in basketball-api. Single repo scope confirmed.

Dependencies

  • #719 -- now explicitly superseded in Lineage section. No longer a scope overlap concern.
  • #720 (backlog): related code area, independent bug. Not a blocker.
  • #731/#733: pre-existing test failures. AC 5 now reads "No new test failures introduced" which correctly scopes around this.
  • Downstream: pal-e-platform#272 (alerting) noted as dependent on metrics from this ticket. Documented in Related section.

Acceptance Criteria

  • AC 1 (pin stripe <15): verifiable via grep on pyproject.toml. Clear.
  • AC 2 (replace 23 .get() calls): verifiable via grep. Count now correct. Clear.
  • AC 3 (live webhook test): manual validation. Acceptable for bug fix.
  • AC 4 (Prometheus metrics + prometheus_client dep): now explicitly includes the dependency addition. Verifiable via curl /metrics. Clear.
  • AC 5 ("No new test failures introduced"): correctly scoped to avoid pre-existing failures. Clear.

Blast Radius

Low. Stripe .get() usage is isolated to webhooks.py. No other files use .get() on Stripe objects. The /metrics endpoint change is additive. Pin change preserves current working behavior (stays on v14.x).

Decomposition Assessment

3 file targets in 1 repo, 5 acceptance criteria. Bug fix (pin + .get() replacement) is mechanical. Metrics addition is small and additive. Single agent can handle in one pass. No decomposition needed.

Refinement Verification

All 5 BODY fixes from review-856-2026-04-04 confirmed addressed:
  • File paths -- now uses repo-root notation (src/basketball_api/routes/webhooks.py), health.py mentioned in Key files.
  • .get() count -- corrected to 23 with explicit note about 2 non-Stripe .get() calls.
  • prometheus_client -- explicitly called out in AC 4.
  • #719 superseded -- noted in Lineage section.
  • AC 5 reworded -- "No new test failures introduced."

Recommendation

  • [SCOPE] Create architecture note arch-basketball-api for component basketball-api (carried forward -- does not block dispatch).
No BODY or LABEL fixes needed. Ticket is ready for dispatch.