fix(deletion): preserve a second leaver's note instead of deleting it (#412) #461
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/412-deletion-collisions"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #412 (LOW).
The defect
Account deletion repoints uniqueness-constrained history onto a single "Deleted user" tombstone. A row that would collide with one the tombstone already owns cannot be repointed — the constraint forbids two rows for one user — and the collision was resolved by deleting the incoming row.
It never fires within a single deletion, because the tombstone owns nothing yet. It fires across repeated deletions, which is precisely when nobody is watching: two GMs leave the group months apart, and the second one's public note vanishes rather than being tombstoned like everyone else's. The campaign's record loses one person's writing in a way indistinguishable from it never having been written.
What ships
Notes merge. The colliding text is appended to the tombstone's existing row, separated by a rule so a reader can see two people wrote it — without naming either, since both accounts are gone. A blank note contributes nothing and leaves no dangling separator.
Votes, attendance and lore ownership still drop, and that is now a stated decision rather than an incidental one. Merging is not meaningful for them: one vote per person is the entire point of the constraint, attendance is a single yes/no, and an ownership link is not additive. With exactly one tombstone, two anonymised people genuinely cannot both be represented — a real limit of the model, not an oversight. So the loss is counted and carried into the existing
user.deletedaudit entry rather than happening silently. That is the second acceptance criterion.The mutation run caught a flaw in my own code
The first version returned "collisions handled" as the count. Running the mutant — merge disabled, everything dropped — only one test failed, because that number was identical whether the text was merged or destroyed. The count was reporting something it had not checked, which in an audit entry is worse than reporting nothing.
It now reports loss specifically: a merged note is not lost, a blank one is not lost, and a dropped vote is. Against the same mutant, both merge tests now fail.
Verification
test_a_second_leavers_note_is_kept_not_deletedandtest_a_merged_note_is_not_counted_as_lostboth fail.1,488 backend tests pass (was 1,482). Lint clean at pinned ruff 0.4.4.
🤖 Generated with Claude Code