根治三类工程治理问题(技术默认值≠产品规则、配置存在但未闭环、文档代码漂移): - 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
4.3 KiB
4.3 KiB
配置漂移审计 — config-drift-audit.md
版本:V1.0.1 配置与规则纠偏 · 日期:2026-09-20 判定原则:同一业务含义只允许一套 canonical key;不得出现「seed 写一套、真实系统读另一套」「前端写一套、后端又一套」「文档说一套、代码做一套」。
一、system_configs 是死表(0 个 Java 读取点)
V001__init_base_tables.sql:131建表,:213-217seed 了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(ymlmatch.*)+FeatureFlagConfig(features.*/feature_flag_overrides),不是system_configs。于是match_score_threshold='60'在死表里躺著,与活键match.default-score-threshold各写一份 → seed 与 migration 漂移、seed 与代码漂移。 - 处置:本轮删除
demo-seed-final.sql的死 keylivenessVerification.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 剩余硬编码为已登记的未来项。