Files
danyang-match/docs/governance/config-drift-audit.md
T
WorkBuddy 438b38d121 V1.0.1 配置与规则纠偏:照片上限配置化+强校验 / 活体开关闭环 / 推荐阈值快照+规则版本化 / governance 三表+漂移审计
根治三类工程治理问题(技术默认值≠产品规则、配置存在但未闭环、文档代码漂移):
- PROFILE-001:profile.photo.maxCount(默认6未确认)+ ProfilePolicy + 服务器端 FOR UPDATE
  并发强校验(PHOTO_LIMIT_EXCEEDED,拒绝先于 S3 不留孤儿)+ 前端 mergeAppConfig 嵌套键修复
- CFG-001/IDENTITY-001:IdentityPolicy + GET /verification/liveness-status 真实判定点
  (默认关不阻断,开则 enhancedVerified 变化,消除假开关)+ 删死 seed livenessVerification.enabled
- MATCH-001:阈值60定为技术默认(消解 PENDING 矛盾)+ V050 recommendation_records.threshold_snapshot
  规则版本化 + 删死重复配置类 MatchConfig
- DOC-001:新增 docs/governance/(config-register/open-questions/decision-register/
  hardcoded-rule-audit/config-drift-audit)
- TEST-001:新增守卫 PhotoLimitGuardTest(8)/IdentityLivenessGuardTest(5)/
  RecommendationThresholdSnapshotGuardTest(4),均经负向注入可红

全量回归 733/0/0/3(基线717+17新增-1删死测试);UI 契约门禁 18/18;STATUS 升 rc.21
2026-09-21 02:05:15 +08:00

4.3 KiB
Raw Permalink Blame History

配置漂移审计 — config-drift-audit.md

版本:V1.0.1 配置与规则纠偏 · 日期:2026-09-20 判定原则:同一业务含义只允许一套 canonical key;不得出现「seed 写一套、真实系统读另一套」「前端写一套、后端又一套」「文档说一套、代码做一套」。


一、system_configs 是死表(0 个 Java 读取点)

  • V001__init_base_tables.sql:131 建表,:213-217 seed 了 match_rule_version / daily_recommendation_limit / match_score_threshold='60' / recommendation_cooldown_days。
  • demo-seed-final.sql 又 seed 一批 flag 名(localEligibility.evidencePolicy、counseling.enabled、premarital.enabled、serviceLocation.enabled、content.enabled、localEligibility.enabled、banner.maxActiveCount)。
  • 全仓 backend/src/main/java 无任何 SystemConfig 实体 / Mapper / 读取(仅 EntityMigrationParityTest 把它列入 H2 白名单)。
  • 后果:真实系统读的是 MatchRuleConfigProperties(yml match.*)+ FeatureFlagConfig(features.* / feature_flag_overrides),不是 system_configs。于是 match_score_threshold='60' 在死表里躺著,与活键 match.default-score-threshold 各写一份 → seed 与 migration 漂移、seed 与代码漂移。
  • 处置:本轮删除 demo-seed-final.sql 的死 key livenessVerification.enabled(与活键 livenessEnabled 同义双 key)。其余 system_configs 死行未删(表整体退役需单独迁移裁定,避免越界)——登记为未来项:整体退役 system_configs 或把它接成真实配置源。

二、match_rule_configs 是未接线的规则版本化雏形(死表)

  • V006 建 match_rule_configs(version/status/10 权重/minimum_score DEFAULT 60),MatchRuleConfigMapper.findActive/findByVersion 无任何调用方。
  • 真实规则版本化本轮走轻量路线:recommendation_records.rule_version + 新列 threshold_snapshot(V050)+ match.rule-version。
  • 处置:登记为未来项 —— 要么把 match_rule_configs 接成「规则版本唯一读取源」(配合 open-questions 的 10 维权重配置化),要么删除该死表。本轮未动(避免越界)。

三、本轮已消除的 key/类漂移

漂移 处置
seed livenessVerification.enabled vs 活键 livenessEnabled(双 key 同义) 已删 seed 行;canonical identity.liveness.enabled 映射到唯一实现键 livenessEnabled(见 config-register)。
shared/config/MatchConfig 与 match/config/MatchRuleConfigProperties 同前缀 match 双 bean(前者 0 业务引用) 已删死类 MatchConfig,统一读 MatchRuleConfigProperties。
前端 mergeAppConfig 平铺合并 → 服务端嵌套 businessLimits.maxProfilePhotos 等从不生效(前端 6 写死、后端也不强校验) 已修前端显式节-键映射 + 后端 ProfilePolicy 强校验 + /app/config 读 ProfilePolicy。前后端现共用同一配置源。
活体开关「假开关」(livenessEnabled 无业务强制点,0 读取点) 已建 IdentityPolicy + GET /verification/liveness-status 真实判定点,开关开则 enhancedVerified 变化(FF-LIVENESS-002)。

四、剩余待登记漂移(未来项,勿本轮扩大)

项 说明
AppController 剩余硬编码(dailyRecommendationLimit / maxInterestTags / selfIntroMaxLength / recommendationCooldownDays / reviewConfig / features) 与 MatchRuleConfigProperties / 各配置源各写一份;待统一为「读配置源 + 经 /app/config 下发」(见 hardcoded-rule-audit 第二节)。
前端 BUSINESS_LIMITS 本地默认值 vs 服务端 maxProfilePhotos 已打通;DAILY_RECOMMENDATION_LIMIT / MAX_INTEREST_TAGS 等仍为本地 fallback,服务端值经 /app/config 下发后应全部以服务端为准(前端只作失败兜底)。
打分公式占位(0.6/0.4、80/60、恒 50.0) 非漂移,属 V1 占位未产品化;正式化时随规则版本一起配置化。

结论:本轮消除了文档点名的 4 类漂移(liveness 双 key、MatchConfig 重复、前后端照片上限失同步、活体假开关)。 system_configs 死表、match_rule_configs 死表、AppController 剩余硬编码为已登记的未来项。