Review of PR 40: the name backfill at delete rewrote every job of the station
while holding the tenant's admission lock, and the changelog called the old
startup backfill a no-op where it nulled a queue name.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
deleteDevice decided "connected and printing" from a read without a lock,
revoked the station, and only then locked and read again. A revoked station
never counts as connected, so the locked read could not refuse: a station
that claimed a job between the first read and the revocation was deleted and
the job closed as OUTCOME_UNKNOWN although the station had its content.
The delete is now one transaction: tenant admission lock, then the station's
row lock (the lock a claim, a job event and a heartbeat take first), the
refusal, the REVOKE control on the same connection, the job closing and the
row deletes, one commit. A refused or failed delete changes nothing; the
station is no longer left revoked when the delete's transaction fails.
PrintingDeviceControls.action gains an overload that runs inside the
caller's transaction. deletePrinter already decided under the station's row
lock and is unchanged.
Also: the printer approval route returns "Printer was removed; share it from
the device again before changing its approval" again (RC.3 changed an HTTP
API text); the startup name backfill only updates jobs whose station or
printer still exists.
Tests: the claim that lands just before the delete locks (station, printer),
the claim in flight that the delete waits for, a printer refused on a live
station, an already revoked station, rollback and retry of a failed
transaction, the 23503 mapping, the final step refusing after the review,
review plan errors, and a tenant-scoped aggregate over print jobs.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>