- river dash animation now flows at a speed continuously derived from
each segment's discharge (period 260/(Q+45) s, clamped 0.5-5.5 s) via
inline per-path animation-duration, so it updates live and per-frame
during the replay (CSS speed classes removed - setStyle cannot change
classes)
- the replay drives the Combined discharge and Strongest flow stat
tiles each frame (marked '2024 replay'), restored on finish
- docs: hour-by-hour detection detail render (22-28 Sep 2024) showing
the model alert at 24 Sep 01:00, flooding at 25 Sep 01:00, and the
24 h warning between them; embedded with commentary
- Matrix alerts now link to https://water.buildfor.life/ (override via
ALERT_DASHBOARD_URL), replacing the Grafana public dashboard link
The push-CI gates (black/isort/mypy) had never actually run before the
branch-trigger fix, and the codebase predates them. Formatting is now
black/isort clean repo-wide. mypy keeps running but non-blocking: 86
pre-existing errors are a separate cleanup, not a gate to hold hostage.
Matrix alerts:
- Send HTML formatted_body (org.matrix.custom.html) so **bold** and URLs
render instead of showing literal Markdown; add plain-text body fallback.
Add dependency-free markdown_to_matrix_html/strip_markdown helpers with
HTML escaping of station/message data.
Security:
- InfluxDB: bind untrusted station_codes as query params and cast limit to
int (was f-string interpolation / injection risk).
- VictoriaMetrics: escape Prometheus label values and coerce metric values
to float, preventing exposition-format injection and None crashes.
- web_api: run blocking scrape cycle via run_in_executor so it no longer
freezes the event loop; make CORS origins configurable and only allow
credentials with explicit origins ("*" + credentials is invalid/unsafe).
- config: remove hardcoded root/postgres password fallbacks (raise instead)
and stop defaulting VM_HOST to a real infrastructure hostname.
Also remove unused imports and wrap long lines to satisfy flake8.
- Stale data alerts now only trigger after 12 hours without new data
- Reduces false alerts during expected data gaps
Co-Authored-By: Claude <noreply@anthropic.com>
- Added Black for code formatting (line-length 120)
- Added isort for import sorting
- Added flake8 for linting
- Added standard pre-commit hooks for file checks
Co-Authored-By: Claude <noreply@anthropic.com>
- Created test suite for zone-based water level alerts (9 test cases)
- Created test suite for rate-of-change alerts (5 test cases)
- Created combined alert scenario test
- Fixed rate-of-change detection to use station_code instead of station_id
- All 3 test suites passing (14 total test cases)
Test coverage:
- Zone alerts: P.1 zones 1-8 with INFO/WARNING/CRITICAL/EMERGENCY levels
- Rate-of-change: 0.15/0.25/0.40 m/h thresholds for WARNING/CRITICAL/EMERGENCY
- Combined: Simultaneous zone and rate-of-change alert triggering
Co-Authored-By: Claude <noreply@anthropic.com>
- Implement check_rate_of_change() to detect rapid water level rises
- Monitor water level changes over configurable lookback period (default 3 hours)
- Define rate-of-change thresholds for P.1 and other stations
- Alert on moderate (15cm/h), rapid (25cm/h), and very rapid (40cm/h) rises
- Only alert on rising water levels (positive rate of change)
- Integrate rate-of-change checks into run_alert_check() cycle
- Support both SQLite and PostgreSQL database adapters with fallback
Rate thresholds for P.1 (Nawarat Bridge):
- Warning: 0.15 m/h (15 cm/hour) - moderate rise
- Critical: 0.25 m/h (25 cm/hour) - rapid rise
- Emergency: 0.40 m/h (40 cm/hour) - very rapid rise
Default thresholds for other stations:
- Warning: 0.20 m/h, Critical: 0.35 m/h, Emergency: 0.50 m/h
Alert messages include:
- Rate of change in m/h and cm/h
- Total level change over period
- Time period analyzed
This early warning system detects dangerous trends before absolute
thresholds are reached, allowing for earlier response to flooding events.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Change HTTP method from POST to PUT for Matrix API v3
- Matrix API requires PUT when transaction ID is included in URL path
- Move transaction ID construction before URL building for clarity
- Fixes "405 Method Not Allowed" error when sending notifications
The Matrix API v3 endpoint structure:
PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}
Previous error:
POST request was being rejected with 405 Method Not Allowed
Now working:
PUT request successfully sends messages to Matrix rooms
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add 8 water level zones plus NewEdge threshold for P.1 station
- Zone 1: 3.7m (Info), Zone 2: 3.9m (Info)
- Zone 3-5: 4.0-4.2m (Warning levels)
- Zone 6-7: 4.3-4.6m (Critical levels)
- Zone 8/NewEdge: 4.8m (Emergency level)
- Implement special zone-based checking logic for P.1
- Maintain backward compatibility with standard warning/critical/emergency thresholds
- Keep standard threshold checking for other stations
Zone progression for P.1:
- 3.7m: Zone 1 alert (Info)
- 3.9m: Zone 2 alert (Info)
- 4.0m: Zone 3 alert (Warning)
- 4.1m: Zone 4 alert (Warning)
- 4.2m: Zone 5 alert (Warning)
- 4.3m: Zone 6 alert (Critical)
- 4.6m: Zone 7 alert (Critical)
- 4.8m: Zone 8/NewEdge alert (Emergency)
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Implement custom Python alerting system (src/alerting.py) with water level monitoring, data freshness checks, and Matrix notifications
- Add complete Grafana Matrix alerting setup guide (docs/GRAFANA_MATRIX_SETUP.md) with webhook configuration, alert rules, and notification policies
- Create Matrix quick start guide (docs/MATRIX_QUICK_START.md) for rapid deployment
- Integrate alerting commands into main application (--alert-check, --alert-test)
- Add Matrix configuration to environment variables (.env.example)
- Update Makefile with alerting targets (alert-check, alert-test)
- Enhance status command to show Matrix notification status
- Support station-specific water level thresholds and escalation rules
- Provide dual alerting approach: native Grafana alerts and custom Python system
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>