KEEP-VERIFY re-audit of the Feature Flag configuration extension (STATUS's
"Phase 22 部署运维配置扩展"): marked ✅ but contained real code defects and
overstated completion.
Real defects fixed:
- D-22-A (High): FeatureFlagController.updateFlag used reflection
`getMethod("set"+cap, boolean.class)` and only supported boolean flags.
7 non-boolean flags (livenessProvider, localEvidenceAllowedTypes,
counselingAttachmentsBucket, localEvidenceMaxFiles, localEvidenceMaxFileSizeMB,
localEvidenceRetentionDays) failed to update via the API. Now dispatches by
field type (boolean/int/String).
- D-22-B (Medium): `body.getOrDefault("value", false)` silently set false when
value was missing and crashed on non-boolean casts. Now returns 400 on missing
value / type mismatch and leaves the original value unchanged.
Doc overclaims corrected (no silent scope creep):
- T01-T05 module-toggle flags (isCounselingEnabled etc.) have zero business
call sites -> dead config (exposed but not gating). Left for each module's
own phase to wire; documented as residual.
- T07 private-storage bucket flags have zero references; storage already uses
object-storage.bucket-private. Documented as residual.
- STATUS claimed "application.yml defaults (15 flags)"; yml has no `features:`
block, defaults are Java field defaults. Functionally fine, docs corrected.
T06 upload policy verified actually enforced in LocalEligibilityService +
PhotoService (kept ✅).
Guard tests: new FeatureFlagControllerTest (7 cases: 21 keys exposed, boolean/
string/int update reflected, unknown flag / missing value / wrong type -> 400).
Negative validation: reverting to boolean-only dispatch made exactly 2 update
cases fail red, then green after restore — proves guards are real.
Full regression: 657 tests / 0 failures / 0 errors / 3 skipped (baseline 650, +7).