Address the Phase-3 review nits collected in #298:
- perf(HtmlToText): hoist the 4 per-call Regex literals in convert() to
private vals so each compiles once, not once per fetched HTML body.
- fix(ReportStore): write reports via temp-file + atomic rename so a crash
mid-write can't truncate a .json that scan() then silently drops. Temp uses
a non-.json suffix so it is never scanned.
- fix(RichTextEditing): applyLink now splits partially-overlapping links
(keeping the non-overlapping remainder) instead of un-linking it whole,
mirroring subtractRange.
- perf(GraphSender): guard attachment size before readBytes() so an oversized
file can't OOM or blow Graph sendMail's ~4 MB request cap; fails
mayHaveSent=false so the outbox falls back to SMTP (which streams).
- perf(RichText): mergeSameValueSpans is O(n) via a last-run-per-style map
instead of O(n^2) indexOfLast; output is identical.
- fix(DiagnosticsCollector): bucket provider labels by DNS-label boundary, not
raw substring, so mail.notgmail.example no longer reads as Gmail.
Adds/updates unit tests for each behavioural change; pure-perf nits keep their
existing green coverage plus a direct mergeSameValueSpans equivalence test.