Review: feat: custom even-money wager amounts ($1-$500)
Verdict: APPROVED
Re-review after refinement. All 6 findings from
review-841-2026-04-05 have been addressed. Scope is solid, file targets verified, traceability complete.Template Completeness
- [x] Type — Feature
- [x] Lineage — Phase 1 of #44 (custom wager amounts)
- [x] Repo — forgejo_admin/twitch-2k-wager
- [x] User Story — challenger wants custom wager amount instead of fixed tiers
- [x] Context — clear motivation, even-money constraint stated, fixed presets remain
- [x] File Targets — 7 files listed with specific change descriptions
- [x] Acceptance Criteria — 7 testable criteria
- [x] Test Expectations — 4 test cases with specific dollar values and expected behavior
- [x] Constraints — 5 constraints including Stripe minimum, $500 max, which CHECK to preserve
- [x] Checklist — standard 3 items
- [x] Related — parent issue #44, story note, arch note all referenced
Traceability
- [x] story:challenger-pay — "Secure Buy-In Payment" (
story-twitch-2k-wager-challenger-payexists in pal-e-docs) - [x] story note verified — found in
project-twitch-2k-wageruser-stories table (key: challenger-pay) - [x] arch:domain-twitch-2k-wager — "Domain Model: Twitch 2K Wager" (
arch-domain-twitch-2k-wagerexists in pal-e-docs) - [x] arch note verified — architecture note, active status, documents Game entity with buy_in_amount field
- [x] Forgejo issue — forgejo_admin/twitch-2k-wager#64, open
File Targets
- [x]
src/routes/play/+page.svelte— verified: has tier pills (lines 59-70), needs "Custom" option added alongside existing presets - [x]
src/lib/stripe.ts— verified: hasTIERSlookup (line 31-36),VALID_TIERS(line 45),createCheckoutSessionrequiresTierDollarstype (line 56). All need widening for custom amounts. - [x]
src/lib/schema.sql— verified: line 28 hasCHECK (buy_in_amount IN (100, 1500, 3000, 4500))to REMOVE. Line 30 hasCHECK (pot_amount = buy_in_amount * 2)to PRESERVE. Ticket correctly distinguishes between the two. - [x]
src/lib/types.ts— verified: line 24 hasexport type BuyInAmount = 100 | 1500 | 3000 | 4500;— needs widening tonumberwith runtime validation - [x]
src/lib/db.ts— verified: line 132 hasbuyInAmount: Game['buy_in_amount']derived fromBuyInAmountunion type. Coupled to enum; needs updating when type widens. - [x]
src/routes/api/checkout/+server.ts— verified: validates viaVALID_TIERS.includes()(line 45), casts throughTIERS[tierDollars].amount(line 72). Needs range validation ($1-$500) instead of tier lookup. - [x]
src/routes/api/webhooks/stripe/+server.ts— verified: line 111 readssession.metadata?.tierfor logging.handleCheckoutCompletedreadsgame_idfrom metadata (line 73) which is tier-agnostic. Ticket correctly uses "evaluate if" language for this target.
Repo Placement
OK. All 7 files are in
forgejo_admin/twitch-2k-wager. Issue is filed on the same repo. Single-repo change, no cross-repo concerns.Dependencies
- [x] No blocking dependencies. Parent #44 is a tracking issue (Phase 1 + Phase 2), not a blocker.
- [x] Board item #832 (winner payout, #60) — independent, touches
arch:dataflow-twitch-2k-wager, no file overlap. - [x] Board item #842 (#65, asymmetric odds) — Phase 2 of #44, sequenced after this ticket. No conflict.
- [x] Production DB migration — removing CHECK constraint requires ALTER TABLE on live DB. Standard practice for this project. Not a code dependency.
Acceptance Criteria
All 7 AC are agent-verifiable:
- [x] AC 1 ("Custom" option on /play) — verifiable via DOM inspection or screenshot
- [x] AC 2 (any $1-$500 creates valid session) — verifiable via checkout API POST with custom amount
- [x] AC 3 (pot always 2x) — verifiable via DB query after checkout, pot_amount CHECK constraint preserved in schema
- [x] AC 4 (fixed presets still work) — verifiable via existing tier checkout tests
- [x] AC 5 (admin shows custom amounts) — admin
tierLabel()already returns${cents/100}for non-standard amounts; safe - [x] AC 6 (input validation) — verifiable via API: reject decimals, amounts below $1 or above $500
- [x] AC 7 (webhook processes custom amounts) — verifiable via webhook test with custom amount metadata
Blast Radius
- Admin page (
src/routes/admin/+page.svelte):tierLabel()already has fallback for non-standard amounts (${cents/100}).tierClass()returns empty string — no color badge for custom. Acceptable, not a blocker. - Game detail page (
src/routes/game/[id]/+page.svelte):getTierLabel()already returns'Custom'for default case. Safe. - Landing page (
src/routes/+page.svelte): has hardcoded tier cards (lines 97-185). Display-only, not a checkout entry point. Not affected. - Existing tests: 3 test suites reference fixed tiers (
checkout.test.ts,stripe.test.ts,db.test.ts). Will need updating, implied by AC "Tests pass." - DB migration: removing CHECK constraint on live table requires
ALTER TABLE game DROP CONSTRAINT. Schema.sql is truth for new deploys; ALTER needed for production. - Rollback: straightforward — re-add the CHECK constraint, revert type changes. Custom-amount games already in DB would violate the constraint, so rollback would need to handle or exclude them.
Decomposition Assessment
7 file targets in 1 repo. 7 AC. 4 test expectations. Borderline on the three-thing limit by raw count, but the changes form a single tightly-coupled dependency chain:
types.ts (widen type) → db.ts (accept new type) → schema.sql (drop CHECK) → stripe.ts (accept any amount) → checkout/+server.ts (range validation) → play/+page.svelte (Custom UI) + webhooks/stripe/+server.ts (evaluate metadata)Splitting this chain would create integration risk — each piece is meaningless without the others. Estimated agent time: 3-5 minutes. No decomposition needed.
Recommendation
No action needed. Ticket is ready for dispatch.
Refinement Verification (6/6 addressed)
- [x] Project page —
project-twitch-2k-wagernow exists in pal-e-docs - [x] Architecture notes —
arch-domain-twitch-2k-wagerexists in pal-e-docs - [x] Label mismatch — board label corrected to
arch:domain-twitch-2k-wager - [x] Missing db.ts target — added to File Targets with createGame type coupling description
- [x] CHECK constraint clarity — issue explicitly distinguishes which CHECK to remove vs preserve
- [x] Webhook handler — added to File Targets with "evaluate if" language