diff --git a/internal/services/gateway/admin_config_facts_test.go b/internal/services/gateway/admin_config_facts_test.go index de83ce0..0599d4f 100644 --- a/internal/services/gateway/admin_config_facts_test.go +++ b/internal/services/gateway/admin_config_facts_test.go @@ -309,9 +309,23 @@ func TestAdminConfigFacts_NeverLeaksSecretValues(t *testing.T) { } } -// TestAdminConfigFacts_KeysMatchEnvExample 是判据 ④:键名单的权威来源是 -// `.env.example` —— 13 个键必须逐字出现在模板里(键名写错一个字母,用户照面板 -// 抄去改就是静默不生效,AGENTS §10 的 E6 固定动作)。 +// envExampleExemptKeys 是**允许不出现在 `.env.example`** 的配置事实键,值 = 豁免理由。 +// +// 依据(主人 2026-10-06 红线):`.env` 冻结为「只保证最小化功能可跑」的**引导面**, +// **不再当作配置面** —— 调优/门槛/上限类旋钮**不进模板**(只有代码默认值;将来由 +// `$DATA_DIR/config/**` + 面板提供,见 `design/13 §2.1`)。因此「键必须在模板里」 +// 这条旧口径收窄为:「**在模板里,或在这里带理由显式豁免**」。 +// +// 🔴 这份清单是**封闭的**:新键要么进模板(确属最小化引导必需、且经主人批准), +// 要么必须在这里显式登记并写清理由 —— 否则本用例红。它守的东西没变: +// **不许有键悄悄漂移出去**(写错一个字母 ⇒ 用户照面板改就是静默不生效)。 +var envExampleExemptKeys = map[string]string{ + "MEMORY_TIDY_COMPARE_LIMIT": "调优旋钮(每分区两两比对上限);按冻结口径走 config/ 而不进 .env(design/13 §2.1)", +} + +// TestAdminConfigFacts_KeysMatchEnvExample 是判据 ④:键名单的权威来源是 `.env.example`。 +// 每个配置事实键必须**逐字出现在模板里**,或**在 envExampleExemptKeys 里带理由登记豁免** +// (口径 2026-10-06 由「必须在模板里」收窄为「在模板里 / 显式豁免」,原因见上)。 func TestAdminConfigFacts_KeysMatchEnvExample(t *testing.T) { t.Parallel() raw, err := os.ReadFile(filepath.Join("..", "..", "..", ".env.example")) @@ -320,8 +334,26 @@ func TestAdminConfigFacts_KeysMatchEnvExample(t *testing.T) { } template := string(raw) for _, spec := range configFactSpecs() { - if !strings.Contains(template, spec.key+"=") { - t.Fatalf(".env.example 里没有 %s= —— 事实表与模板漂移", spec.key) + if strings.Contains(template, spec.key+"=") { + continue + } + if why, ok := envExampleExemptKeys[spec.key]; ok && strings.TrimSpace(why) != "" { + continue + } + t.Fatalf(".env.example 里没有 %s= 且未登记豁免 —— 事实表与模板漂移", spec.key) + } + // 反向:豁免清单里不许留着「其实模板里有」或「根本不是事实键」的条目 + // (否则清单会变成垃圾桶,守卫随之失效)。 + keys := map[string]bool{} + for _, spec := range configFactSpecs() { + keys[spec.key] = true + } + for key := range envExampleExemptKeys { + if !keys[key] { + t.Fatalf("豁免清单里的 %q 不是配置事实键 —— 请删掉(清单只放事实键)", key) + } + if strings.Contains(template, key+"=") { + t.Fatalf("豁免清单里的 %q 其实已经在 .env.example 里 —— 请把它从清单删掉", key) } } }