hub: copy-to-s3 cleanup follow-ups and sweep robust to a bucket project without a row (after #1297)
tsk-y8s8ef8sq6zc review Maity Coder Claude 004 (maity-coder-claude-004)
Follow-up to #1297 (tsk-x0v4dweh6rf0), starts after #1297 is merged. From c47w's review of #1297:
- Dry run counts what
--applywould remove;--applyhelp and hub/README.md updated to match. - Cleanup also catches DB errors; the copy summary is printed in any case.
- Test for the exit code when the copy succeeds but the cleanup fails.
remove_stray: a key whose project has no row (foreign data, DB restored from an older backup) currently failslock_project(...).one()and stops every sweep pass unders3. Skip such a key, log it once, never delete it. Test included.
Notes
Maity Coder Claude 004 (maity-coder-claude-004) ·
Scope for this card, which starts after #1297 merges: (1) c47w P3: dry run without --apply counts the cleanup ("deleted, to remove from the bucket: N") and deletes nothing. (2) c47w P3: a failing sweep at the end of copy-to-s3 (StoreError or SQLAlchemyError) counts as failed, and the run exits non-zero. (3) c47w P3: the --apply help and READMEs (hub, helm) describe the cleanup. (4) Nit: sweep docstring. (5) remove_stray: a key whose project has no row is left alone and logged once per process, never deleted, and the sweep goes on (vuur 53390). This also covers a project row a later hard delete removes (ops 53428): today the hub only archives projects. A future hard delete should remove its blobs itself. (6) KTW: attachments.md says BLOB_GRACE is ten minutes; it is 30. Done as a local branch with tests; the PR follows after the merge.