Red-flag audit + fix
Finding: red flags never fired in production
Same skew class as the model metadata. The gateway posts the raw anamnesis
(bleeding, color, fever.exists, location1.secondary, β¦) to /red_flags,
but every rule in redFlags.csv indexes derived features β is_bleeding_true,
temperature, is_color_condition_black, is_secondary_locations_gingiva, β¦ β
which nothing in the serving path computes. So each rule raised KeyError,
and evaluate() caught it with except (KeyError, TypeError): continue β silently
skipping every rule. Net: zero red flags, ever, on both the ai-service path
(/api/v1/diagnosis/red_flags, used by /api/diagnosis) and the gateway path
(/api/ai/red_flags, used by the mobile app). Both managers + rule tables are
duplicates and were both broken.
Changes
- Pruned the rule table to the questions we still collect. Of 22 rules, 18
depended on dropped questions (color, bleeding, fever, swelling, size, pus,
elevation/topography, crater). Kept the 4 that use only kept fields:
oral lesions (location), infant / elderly (age), pregnant
(pregnancy). Applied to both
redFlags.csvcopies. - Derive the features from the raw anamnesis (
_derive_features) so the kept rules actually fire:age,is_pregnancy_true,is_secondary_locations_*. Applied to both managers. - Fail loudly instead of silently.
evaluate()no longer swallowsKeyError/TypeError; if a rule references a feature the deriver doesnβt produce, it raisesRuntimeErrornaming the rule β so a future metadata/rule mismatch surfaces instead of disappearing (this is what hid the original bug).
Verification
- New
red_flag_manager_test.py: the 4 rules fire from raw dotted-key anamnesis (pregnant/infant/elderly/oral), no false positives, missing age is neutral, scalarlocation.secondaryhandled, and an undefined-feature rule raises. - 6 tests pass; ruff clean on both managers.
Important note for later
This removed the melanoma / erysipelas / high-fever / bleeding red flags along with their inputs. Those were not firing anyway, but if we want them back we must re-collect the underlying signals (color, bleeding, fever) β deciding what to ask purely for safety is a separate product call, independent of what the model uses.