主人 2026-10-07 两条口径:「.env 只做兜底用,后端自动创建独立的面板配置文件 之后就走面板配置文件,这些键优先从面板配置上取」+「频率必须调,可以调到 1 小时 或者三小时,或者动态分配(白天短、静默期长)」。 此前 $DATA_DIR/config/memory-tidy.json 只有读路径(装配期读一次 + 启动播种): 主人要改频率只能改文件 + 重启后端。本切片补上「读回来 → 改 → 落盘 → 当场生效」。 后端(读写端点,契约待塔登记 v0.92): - GET /api/v1/admin/memories/tidy/tuning 读盘上 7 键值 + 取值规则 specs + 缺位时 .env 档的进程生效值(与 /admin/config-facts 同源) - PUT 同路径:三态补丁(键缺位 = 不改动 / 合法值 = 采用 / 非法值 = 400 且盘上一 个字节都不动)+ null 清除哨兵(删键 ⇒ 回到下一档)+ writeAuth + 审计 memory.tidy.tuning;值一个都没变时不落盘,文件解不开时拒绝覆盖(409) - 落盘走 runtimeconfig.PatchMemoryTidyTuning(原子写 temp+rename,与 SeedMemoryTidy/SaveWebSearch 同族同手法);补丁语义保留下受管的其它键 (t1Judge/t1PerWindow/autoApplyPerRound 原样保留) - 热生效:保存后按「面板 > .env > 代码默认」重算并叠到运行期对象;整理档会 重排心跳(否则新周期要等旧周期那一觉睡完),审查档当场改 ingestGate/tempTtlSec。 未接线/失败时如实回 hot:false + hotError,绝不把「落盘了」说成「生效了」 前端(Miuix): - 记忆管理页新增「记忆整理调优」卡:7 键表单(中文标签、单位、留空⇒跟随谁、 env 档当前值、坏值就地报错并拦住保存、保存后回显从磁盘读回的真值) - 试算卡的 recallMode 按契约 v0.91 如实渲染:embedding / lexical(已降级)/ mixed(部分分区降级)/ ""(无候选可比)——空串不再渲染成空标签;并把 error.code=tidy_recall_unavailable 单列一句(「尝试过但向量源不可用」,与 「没有候选可比」显式区分) 验证:go test ./internal/{services/gateway,runtime/memory,config/runtimeconfig} 全绿;三态/清除/坏文件拒写/同值不重写/热生效接线各有用例,并逐条做过变异自证; tsc --noEmit + vite build 通过;两个 esbuild 前端测试 39 + 34 + 41 checks 通过。
主人要「现在就想看到在 736 条上它会建议合并哪些」,而不是等 23:00 的低峰首跑。 - 后端:Tidier.DryRun + TidyService.DryRun,**复用同一条扫描→召回→判定→构造候选路径**(抽出 tidyRoundPolicy,生产轮与试算轮只差「候选出口」与「召回降级策略」两处;禁止第二套实现) - 🔴 零副作用:不写 memory_tidy_candidates / memory_tidy_runs,绝不改 memory_items 任何列;机械证明 = 跑前跑后 cyrene.db 与 -wal 的 SHA256 一致(测试断言「表行数不变」) - 失败码诚实:500 tidy_unavailable / 409 tidy_disabled / 500 tidy_recall_unavailable(**embedding 不可用不降级成 0 条**)/ 503 tidy_timeout / 500 tidy_dry_run_failed;**空数组唯一含义 = 算过了没建议** - 端点 POST /api/v1/admin/memories/tidy/dry-run(writeAuth);面板「记忆」页加试算卡(点了才跑、无轮询、三态分开、明写「仅试算,不会改动任何记忆」) - 真机 e2e(741 条活库副本):76 ms / 15 分区 / 53 候选 / 41 skipped / 1 vetoed(low_confidence);样例 merge reason=fact_subset score=1.0000、link reason=similar_but_not_contained score=0.9248 - 变异:dry-run 顺手写库 ⇒ 两条测试红(行数 0→2);自造阈值 ⇒ 红;失败回 200 空数组 ⇒ 红 - 如实登记:Compared=688 被 400/分区护栏截断、候选上限 20/分区被打满 ⇒ 护栏值需在 741 条量级重定(非 bug)