Skip to content

Commit d6fa8ed

Browse files
committed
fix(schema): predecessor_memory_id ON DELETE CASCADE (review #4)
Hard-deletes (e.g. resetBySource in repository-write) silently nulled out predecessor_memory_id pointers, breaking backward chain traversal and leaving half-broken chains where some events still reference a deleted ancestor. Change the predecessor FK to ON DELETE CASCADE so the dependent chain node gets removed cleanly when its predecessor goes. Matches the memory_id FK policy on the same table. Schema migration runs an idempotent DROP CONSTRAINT / ADD CONSTRAINT in a DO block because CREATE TABLE IF NOT EXISTS won't update column-level FK definitions on an existing table.
1 parent 4020135 commit d6fa8ed

1 file changed

Lines changed: 23 additions & 1 deletion

File tree

src/db/schema.sql

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ CREATE TABLE IF NOT EXISTS temporal_linkage_list (
334334
user_id TEXT NOT NULL,
335335
entity_id UUID NOT NULL REFERENCES entities(id) ON DELETE CASCADE,
336336
memory_id UUID NOT NULL REFERENCES memories(id) ON DELETE CASCADE,
337-
predecessor_memory_id UUID DEFAULT NULL REFERENCES memories(id) ON DELETE SET NULL,
337+
predecessor_memory_id UUID DEFAULT NULL REFERENCES memories(id) ON DELETE CASCADE,
338338
observation_date TIMESTAMPTZ NOT NULL,
339339
position_in_chain INTEGER NOT NULL,
340340
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
@@ -353,6 +353,28 @@ CREATE INDEX IF NOT EXISTS idx_tll_memory
353353
CREATE UNIQUE INDEX IF NOT EXISTS idx_tll_chain_position_unique
354354
ON temporal_linkage_list (user_id, entity_id, position_in_chain);
355355

356+
-- Align predecessor FK with memory FK (CASCADE) so a hard-deleted memory
357+
-- removes the dependent chain node instead of leaving a half-broken
358+
-- predecessor pointer that breaks backward chain traversal. Idempotent:
359+
-- re-applying the constraint overwrites any prior ON DELETE SET NULL
360+
-- definition. Required for existing databases since the table-level
361+
-- CREATE TABLE IF NOT EXISTS above does not update column constraints.
362+
DO $$
363+
BEGIN
364+
IF EXISTS (
365+
SELECT 1 FROM information_schema.table_constraints
366+
WHERE table_name = 'temporal_linkage_list'
367+
AND constraint_name = 'temporal_linkage_list_predecessor_memory_id_fkey'
368+
) THEN
369+
ALTER TABLE temporal_linkage_list
370+
DROP CONSTRAINT temporal_linkage_list_predecessor_memory_id_fkey;
371+
END IF;
372+
ALTER TABLE temporal_linkage_list
373+
ADD CONSTRAINT temporal_linkage_list_predecessor_memory_id_fkey
374+
FOREIGN KEY (predecessor_memory_id) REFERENCES memories(id)
375+
ON DELETE CASCADE;
376+
END$$;
377+
356378
-- =====================================================================
357379
-- First-mention events (chronological topic-introduction list)
358380
-- =====================================================================

0 commit comments

Comments
 (0)