package memory import ( "git.yeij.top/AskaEth/Cyrene_v2/internal/config/runtimeconfig" ) // 本文件是「启动播种」的**值来源**:把 `$DATA_DIR/config/memory-tidy.json` 十一键的 // **当前生效值**拍成一份完整快照,交给 runtimeconfig.SeedMemoryTidy 落盘。 // // 它回应主人 2026-10-07 的两条口径: // // - 「**`.env` 只做兜底用** —— 后端**自动创建**独立的面板配置文件之后就走面板 // 配置文件,这些键优先从面板配置上取」⇒ 播种的时机与「此后以面板为准」; // - 「后端**自动创建**独立的面板配置文件**要做**」⇒ 这份快照就是「自动创建」的 // 内容,**零新 env 键**(`.env` 已冻结,design/13 §2.1)。 // // 为什么放在 memory 而不是 runtimeconfig:runtimeconfig 只管**文件形状与读写**, // 「缺位/坏值怎么回落、默认值是多少」属于 TidyConfig / ReviewConfig 的归一化语义 // (与 normalizeTidyConfig / normalizeReviewConfig 同一层)。 // // 为什么快照取**归一化之后**的值:主人要的是「播种那一刻行为零变化」——把当时真正 // 生效的值写成文件,读回来叠上去之后(面板这一档等于生效值本身)结果逐字相同。 // 若快照取的是「未归一化的中间值」(比如四键还是 0),写下去的就是一份**比现状更空** // 的配置,只是侥幸等价;取归一化后的值,等价性才是结构性的(见 // TestTidyTuningSnapshot_PanelRoundTripKeepsEffectiveConfig)。 // // 为什么只有一处实现:十一键的默认值在 memory 侧各只有一处定义 // (tidy_config.go / preinsert_config.go 的 default* 常量),快照直接复用那两个 // normalize,**不另写一份默认值** —— 否则播种写下去的就是第二份「差不多」的默认值, // 会与运行期悄悄分叉。 // // 十一键与它们的生效来源: // // 键 生效来源(无面板文件时) 快照值 // autoApply DisableAutoApply 的反向(代码默认开) true // autoApplyPerRound defaultTidyAutoApplyPerRound 50 // ingestGate DisableIngestGate 的反向(默认开) true // t1Judge DisableT1 的反向(默认开) true // t1PerWindow defaultT1PerWindow 120 // t1WindowSec defaultT1Window 3600 // tempTtlSec ReviewConfig.TempTTL(默认 7 天 = 604800) 归一化值 // intervalSec TidyConfig.IntervalSec(env 或 86400) 归一化值 // quietIntervalSec 缺省 = intervalSec 归一化值 // quietStartHour TidyConfig.QuietStartHour(env 或 23) 归一化值 // quietEndHour TidyConfig.QuietEndHour(env 或 7) 归一化值 // TidyTuningSnapshot 拍下十一键的**当前生效值**,返回一份可直接落盘的面板快照。 // // 入参是**已经叠过面板层的**两个配置(组合根的次序:TidyConfigFromConfig → // ApplyTidyScheduleTuning → 本函数;审查侧同理),本函数只做最后一步归一化并翻成 // 文件形状 —— 它不读盘、不读 env、不认识面板文件: // // - tidy 侧四键(intervalSec / quietIntervalSec / quietStartHour / quietEndHour) // 与自动档两键(autoApply / autoApplyPerRound); // - review 侧五键(ingestGate / t1Judge / t1PerWindow / t1WindowSec / // tempTtlSec):这五项在 `.env` 里**没有出处**(`.env` 已冻结),只由面板文件 // 与代码默认决定,而播种只发生在**面板文件不存在**时 —— 那正是「零值 + // normalizeReviewConfig」这一条路径,与运行期(wireMemoryReview 的四个 helper) // 逐字一致。 // // 两个开关是**反向**字段(DisableX),快照要把它们翻回正向的 JSON 键:文件里的 // `"autoApply": true` 才是「没配时到底开不开」的如实陈述。 func TidyTuningSnapshot(tidy TidyConfig, review ReviewConfig) runtimeconfig.MemoryTidyTuning { tidy = normalizeTidyConfig(tidy) review = normalizeReviewConfig(review) autoApply := !tidy.DisableAutoApply ingestGate := !review.DisableIngestGate t1Judge := !review.DisableT1 intervalSec := tidy.IntervalSec quietIntervalSec := tidy.QuietIntervalSec quietStartHour := tidy.QuietStartHour quietEndHour := tidy.QuietEndHour // 临时记忆 TTL(design/03 §9.6):normalize 之后恒为正(7 天 = 604800), // 因此快照写下去的**必然是有效值**,不会播出一份自己读回都要 WARN 的配置。 tempTtlSec := int(review.TempTTL.Seconds()) return runtimeconfig.MemoryTidyTuning{ AutoApply: &autoApply, AutoApplyPerRound: tidy.AutoApplyPerRound, IngestGate: &ingestGate, T1Judge: &t1Judge, T1PerWindow: review.T1PerWindow, T1WindowSec: int(review.T1Window.Seconds()), TempTtlSec: &tempTtlSec, IntervalSec: &intervalSec, QuietIntervalSec: &quietIntervalSec, QuietStartHour: &quietStartHour, QuietEndHour: &quietEndHour, } }