Files
VoiceStudio/tests
Palash Debnath b66b09ceaa fix(dub): deleting a dub no longer resurrects it (#1252, #1253) (#1270)
* fix(dub): deleting a dub no longer resurrects it (#1252, #1253)

Split out of #1264. The other six fixes there are independent error-message
changes that needed no corrections; this one is a concurrency change that
needed five rounds, each finding something real in work that looked finished
and tested:

  1. review: merge and save were split, so a delete between them had the row
     written straight back;
  2. review: dict membership cannot express 'withdrawn' — an absent key means
     'not written yet' for a new job and 'deleted' for an established one;
  3. fail-before check: the race test was not testing the race (it asserted
     WHAT happened, never WHEN, and 'save after delete' IS the resurrection);
  4. review: the gate sat in two ingest helpers while eight direct save_job
     call sites bypassed it;
  5. direct check of the reported scenario: the tombstone covered in-flight
     ingests only, so a delete during a RENDER — the common case — still
     resurrected the job.

Riding a release on that record is not a good trade, so it ships on its own.

What it does now: the withdrawal is recorded when a job is DELETED, held in a
bounded LRU (there is no moment at which a delete stops mattering), and checked
inside save_job so every caller inherits it. Re-importing an id is the only
thing that revives it. The lock is re-entrant because the atomic helpers call
save_job while holding it.

Carries #1252's message half too: str(KeyError) is the repr of the key, which
is how the user's own job id became the entire error text.

* fix(dub): expire withdrawal markers by age, not by count

Greptile P1 — the sixth real finding on this fix, and reachable by ordinary
use. DELETE /dub/history selects every row with no limit, so a user with a
large history clearing it mid-render pushed that very job's marker out of a
count-bounded LRU, and the render then wrote it straight back.

Age is the honest policy: what matters is how long ago the delete happened, not
how many others followed it. Six hours outlives any realistic render or
transcribe. The count cap stays only as a memory backstop, raised far above any
real history and documented as such.

Verified fail-before: restoring count-based eviction fails both new tests.

* docs(changelog): the dub delete-resurrection fix (#1252, #1253)
2026-07-26 14:25:32 -07:00
..