From 733e85f7fbaef302d5cd28203324fb133a8f5b38 Mon Sep 17 00:00:00 2001 From: rock Date: Thu, 10 Sep 2026 09:06:06 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20migration=20009=20=E2=80=94=20temporal?= =?UTF-8?q?=20edge=20schema=20for=20production?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces old memory_edge (child_sha/parent_sha node graph) with temporal edge schema (Zep §2.2.2): - source_id, target_id, relation_type, fact - t_valid, t_invalid, t_created, t_expired (bi-temporal) - confidence, strength, weight - Idempotent (safe to re-run) - Old table preserved as memory_edge_legacy Applied to production CNPG cluster. Schema verified matching code. --- .../009_temporal_edge_migration.sql | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 crates/mem-store/migrations/009_temporal_edge_migration.sql diff --git a/crates/mem-store/migrations/009_temporal_edge_migration.sql b/crates/mem-store/migrations/009_temporal_edge_migration.sql new file mode 100644 index 0000000..4eeba2a --- /dev/null +++ b/crates/mem-store/migrations/009_temporal_edge_migration.sql @@ -0,0 +1,55 @@ +-- Migration 009: Temporal edge schema (Zep paper §2.2.2) +-- Replaces old memory_edge (child_sha/parent_sha node graph) +-- with temporal edge schema supporting relation types, facts, and validity periods. +-- Idempotent: safe to run multiple times. + +-- Rename old table if it still exists (skip if already migrated) +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'memory_edge' + AND EXISTS (SELECT 1 FROM information_schema.columns + WHERE table_name = 'memory_edge' AND column_name = 'child_sha')) + THEN + ALTER TABLE memory_edge RENAME TO memory_edge_legacy; + END IF; +END $$; + +-- Create temporal edge table +CREATE TABLE IF NOT EXISTS memory_edge ( + id TEXT PRIMARY KEY, + project_id TEXT NOT NULL DEFAULT 'default', + source_id TEXT NOT NULL, + target_id TEXT NOT NULL, + relation_type TEXT NOT NULL DEFAULT '', + fact TEXT NOT NULL DEFAULT '', + weight REAL NOT NULL DEFAULT 1.0, + strength REAL DEFAULT 1.0, + confidence REAL DEFAULT 0.8, + t_valid TIMESTAMPTZ, + t_invalid TIMESTAMPTZ, + t_created TIMESTAMPTZ NOT NULL DEFAULT NOW(), + t_expired TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + episode_id TEXT, + deleted_at TIMESTAMPTZ +); + +-- Ensure app user owns the table +DO $$ BEGIN + IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'app') THEN + ALTER TABLE memory_edge OWNER TO app; + END IF; +END $$; + +CREATE INDEX IF NOT EXISTS idx_memory_edge_source ON memory_edge(source_id); +CREATE INDEX IF NOT EXISTS idx_memory_edge_target ON memory_edge(target_id); +CREATE INDEX IF NOT EXISTS idx_memory_edge_project ON memory_edge(project_id); +CREATE INDEX IF NOT EXISTS idx_memory_edge_relation ON memory_edge(relation_type); + +-- Ensure memory_entity has deleted_at for BFS soft-delete queries +ALTER TABLE memory_entity ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMPTZ; + +-- ROLLBACK instructions: +-- DROP TABLE IF EXISTS memory_edge; +-- ALTER TABLE IF EXISTS memory_edge_legacy RENAME TO memory_edge;