Files
Cyrene_v2/internal/db/migrations/0025_memory_ingest_reviews.up.sql
AskaEth ffe2518bf4
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
feat(memory): 留痕表正式迁移 0025 + 保留期清扫(W5)
- 迁移 0025_memory_ingest_reviews(幂等,既有部署重跑不炸/不丢行)
- GC:保留期 720h + 条数上限 10 万行,挂进审查服务生命周期(Start 起 / Stop 停 / 启动先扫)
- 过期即硬删(RevertMerged 只读 memory_items,删留痕不损失回滚能力)
- 偏离一处并给理由:表只留 created_at(先例 0017;append-only;加 updated_at 需三份 DDL 真源)
- 3 个变异自检(边界 <=/元组比较方向/Retention=0)
2026-10-06 15:59:16 +08:00

60 lines
3.6 KiB
SQL
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- 0025_memory_ingest_reviews: 入库前审查(design/23 §15.1 D3)留痕表的**正式迁移号**
-- (切片 W5;D3 本体已落地于 6e28b38,当时**刻意没占迁移号**,以免与并行切片抢号)。
--
-- 为什么现在补:本表此前**只**由 `memory.NewStore` 的幂等前滚创建
-- (internal/runtime/memory/preinsert_schema.go)。后果是「库里有这张表」这件事
-- 分裂成两份真源:新库靠自举、迁移账本却不知道它存在;而清理(保留期清扫)要按
-- `created_at` 扫表 —— 一个不在迁移账本里的表,没人能回答「它的形状是谁负责的」。
-- 本迁移把它登记进 schema_migrations(手法照 0019_memory_tidy 对 memory_items
-- 整理列 / 候选表 / 运行表的处理)。
--
-- 🔴 **幂等是硬要求**(本迁移的部署面比一般迁移宽):**所有既有部署的
-- `memory_ingest_reviews` 早已存在**(NewStore 自举),只是没有 0025 这一行。
-- 因此 DDL 一律 `IF NOT EXISTS`:重复执行 = 空操作,绝不因为「表已存在」而炸,
-- 也不会因为「表已存在」而漏建索引。形状必须与自举 DDL **逐字同形**(少一列就是
-- 「新库有、老库无」的漂移),由 `internal/runtime/memory/preinsert_migration_test.go`
-- 的对照测试钉住(迁移建的表 vs 自举建的表,列与索引逐项比对)。
--
-- 命名口径:表名复数、主键 `id`、索引 `idx_{table}_{col}`(援引 AGENTS §10 已登记例外,
-- 与既有迁移一致)。
--
-- 时间戳:**只有 created_at**(定宽 UTC 纳秒串,由 internal/runtime/memory.formatTime
-- 写入;见该包 timefmt.go 的口径)。本表是 **append-only**:留痕落一行即不再改写,
-- 因此按同类逐条样本表 `0017_llm_usage` 的先例**不引入 updated_at** —— 一个永远等于
-- created_at 的列只会撒谎,而且要补它就必须为既有部署再加一条幂等 ALTER,
-- 把 DDL 的两份真源变成三份。若将来真出现「留痕被后续动作改写」的需求,
-- 那是 shape 变更,按项目惯例开新迁移号。
--
-- 脱敏(design/23 §15 D3-8「记忆正文不进日志」延伸到表结构):本表**没有**承载
-- 记忆正文的列 —— 命中的既有 id(target_id / merged_ids)足以让 owner-only 的
-- 读侧回表取原文,而正文一个字都不进这张表。
CREATE TABLE IF NOT EXISTS memory_ingest_reviews (
id TEXT PRIMARY KEY,
item_id TEXT NOT NULL,
persona_id TEXT NOT NULL,
scope TEXT NOT NULL,
project_id TEXT NOT NULL DEFAULT '',
decision TEXT NOT NULL,
reason TEXT NOT NULL DEFAULT '',
veto TEXT NOT NULL DEFAULT '',
target_id TEXT NOT NULL DEFAULT '',
merged_ids TEXT NOT NULL DEFAULT '[]',
score REAL NOT NULL DEFAULT 0,
recall_mode TEXT NOT NULL DEFAULT '',
degraded INTEGER NOT NULL DEFAULT 0,
rule_version TEXT NOT NULL DEFAULT '',
session_id TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL
);
-- 按被审条目回溯(「这一条记忆当初被谁合了」)。
CREATE INDEX IF NOT EXISTS idx_memory_ingest_reviews_item_id
ON memory_ingest_reviews (item_id);
-- 读侧倒序(ListIngestReviews)与**保留期清扫的唯一依赖**:批删语句带
-- `WHERE created_at < ? ORDER BY created_at LIMIT ?`,吃得上这条索引,
-- 且每批的扫描面有界(internal/runtime/memory/preinsert_gc.go)。
CREATE INDEX IF NOT EXISTS idx_memory_ingest_reviews_created_at
ON memory_ingest_reviews (created_at);