Skip to content

Commit 6f5ec66

Browse files
committed
fix(knowledge): auto-maintain updated_at via trigger on all knowledge tables
Add a shared PostgreSQL trigger function (update_updated_at) wired to knowledge_sources, knowledge_items, and knowledge_propositions. Any UPDATE on these tables now automatically stamps updated_at = NOW() at the database level, removing the need for application code to manage this column.
1 parent ea2e8e8 commit 6f5ec66

2 files changed

Lines changed: 59 additions & 0 deletions

File tree

src/workflows_mcp/engine/knowledge/schema.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,49 @@
275275
WITH (m = 16, ef_construction = 64);
276276
""",
277277
),
278+
(
279+
6,
280+
"Add updated_at trigger to all knowledge tables that carry the column",
281+
"""
282+
CREATE OR REPLACE FUNCTION update_updated_at()
283+
RETURNS TRIGGER AS $$
284+
BEGIN
285+
NEW.updated_at = NOW();
286+
RETURN NEW;
287+
END;
288+
$$ LANGUAGE plpgsql;
289+
290+
DO $$
291+
BEGIN
292+
IF NOT EXISTS (
293+
SELECT 1 FROM pg_trigger
294+
WHERE tgname = 'trg_ks_updated_at'
295+
) THEN
296+
CREATE TRIGGER trg_ks_updated_at
297+
BEFORE UPDATE ON knowledge_sources
298+
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
299+
END IF;
300+
301+
IF NOT EXISTS (
302+
SELECT 1 FROM pg_trigger
303+
WHERE tgname = 'trg_ki_updated_at'
304+
) THEN
305+
CREATE TRIGGER trg_ki_updated_at
306+
BEFORE UPDATE ON knowledge_items
307+
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
308+
END IF;
309+
310+
IF NOT EXISTS (
311+
SELECT 1 FROM pg_trigger
312+
WHERE tgname = 'trg_kp_updated_at'
313+
) THEN
314+
CREATE TRIGGER trg_kp_updated_at
315+
BEFORE UPDATE ON knowledge_propositions
316+
FOR EACH ROW EXECUTE FUNCTION update_updated_at();
317+
END IF;
318+
END $$;
319+
""",
320+
),
278321
]
279322

280323
SCHEMA_VERSION = MIGRATIONS[-1][0] if MIGRATIONS else 0

tests/test_knowledge_executor.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,7 @@ def test_forget_update_sql_does_not_contain_updated_at(self) -> None:
882882
Some deployments omit updated_at from knowledge_propositions;
883883
unconditionally setting it causes 'column does not exist' errors.
884884
The only mutation needed is setting lifecycle_state = ARCHIVED.
885+
updated_at is maintained by the trg_kp_updated_at trigger (migration v6).
885886
"""
886887
import inspect
887888

@@ -892,6 +893,21 @@ def test_forget_update_sql_does_not_contain_updated_at(self) -> None:
892893
"_op_forget must not reference updated_at — not all schemas have that column"
893894
)
894895

896+
def test_migration_v6_adds_updated_at_trigger(self) -> None:
897+
"""Migration v6 must wire updated_at triggers on all three knowledge tables.
898+
899+
Regression guard for TASK-341: archive operations were leaving updated_at
900+
unchanged. One shared trigger function covers all tables that carry the column.
901+
"""
902+
v6 = next((m for m in MIGRATIONS if m[0] == 6), None)
903+
assert v6 is not None, "Migration v6 is missing from MIGRATIONS list"
904+
_, description, sql = v6
905+
assert "update_updated_at" in sql, "Migration v6 must create update_updated_at() function"
906+
assert "BEFORE UPDATE" in sql, "Trigger must fire BEFORE UPDATE"
907+
assert "trg_ks_updated_at" in sql, "Trigger missing for knowledge_sources"
908+
assert "trg_ki_updated_at" in sql, "Trigger missing for knowledge_items"
909+
assert "trg_kp_updated_at" in sql, "Trigger missing for knowledge_propositions"
910+
895911

896912
# ============================================================================
897913
# Recall Operation Tests

0 commit comments

Comments
 (0)