Improve weather alert parsing and deduplication - #1
Conversation
Three problems reported on the community forum for the One Call 3.0 alerts (https://community.gladysassistant.com/t/integration-externe-openweather/10497): 1. Wrong severities. OpenWeather relays the MeteoAlarm wording, in which EVERY alert is a "<colour> <phenomenon> warning" — the `warning` keyword of the `severe` rule matched first, so a yellow vigilance was published as `severe`. On top of that the severity was read from the `tags` too, and the "Extreme high temperature" tag is the name of the PHENOMENON: every heat and cold alert came out as `extreme`. The vigilance colour is now read first, and the phenomenon labels are stripped from the wording before it is ranked. 2. The bulletin text printed once per alert. A national office sends the same department bulletin as the description of every phenomenon it covers; a description already published is no longer repeated on the following alerts, and a description that repeats itself is collapsed. Identical alerts sent twice are dropped as well. 3. Expired bulletins. OpenWeather keeps serving an alert past its `end` date; it is now dropped instead of being displayed and taking one of the 10 slots the core keeps. The alert wording itself stays in English: OpenWeather serves it that way whatever `lang` says ("National weather alerts are provided in English by default"), and only the weather `description` field — which this integration does not use — is translated. What the widget can translate is the label of a TYPED alert, so the phenomenon detection now also covers freezing rain, frost, fog, tornado, tropical storm, runoff and their French wordings. Documented in the README and both user docs. Also formats the manifest with the pinned Prettier, which the repository had drifted from. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013uqZyRZP4W7eKXKRKUDiBG
📝 WalkthroughWalkthroughChangesAlert processing
Estimated code review effort: 4 (Complex) | ~45 minutes PoemPoem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/openweather/alerts.js`:
- Around line 189-194: Normalize internal whitespace in each paragraph before
constructing distinct, while preserving the existing trimming, empty-paragraph
filtering, joining, and undefined behavior. Update the paragraph transformation
in the rawDescription processing flow so differently wrapped instances of the
same paragraph produce identical text for Set de-duplication.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: db33c176-a1d5-494f-aa61-6c48e7e7f02e
📒 Files selected for processing (11)
README.mddocs/en.mddocs/fr.mdgladys-assistant-integration.jsonsrc/openweather/alerts.jssrc/openweather/formatOneCall.jssrc/weather.jstest/alerts.test.jstest/fixtures/oneCall.jstest/formatOneCall.test.jstest/weather.test.js
| const paragraphs = rawDescription | ||
| .split(/\n\s*\n+/) | ||
| .map((paragraph) => paragraph.trim()) | ||
| .filter((paragraph) => paragraph.length > 0); | ||
| const distinct = [...new Set(paragraphs)]; | ||
| return distinct.length > 0 ? distinct.join('\n\n') : undefined; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Normalize each paragraph before de-duplication.
distinct compares only trimmed paragraph text. It does not compare whitespace-normalized text. If the relay wraps a repeated paragraph differently, this function publishes that paragraph twice. descriptionKey runs after the paragraphs are joined, so it cannot remove the duplicate.
Proposed fix
- const distinct = [...new Set(paragraphs)];
+ const seen = new Set();
+ const distinct = paragraphs.filter((paragraph) => {
+ const key = descriptionKey(paragraph);
+ if (seen.has(key)) {
+ return false;
+ }
+ seen.add(key);
+ return true;
+ });📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const paragraphs = rawDescription | |
| .split(/\n\s*\n+/) | |
| .map((paragraph) => paragraph.trim()) | |
| .filter((paragraph) => paragraph.length > 0); | |
| const distinct = [...new Set(paragraphs)]; | |
| return distinct.length > 0 ? distinct.join('\n\n') : undefined; | |
| const paragraphs = rawDescription | |
| .split(/\n\s*\n+/) | |
| .map((paragraph) => paragraph.trim()) | |
| .filter((paragraph) => paragraph.length > 0); | |
| const seen = new Set(); | |
| const distinct = paragraphs.filter((paragraph) => { | |
| const key = descriptionKey(paragraph); | |
| if (seen.has(key)) { | |
| return false; | |
| } | |
| seen.add(key); | |
| return true; | |
| }); | |
| return distinct.length > 0 ? distinct.join('\n\n') : undefined; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/openweather/alerts.js` around lines 189 - 194, Normalize internal
whitespace in each paragraph before constructing distinct, while preserving the
existing trimming, empty-paragraph filtering, joining, and undefined behavior.
Update the paragraph transformation in the rawDescription processing flow so
differently wrapped instances of the same paragraph produce identical text for
Set de-duplication.
Summary
Enhanced the weather alert processing to correctly parse alert severity from vigilance colours, deduplicate repeated bulletins, filter expired alerts, and improve phenomenon type detection across French and English wordings.
Key Changes
Severity parsing by colour: Added
SEVERITY_BY_COLOURto read the vigilance colour (red/orange/yellow) before generic severity keywords. This is critical for MeteoAlarm alerts where every alert is called a "warning" — the colour is the actual severity level published by the office.Phenomenon label stripping: Created
severityWording()function that removes phenomenon labels (both from OpenWeather tags and thePHENOMENON_LABELSlist) before ranking severity. This prevents "Extreme high temperature" (a phenomenon name) from incorrectly elevating a yellow alert to extreme.Bulletin deduplication:
toDescription()to clean up bulletin text by removing duplicate paragraphsdescriptionKey()to normalize text for comparison (handles re-wrapping by relays)Expired alert filtering: Added
isOngoing()function to drop alerts past theirenddate. OpenWeather continues serving bulletins well after expiration, which would waste the 10-alert limit.Duplicate alert detection: Track alert identity (severity + type + event + start + end) to drop identical alerts sent multiple times.
Expanded pattern matching: Enhanced regex patterns for phenomenon detection to cover more French and English variations:
Test coverage: Added comprehensive tests for colour-based severity, phenomenon label handling, bulletin deduplication, expired alert filtering, and duplicate detection.
Documentation updates: Updated README and troubleshooting docs to explain alert language handling (OpenWeather serves alerts in English by default) and the importance of type detection for widget translation.
Implementation Details
formatAlerts()function now accepts an optionalnowparameter for testabilityformatOneCallWeather()also accepts optionalnowparameter and passes it toformatAlerts()ONE_CALL_NOWconstant to ensure consistent alert expiration testingescapeForRegExp()added for safe dynamic pattern constructionhttps://claude.ai/code/session_013uqZyRZP4W7eKXKRKUDiBG
Summary by CodeRabbit
Improvements
Documentation