- 迁移 0025_memory_ingest_reviews(幂等,既有部署重跑不炸/不丢行) - GC:保留期 720h + 条数上限 10 万行,挂进审查服务生命周期(Start 起 / Stop 停 / 启动先扫) - 过期即硬删(RevertMerged 只读 memory_items,删留痕不损失回滚能力) - 偏离一处并给理由:表只留 created_at(先例 0017;append-only;加 updated_at 需三份 DDL 真源) - 3 个变异自检(边界 <=/元组比较方向/Retention=0)
60 lines
3.6 KiB
SQL
60 lines
3.6 KiB
SQL
-- 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);
|