Summary
detectAlertLevel in scripts/_disease-outbreaks-helpers.mjs:65-70 classifies disease outbreak items into alert / warning / watch using a hand-picked keyword list with no documented source. The resulting alertLevel drives sort order and badge color in src/components/DiseaseOutbreaksPanel.ts — so a user-visible "concern" signal is being produced by a small undocumented editorial heuristic.
Origin
Filed as a follow-up after diagnosing #3729. #3729 claimed there was a weighted scoring formula (severity * 0.6 + spread * 0.25 + alertLevel * 0.15) that turned out to never have existed in the codebase (the reporter copy-pasted from a speculative TODO). The smaller, real issue is below.
Current code
// scripts/_disease-outbreaks-helpers.mjs:65-70
export function detectAlertLevel(title, desc) {
const text = `${title} ${desc}`.toLowerCase();
if (text.includes('outbreak') || text.includes('emergency') || text.includes('epidemic') || text.includes('pandemic')) return 'alert';
if (text.includes('warning') || text.includes('spread') || text.includes('cases increasing')) return 'warning';
return 'watch';
}
Three concerns:
- No methodology disclosure. Users see a colored "alert/warning/watch" badge with no explanation of how it was derived.
- Substring matching with no boundaries.
'epidemic' matches inside 'antiepidemic'; 'spread' matches inside 'widespread vaccination'. Both can over-promote items to a higher alert level. (Lower-priority than the disclosure issue, but worth fixing while in the file.)
- No fallback signal. Items with neither keyword set default to
'watch', which is the lowest visible level — there's no way to mark "no useful signal" distinct from "no urgent signal."
Suggested remediation
- Add a header comment to
detectAlertLevel documenting that the keyword set is editorial (not derived from a published index) and listing the last-reviewed date.
- Add word-boundary checks (
/\b(outbreak|emergency|epidemic|pandemic)\b/) to avoid substring false positives.
- Add a methodology blurb to the panel tooltip in
DiseaseOutbreaksPanel.ts so users can see what alert / warning / watch actually mean.
Same disclosure pattern as #3725 (resolved by PR #3780) — extracted constants + methodology doc — applied at the smaller scale appropriate for a 6-keyword classifier.
Scope
Small. Estimated S effort: ~30 min for the comment + boundary fix + tooltip line + a unit test for detectAlertLevel covering the substring-false-positive case.
Summary
detectAlertLevelinscripts/_disease-outbreaks-helpers.mjs:65-70classifies disease outbreak items intoalert/warning/watchusing a hand-picked keyword list with no documented source. The resultingalertLeveldrives sort order and badge color insrc/components/DiseaseOutbreaksPanel.ts— so a user-visible "concern" signal is being produced by a small undocumented editorial heuristic.Origin
Filed as a follow-up after diagnosing #3729. #3729 claimed there was a weighted scoring formula (
severity * 0.6 + spread * 0.25 + alertLevel * 0.15) that turned out to never have existed in the codebase (the reporter copy-pasted from a speculative TODO). The smaller, real issue is below.Current code
Three concerns:
'epidemic'matches inside'antiepidemic';'spread'matches inside'widespread vaccination'. Both can over-promote items to a higher alert level. (Lower-priority than the disclosure issue, but worth fixing while in the file.)'watch', which is the lowest visible level — there's no way to mark "no useful signal" distinct from "no urgent signal."Suggested remediation
detectAlertLeveldocumenting that the keyword set is editorial (not derived from a published index) and listing the last-reviewed date./\b(outbreak|emergency|epidemic|pandemic)\b/) to avoid substring false positives.DiseaseOutbreaksPanel.tsso users can see whatalert/warning/watchactually mean.Same disclosure pattern as #3725 (resolved by PR #3780) — extracted constants + methodology doc — applied at the smaller scale appropriate for a 6-keyword classifier.
Scope
Small. Estimated S effort: ~30 min for the comment + boundary fix + tooltip line + a unit test for
detectAlertLevelcovering the substring-false-positive case.