Skip to content

docs(audit): correct /payment-result route framing β€” already shipped 2026-04-16#62

Merged
TortoiseWolfe merged 1 commit intomainfrom
043/doc-fix-payment-result-route-name
Apr 27, 2026
Merged

docs(audit): correct /payment-result route framing β€” already shipped 2026-04-16#62
TortoiseWolfe merged 1 commit intomainfrom
043/doc-fix-payment-result-route-name

Conversation

@TortoiseWolfe
Copy link
Copy Markdown
Owner

Summary

The 2026-04-25 audit cross-referenced spec text against documented status rather than the filesystem and concluded the /payment-result route was "missing." It is not. src/app/payment-result/page.tsx shipped in commit ffb33a1 on 2026-04-16 β€” a 290-LOC, 6-state page (loading, missing-id, not-configured, loaded, not-found, error) with auth gating, suspense, real-time updates via usePaymentRealtime, and a working retry button.

The wrong "missing" framing then propagated through STATUS.md, PRP-STATUS.md, the spec, the truth-table, the stability tracker, and the session handoff. This PR corrects all seven surfaces and rewrites the gap list to reflect the real B1 work that #43 still demands:

Also corrects the assumed-future names of the three remaining payment routes from /payment/* (nested) to /payment-* (kebab-case) to match the existing convention shared with /payment-demo, /payment-result, and 8 other top-level kebab-case routes. There is no /payment/ parent in the app today and creating one for these routes hasn't been justified.

No code changes. A follow-up PR will close gaps 1-5 above. User Stories 3 + 4 are deferred to a separate PR after that.

Scope

7 doc files, +91/-73 lines:

  • STATUS.md β€” flip 040 from [!] to [~]; fix route count from 4 missing to 3
  • features/payments/040-payment-retry-ui/spec.md β€” Status field + AUDIT-IMPL-STATUS block rewritten
  • features/payments/040-payment-retry-ui/040_payment-retry-ui_feature.md β€” Status line rewritten
  • docs/prp-docs/PRP-STATUS.md β€” 040 row + recommended-actions list updated
  • docs/STABILITY-TRACKING.md β€” B1 description rewritten; B2/B3/B4 route names switched to kebab-case
  • docs/SESSION-HANDOFF-2026-04-27.md β€” inline "Correction" callout, B1 framing fixed
  • scripts/audit/truth-table.json β€” 040 entry: code_evidence expanded, gaps rewritten, notes explain how the audit went wrong

Test plan

  • CI green (no code changes β€” only doc + JSON edits)
  • Verify zero remaining /payment/result references in tracked docs (excluding the two intentional explanations of the divergence): `grep -rn '/payment/result' STATUS.md docs/ features/ scripts/`
  • Spot-check that the existing E2E tests in `tests/e2e/payment/03-failed-payment-retry.spec.ts` (which already use the correct `/payment-result` path) still pass on the next CI run

Why doc-only

Decoupling the truth surface from the code work means the wrong framing leaves `main` immediately, the next PR is pure code, and the diff stays trivial to review.

πŸ€– Generated with Claude Code

…2026-04-16

The 2026-04-25 audit cross-referenced spec text against documented status
rather than the filesystem and concluded the /payment-result route was
"missing." It is not. src/app/payment-result/page.tsx shipped in commit
ffb33a1 on 2026-04-16 β€” a 290-LOC, 6-state page (loading, missing-id,
not-configured, loaded, not-found, error) with auth gating, suspense,
real-time updates via usePaymentRealtime, and a working retry button.

The wrong "missing" framing then propagated through STATUS.md, PRP-STATUS.md,
the spec, the truth-table, the stability tracker, and the session handoff.
This commit corrects all seven surfaces and rewrites the gap list to reflect
the real B1 work that #43 still demands:

- Retry button regenerates idempotency_key instead of reusing the queued
  one (loses dedupe with the offline-queue replay path that landed in #59)
- No retry attempt counter or cooling period (FR-008/009/010)
- No error categorization β€” UI only shows status === 'failed' with no
  reason context (FR-002 lists 8 error types, none mapped)
- No offline error banner
- No audit log on retry attempts (NFR-007)
- User Story 3 (update payment method, FR-011-FR-015) entirely unbuilt
- User Story 4 (guided recovery wizard, FR-016-FR-019) entirely unbuilt

Also corrects the assumed-future names of the three remaining payment
routes from /payment/* (nested) to /payment-* (kebab-case) to match the
existing convention shared with /payment-demo, /payment-result, and 8
other top-level kebab-case routes. There is no /payment/ parent in the
app today and creating one for these routes hasn't been justified.

No code changes. The next commit will close gaps 1-5 above; User Stories
3 + 4 are deferred to a follow-up PR.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@TortoiseWolfe TortoiseWolfe merged commit 7c45970 into main Apr 27, 2026
28 checks passed
TortoiseWolfe added a commit that referenced this pull request Apr 28, 2026
…r + cooling, error categorization, offline banner, audit log (#43) (#63)

Closes 5 of 7 gaps in #43. Route /payment-result itself shipped 2026-04-16 (commit ffb33a1); this PR closes the retry-UX gaps obscured by the original 'route missing' framing (corrected in #62).

Closes (gaps 1-5 of #43):
1. Retry button regenerates idempotency_key. retryFailedPayment() now reuses parent's queued key; doubled clicks become server-side ON CONFLICT no-ops (matches PR #59's offline-queue dedupe).
2. No retry attempt counter or cooling. payment_intents gains retry_count + parent_intent_id; service refuses past RETRY_LIMIT=3 (FR-009); enforces COOLING_PERIOD_MS=30s (FR-010); custom error classes carry waitMs for UI countdown (FR-008).
3. No error categorization. New error-categorization.ts maps Stripe + PayPal error_code to one of FR-002's 8 categories with non-technical user message + resolution hint + recoverable flag (FR-001/003/006/NFR-001).
4. No offline error banner. New OfflineRetryBanner 5-file component reads useOfflineStatus + paymentQueue.getCount(); silent in steady state.
5. No audit log on retry. auth_audit_logs CHECK extended with payment_retry; every retry recorded with { original_intent_id, new_intent_id, retry_count, deduped }.

Bonus: PaymentRetryExpiredError refuses retry past parent's 24h provider session.

Deferred (gaps 6-7 to follow-up PR):
- US3 (Update Payment Method, FR-011-FR-015) β€” has stripe.js + PCI surface
- US4 (Guided Recovery Wizard, FR-016-FR-019) β€” largest piece

E2E test fixes during CI:
- 1ea0833 β€” Navigate online before flipping offline (static-export needs network for first load).
- a350833 β€” Synthesize navigator.onLine + 'offline' event manually. Playwright's setOffline blocks request traffic but doesn't fire the offline browser event in Firefox/WebKit; only Chromium does. Real browsers DO fire the event on real network drops, so synthesizing it is closer to production behavior and works cross-browser.

Verification:
- pnpm test: 3249/3249 across 286 files (60 new for B1)
- pnpm test:rls: 55/55 (new columns inherit existing policies)
- pnpm run type-check, lint: clean
- CI: 29/29 green incl. all three regression-target gen 3/6 shards (chromium, firefox, webkit)

Schema applied locally; cloud apply is reviewer's call (idempotent, safe to re-apply).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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