Skip to content

Improve weather alert parsing and deduplication - #1

Merged
Pierre-Gilles merged 1 commit into
mainfrom
claude/openweather-integration-ohl3uo
Aug 10, 2026
Merged

Improve weather alert parsing and deduplication#1
Pierre-Gilles merged 1 commit into
mainfrom
claude/openweather-integration-ohl3uo

Conversation

@Pierre-Gilles

@Pierre-Gilles Pierre-Gilles commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

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_COLOUR to 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 the PHENOMENON_LABELS list) before ranking severity. This prevents "Extreme high temperature" (a phenomenon name) from incorrectly elevating a yellow alert to extreme.

  • Bulletin deduplication:

    • Added toDescription() to clean up bulletin text by removing duplicate paragraphs
    • Added descriptionKey() to normalize text for comparison (handles re-wrapping by relays)
    • Track seen descriptions to avoid publishing the same bulletin text multiple times across related alerts
  • Expired alert filtering: Added isOngoing() function to drop alerts past their end date. 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:

    • SNOW: added "freezing", "icy", "glace"
    • COLD: added "gel", "gelée", "givre"
    • FOG: added "brume"
    • WIND: added "tornad", "cyclone", "typhoon", "tropical storm"
    • FLOOD: added "ruissellement"
  • 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

  • The formatAlerts() function now accepts an optional now parameter for testability
  • formatOneCallWeather() also accepts optional now parameter and passes it to formatAlerts()
  • Test fixtures export ONE_CALL_NOW constant to ensure consistent alert expiration testing
  • Regex escaping utility escapeForRegExp() added for safe dynamic pattern construction

https://claude.ai/code/session_013uqZyRZP4W7eKXKRKUDiBG

Summary by CodeRabbit

  • Improvements

    • Improved weather alert severity detection using warning colours and severity wording.
    • Recognized additional English and French alert types.
    • Excluded expired alerts and removed duplicate bulletins, descriptions, and alerts.
    • Improved alert text formatting and timestamp handling.
  • Documentation

    • Expanded troubleshooting guidance for English-language alerts and missing weather alerts.
    • Clarified alert translation coverage and severity-mapping behavior.

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
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Alert processing

Layer / File(s) Summary
Classification and alert filtering
src/openweather/alerts.js
Alert parsing recognizes more phenomenon terms, prioritizes vigilance colours, removes phenomenon labels before wording checks, filters expired alerts, and suppresses duplicates.
Timestamp propagation and validation
src/openweather/formatOneCall.js, src/weather.js, test/*
The request timestamp reaches alert formatting. Tests cover severity, phenomenon detection, deduplication, and expiry filtering.
Alert behavior documentation
README.md, docs/en.md, docs/fr.md
Documentation describes severity rules, alert filtering, English bulletin text, and translated labels.

Estimated code review effort: 4 (Complex) | ~45 minutes

Poem

Poem

I’m a rabbit with alerts in my den,
Colours sort the warnings again.
Old bulletins fade, duplicates flee,
English words hop through clearly.
With timestamps fixed, tests dance free.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes to weather alert parsing and deduplication.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/openweather-integration-ohl3uo

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between b288dae and 3beca44.

📒 Files selected for processing (11)
  • README.md
  • docs/en.md
  • docs/fr.md
  • gladys-assistant-integration.json
  • src/openweather/alerts.js
  • src/openweather/formatOneCall.js
  • src/weather.js
  • test/alerts.test.js
  • test/fixtures/oneCall.js
  • test/formatOneCall.test.js
  • test/weather.test.js

Comment thread src/openweather/alerts.js
Comment on lines +189 to +194
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;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 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.

Suggested change
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.

@Pierre-Gilles
Pierre-Gilles merged commit add3cda into main Aug 10, 2026
2 checks passed
@Pierre-Gilles
Pierre-Gilles deleted the claude/openweather-integration-ohl3uo branch August 10, 2026 13:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants