Migrate richer channels onto the shared notification formatter #14

Closed
opened 2026-06-23 23:15:17 +00:00 by rbrooks · 2 comments
Owner

Target release: v1.2.0

SMS already uses the shared formatter and 140-char budget. Gradually move the richer channels (Discord, Matrix, Signal, Pushover, Webex, Webhook) onto app/services/notification_formatting.py with per-channel budgets/profiles and truncation metadata.

Acceptance

  • Per-channel message budgets and formatting profiles defined.
  • Each richer notifier returns text + metadata (char count, link count, truncation status, omitted sections).
  • Verbose official text pushed to linked detail pages; compact "Details" link in a predictable place.

Source: docs/ROADMAP.md → Notification Message Budget and Compact Link System.

**Target release:** v1.2.0 SMS already uses the shared formatter and 140-char budget. Gradually move the richer channels (Discord, Matrix, Signal, Pushover, Webex, Webhook) onto `app/services/notification_formatting.py` with per-channel budgets/profiles and truncation metadata. **Acceptance** - [ ] Per-channel message budgets and formatting profiles defined. - [ ] Each richer notifier returns text + metadata (char count, link count, truncation status, omitted sections). - [ ] Verbose official text pushed to linked detail pages; compact "Details" link in a predictable place. Source: `docs/ROADMAP.md` → Notification Message Budget and Compact Link System.
Contributor

Audit note (2026-07-18)

From the 2026-07 codebase audit (docs/.internal/report-2026-07-17.md), finding F-32.

The shared formatter's budget math is codepoint-based — len() against a flat 140 (app/services/notification_formatting.py:35-43,95-117). A single non-GSM-7 character (em dash, curly quote — both common in NWS text, or in a free-text location.name) silently flips carrier encoding to UCS-2 (70 chars/segment), so a message the code considers "fits in budget" can span 2+ real SMS segments.

As part of the per-channel budgets in this issue, make the SMS budget segment-aware (detect GSM-7 vs UCS-2 and budget accordingly), or strip/replace non-GSM-7 characters before budgeting.

Related audit work now scheduled in this milestone (v1.2.0): delivery outbox (#50), pipeline concurrency (#53), per-type channel-config validation (#55), non-blocking Twilio (#56).

## Audit note (2026-07-18) From the 2026-07 codebase audit (`docs/.internal/report-2026-07-17.md`), finding **F-32**. The shared formatter's budget math is codepoint-based — `len()` against a flat 140 (`app/services/notification_formatting.py:35-43,95-117`). A single non-GSM-7 character (em dash, curly quote — both common in NWS text, or in a free-text `location.name`) silently flips carrier encoding to UCS-2 (70 chars/segment), so a message the code considers "fits in budget" can span 2+ real SMS segments. As part of the per-channel budgets in this issue, make the SMS budget **segment-aware** (detect GSM-7 vs UCS-2 and budget accordingly), or strip/replace non-GSM-7 characters before budgeting. Related audit work now scheduled in this milestone (v1.2.0): delivery outbox (#50), pipeline concurrency (#53), per-type channel-config validation (#55), non-blocking Twilio (#56).
Contributor

Done in #99 (merged). The six richer channels (Discord, Matrix, Signal, Pushover, Webex, webhook) now build messages through the shared formatter with per-channel-type budgets and a 3-tier compose() (required / droppable-optional / pinned) that keeps one compact "Details" link in a predictable place. FormattedMessage carries char/link/omitted/encoding/segment metadata. SMS budgeting is segment-aware (F-32: sanitize non-GSM-7 punctuation, else budget at the UCS-2 rate). Each channel's structural shape (Discord embed, Matrix HTML body, Pushover title/url, Webex markdown) is preserved.

Done in #99 (merged). The six richer channels (Discord, Matrix, Signal, Pushover, Webex, webhook) now build messages through the shared formatter with per-channel-type budgets and a 3-tier `compose()` (required / droppable-optional / pinned) that keeps one compact "Details" link in a predictable place. `FormattedMessage` carries char/link/omitted/encoding/segment metadata. SMS budgeting is segment-aware (F-32: sanitize non-GSM-7 punctuation, else budget at the UCS-2 rate). Each channel's structural shape (Discord embed, Matrix HTML body, Pushover title/url, Webex markdown) is preserved.
Sign in to join this conversation.
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rbrooks/WeatherBot#14
No description provided.