-- Add a supersession pointer to entity_facts. -- -- Status alone is a one-way trapdoor: 'rejected' loses the link -- between the rejected fact and the one that replaced it. For -- evolving facts (Cameron's relationship, employer, address) the -- curator wants to *replace* a stale fact with a new one and keep -- the history readable: "from 2018 until 2022 this was true, then -- it became this other thing". -- -- A nullable INTEGER column pointing at another entity_facts.id — -- no FK constraint because SQLite can't ALTER ADD COLUMN with REFs; -- the DAO's delete_fact clears dangling pointers in the same -- transaction as the parent delete to keep the column honest. -- -- A status of 'superseded' on the old fact (alongside the existing -- active / reviewed / rejected) signals "replaced by a newer -- claim". Read paths already filter 'rejected' out of the active -- view; the curation UI will treat 'superseded' the same way for -- conflict detection so they don't keep flagging. -- -- Pairs with the valid-time columns from 2026-05-10-000100: the -- supersede action auto-stamps the old fact's `valid_until` from -- the new fact's `valid_from`, closing the interval cleanly. ALTER TABLE entity_facts ADD COLUMN superseded_by INTEGER; -- Helpful index for "show me what superseded this fact" walks -- (rare today; cheap to add now while the table is small). CREATE INDEX idx_entity_facts_superseded_by ON entity_facts(superseded_by) WHERE superseded_by IS NOT NULL;