721546b140
Tombstone files under tombstones/id/<id>.json and tombstones/addr/ <kind>/<pubkey>/<sha256(d)>.json, each a hardlink to the kind-5 event that authored the deletion. One source of truth: the tombstone IS the deletion event, just indexed by target. - FsTombstones — installs id tombstones unconditionally, installs addr tombstones with strongest-cutoff-wins semantics (later kind-5 replaces earlier via atomic rename), and exposes hasIdTombstone / addrTombstoneCutoff for pre-insert checks. - FsEventStore.insert — pre-insert guard: id tombstone always blocks; addr tombstone blocks when event.createdAt <= tomb.createdAt, matching SQLite's reject_deleted_events trigger. Kind-5 inserts trigger a cascade: for each e-tag target owned by the deletion author, unlink indexes + slot + canonical; for each a-tag (same pubkey), evict the slot winner if its createdAt <= deletion.createdAt. Tombstones are installed for every target regardless, so future re-inserts are blocked. Tests: 11 new in FsDeletionTest — delete-by-id, block-reinsert-by-id, non-author-deletion still installs tombstone but no cascade, cascade addressable slot, newer-at-deleted-address passes, older blocked, equal-timestamp blocked, later kind-5 raises cutoff, earlier kind-5 does not lower, deletion event stays queryable, tombstone shares inode with kind-5 canonical. 51 fs tests green.