68d10658c7
Correctness fixes from docs/CORE_CORRECTNESS_ISSUES.md: - Issue 3 (HIGH, exploit): submit_sbc dedups owned_card_ids (HashSet) and bounds the list (MAX_SBC_CARDS=30) before resolution. A repeated id resolved the same card N times, passed validation, and granted the reward while only one card was consumed -> any SBC satisfiable with one duplicated card = free reward. Now rejected with BadRequest. Regression test added. - Issue 2 (HIGH): TOCTOU economy mutations closed with single-statement compare-and-swap (no transaction plumbing): club::spend_coins conditional debit (WHERE coins >= ?) + rows_affected, also rejects negative amounts; pack::open_pack claims the pack before minting; market::buy_listing claims the listing before charging and releases on debit failure; market::sell_card guards the DELETE with owner + rows_affected; checkin::claim uses a conditional INSERT ... WHERE NOT EXISTS (today) before paying out. - Issue 4 (LOW): season.rs .expect() on missing rows -> graceful AppError; checkin index (streak-1) % 7 -> .rem_euclid(7) (guards negative index panic). - Issue 1 (LOW): migration 0019 adds sbc_submissions.club_id + backfill; submit_sbc binds it so the MY CLUB milestone query stops silently reading 0. Core suite 179 green + clippy clean.
12 lines
656 B
SQL
12 lines
656 B
SQL
-- Issue 1: sbc_submissions was created (0001_initial.sql) without a club_id column,
|
|
-- but the MY CLUB milestone query (routes/club.rs get_milestones) counts
|
|
-- SELECT COUNT(*) FROM sbc_submissions WHERE club_id = ? AND passed = 1
|
|
-- so SQLite errored on the unknown column and the error was swallowed by
|
|
-- `.unwrap_or(0)` -> the `sbcs_completed` milestone always read 0. Add the column
|
|
-- and backfill it from the profile's club so historical submissions count.
|
|
ALTER TABLE sbc_submissions ADD COLUMN club_id TEXT;
|
|
|
|
UPDATE sbc_submissions
|
|
SET club_id = (SELECT c.id FROM clubs c WHERE c.profile_id = sbc_submissions.profile_id)
|
|
WHERE club_id IS NULL;
|