feedBack/lib/routers
Byron Gamatos 4fd0cd49e7
fix(loops): take the DB lock for the count+insert and the list read (#840)
Two pre-existing races in the loops routes, flagged by CodeRabbit on #839 (the
verbatim extraction moved them unchanged from server.py, so they correctly
weren't fixed there):

1. save_loop computed `COUNT(*)` OUTSIDE meta_db._lock, then inserted inside it.
   Two simultaneous unnamed POSTs read the same count and both mint "Loop N".
   Fix: one lock scope around COUNT + INSERT.
2. list_loops read the shared single connection (check_same_thread=False) with
   no lock, so it could overlap a POST/DELETE commit. Fix: read under the lock,
   like every writer.

Low severity in context — FeedBack is single-user (Principle I), so concurrent
unnamed-loop POSTs essentially can't happen — but each fix is one lock scope.

tests/test_loops_concurrency.py pins both with a threading.Barrier that releases
16 workers into save_loop at once. Negative-checked: reverting the COUNT back
outside the lock fails the uniqueness assertion 5/5 runs; the fix passes 3/3.
pytest 2400 passed; on-device two unnamed POSTs -> ['Loop 1','Loop 2'].

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-10 19:16:01 +02:00
..
__init__.py fix(build): move appstate.py + routers/ under lib/ so the desktop app ships them (#836) 2026-07-10 17:16:34 +02:00
artist_aliases.py refactor(server): extract the artist-alias routes into routers/artist_aliases.py (R3) (#838) 2026-07-10 18:55:03 +02:00
audio_effects.py fix(build): move appstate.py + routers/ under lib/ so the desktop app ships them (#836) 2026-07-10 17:16:34 +02:00
loops.py fix(loops): take the DB lock for the count+insert and the list read (#840) 2026-07-10 19:16:01 +02:00