package memory import ( "log/slog" "time" "git.yeij.top/AskaEth/Cyrene_v2/internal/config/runtimeconfig" "git.yeij.top/AskaEth/Cyrene_v2/internal/logger" ) // 本文件是**入库前审查调优面**的解析点:把 `$DATA_DIR/config/memory-tidy.json` // 的面板旋钮叠到 ReviewConfig 上 —— 与 tidy_tuning.go 对 TidyConfig 做的事同源、 // 同一条口径(主人 2026-10-07:「**`.env` 只做兜底用** —— 后端自动创建独立的面板 // 配置文件之后就走面板配置文件,这些键优先从面板配置上取」)。 // // 为什么解析放在 memory 而不是 runtimeconfig:runtimeconfig 只负责**文件形状与 // 读取**(它的头注释把这条边界写死了),而「缺位/坏值怎么回落」属于 ReviewConfig // 的归一化语义 —— 与 normalizeReviewConfig 同一层,因此两者可以一起被单测覆盖。 // // 为什么不是「读盘时逐键容错」:整份文件解不开(含某键类型写错)时**全部键一起** // 回落,这是本文件家族既有的粒度(见 runtimeconfig.LoadMemoryTidyTuning 与它的 // 用例③);本文件处理的是**类型正确但值不可用**(非正数)那一档。 // ApplyReviewTuning 把面板调优旋钮叠到 ReviewConfig 上,返回叠加后的配置 // (**未归一化**:调用方随后交给 NewPreInsertReviewer / normalizeReviewConfig // 填代码默认值,与组合根对 TidyConfig 的既有顺序一致)。 // // 目前只有一键,逐键独立,三档优先级是: // // 键 面板(memory-tidy.json) 下一档(.env) 代码默认 // tempTtlSec tempTtlSec **无此键**(结构性为空) 604800(7 天) // // 🔴 **中档(`.env`)在结构上是空的**,这是**刻意**的、不是漏配:`.env` 已冻结 // (design/13 §2.1「不加、不改、不删」),而「多久算临时」是本次新增的能力, // 它在 `.env` 里**从来就没有键**。因此实际生效链是「面板 > 代码默认」——报回报时 // 不许把它写成「面板 > .env > 代码默认」而让读者以为 `.env` 那档还有东西可调。 // // 坏值(非正秒数)**绝不写进 cfg**:回落代码默认 + 记一条 WARN。一个 ≤0 的 TTL // 会让每条 defer 记忆**落库即过期**(读侧立刻隐藏、后台清扫下一轮就删)——那是 // 坏配置而不是「不过期」,但也不许因此让启动失败(design/03 §9.6)。 func ApplyReviewTuning(cfg ReviewConfig, panel runtimeconfig.MemoryTidyTuning, log *slog.Logger) ReviewConfig { log = logger.WithSource(baseTidyLog(log), "memory/review") if sec := panelPositiveTTLSec(panel.TempTtlSec, "tempTtlSec", log); sec > 0 { cfg.TempTTL = time.Duration(sec) * time.Second } return cfg } // panelPositiveTTLSec 解析**临时记忆 TTL** 旋钮,返回 0 表示「不覆盖」(调用方原样 // 留着上一档的值,最终由 normalizeReviewConfig 落到代码默认 7 天)。 // // 三种情形分得很清,因为它们该有不同的观测形状(与 tidy_tuning.go 的 // panelPositiveSec 逐字同构): // // - `nil`(键没写)⇒ 0,**静默**:没配不是错,正是「代码默认兜底」那一档; // - 非正数(写了 0 或负数)⇒ 0 + **WARN**:它会让每条临时记忆落库即过期 // (与「不过期」恰好相反),属于坏配置,必须留下痕迹; // - 正数 ⇒ 原值。 func panelPositiveTTLSec(v *int, key string, log *slog.Logger) int { if v == nil { return 0 } if *v <= 0 { log.Warn("memory-tidy.json 的临时记忆 TTL 不可用,回落代码默认(非正 TTL 会让临时记忆落库即过期)", "key", key, "value", *v, "fallback_sec", tempTtlSec) return 0 } return *v }