feat(memory): 记忆整理**应用路径 + 调度修复 + 手动真跑**(TIDY-1,主人投诉的根因)
主人实测:memory_items 1191 行、候选 77 条全 pending、memory_tidy_runs 仅 1 行、两晚定时没跑。 根因两条(都在这片里修掉): ① **以前根本没有执行面** —— 只有只读试算,候选永远 pending ② **调度被重启饿死** —— interval=24h 的 ticker 从进程启动算起,两天重启十几次 ⇒ 24h 永远走不完 - 应用路径:逐条 / 按 run 批量(默认 100、硬顶 500、超限 truncated)/ revert;**软合并** (status + merged_into/merged_from/merge_count,**绝不改 content、行不删**)+ 审计 (memory.tidy.apply / memory.tidy.revert)+ **幂等**(候选状态条件更新 + 行 status 闸两道) - 调度:改成**到点即跑**(catchUp:无历史+窗口内 / 距上次 run ≥ interval / 窗口起点晚于上次 run), 「上次 run」以 memory_tidy_runs 为**持久事实**;注入时钟用例证明**重启不饿死** - 手动真跑端点 POST /admin/memories/tidy/run(同档鉴权 + 审计 + 回执:新增/合并/软删/耗时) - 候选表加 run_id 列 + 索引(前滚;顺序=建表→补列→建索引,否则既有库会 no such column) - 3 个变异自检(删 catchUp / 去掉两道 status 闸 / truncated 恒 false) ⚠️ 生产库零动作:1191 行真跑与 77 条候选应用**未执行**(按红线由主人确认后主会话执行) ⚠️ 契约段在报告里(candidates 列表/apply/revert/tidy.run),Docs/ 待登记
This commit is contained in:
1 parent
57d0e8c543
commit
454ddb0b70
18 files changed
+3181
-71
No files matched your search
@@ -70,6 +70,17 @@ const (
|
||||
// minTidyContentRunes 是参与比对的最小内容长度(按 rune)。过短的内容
|
||||
// (如单字)没有可判定的事实要素,进比对只会产出噪声,直接跳过。
|
||||
minTidyContentRunes = 3
|
||||
|
||||
// defaultTidyApplyBatchLimit 是「批量应用候选」的单次条数上限(切片 TIDY-1)。
|
||||
// 它有上限是**刻意**的:一次点下去改几百条记忆是不可回头的观感,因此宁可
|
||||
// 让主人分批点,且回执如实带上 Total/Truncated(超限绝不静默少应用)。
|
||||
// 它是**代码默认值**(`.env` 已冻结、design/13 §2.1:新旋钮一律走
|
||||
// $DATA_DIR/config/** 或代码默认值),不新增任何 env 键。
|
||||
defaultTidyApplyBatchLimit = 100
|
||||
|
||||
// maxTidyApplyBatchLimit 是批量应用上限的硬顶:请求给更大的值就钳到这里
|
||||
// (与既有查询面「钳位而不是报错」同一约定)。
|
||||
maxTidyApplyBatchLimit = 500
|
||||
)
|
||||
|
||||
// TidyConfig 携带记忆整理的调优旋钮。零值经 normalize 选取安全默认值,
|
||||
@@ -173,3 +184,21 @@ func (c TidyConfig) nextQuietStart(at time.Time) time.Time {
|
||||
}
|
||||
return start
|
||||
}
|
||||
|
||||
// currentQuietStart 返回 at **所在**的低峰窗口起点(不晚于 at):
|
||||
// 落在窗口里(含跨午夜的半夜那一段)时是今天/昨天的 QuietStartHour 整点。
|
||||
// 窗口关闭时返回零值时间。
|
||||
//
|
||||
// 它服务**补跑判据**(切片 TIDY-1):判断「这个窗口是不是已经跑过」只需要
|
||||
// 「窗口起点 ≤ 上次 run」这一个比较,不必去构造「窗口内哪天」这种概念 ——
|
||||
// 跨午夜的窗口(23:00–07:00)用日期算会算错。
|
||||
func (c TidyConfig) currentQuietStart(at time.Time) time.Time {
|
||||
if c.quietWindowDisabled() {
|
||||
return time.Time{}
|
||||
}
|
||||
start := time.Date(at.Year(), at.Month(), at.Day(), c.QuietStartHour, 0, 0, 0, at.Location())
|
||||
if start.After(at) {
|
||||
start = start.AddDate(0, 0, -1)
|
||||
}
|
||||
return start
|
||||
}
|
||||
Reference in new issue
Block a user