Files
pad/internal
xarmian 48477f3b89 test(storage): force the copy/upload race so the storage lock's test can go red (TASK-3779) (#2135)
* test(storage): force the copy/upload race so the storage lock's test can go red (TASK-3779)

The 25-round race between a cross-workspace copy and an upload (BUG-3653)
passed with the storage advisory lock removed on Postgres: the long copy
and the short upload never overlapped inside the check-to-commit window.

testHookCopyAfterStorageCheck holds the copy after its storage check and
before its inserts, with the lock held. The upload starts in that window.
With the lock it waits for the copy to commit and is refused. Without it
(mutant on test-pg) it commits while the copy is held, and the test fails
naming that. Nil in production.

Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS

* test(storage): the forced race proves the upload reached the lock, and never strands a held copy (TASK-3779)

Codex round 1:
- The 500ms window could pass vacuously if the upload had not reached
  the lock yet. testHookAfterStorageOwnerRead is now armed once the copy
  is held, so it fires for the upload alone, just before it takes the
  lock, and the window starts there.
- A failure before release left the copy parked holding its locks.
  Cleanup now releases it once and joins the copy goroutine.

The test is Postgres-only: on SQLite the upload's BEGIN IMMEDIATE waits
behind the held copy's writer lock before reaching the advisory lock it
watches.

Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS

* test(storage): prove the upload waits on the advisory lock from pg_locks, and join it on cleanup (TASK-3779)

Codex round 2: the owner-read hook fires a few statements before the
lock wait, so it did not prove the upload was blocked on the lock. The
test now polls pg_locks for an ungranted advisory lock in its own
database while the copy is held: present with the lock, never present
without it (the upload then commits past the cap and the test fails).
Cleanup also joins the upload goroutine.

Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS

* test(storage): the waiter check matches the storage lock's own key (TASK-3779)

Codex round 3: any ungranted advisory lock in the database counted as
the upload's wait. The pg_locks query now matches objid to the low 32
bits of hashtext('pad:plan-limit:storage_bytes:' || owner), with
objsubid 1.

Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS

* test(storage): match the storage lock's classid as well as its objid (TASK-3779)

Codex round 4: objid alone is the low 32 bits of the key.

Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS
2026-10-13 16:54:44 -04:00
..