Feedback em dash sanitize at boundary
Justin's frustration 2026-04-29: "this and all the bots including stuff that is putting on Notion I'll have M dashes ... wondering if essentially I just need to give up on that because every single one of them is doing that." The answer is no, you don't give up — Sonnet's prompt-following on no-em-dash is unreliable, so we sanitize in python before bytes leave the process.
Why: Sonnet ignores the rule about ~30% of the time even with explicit "NO em dashes" in the system prompt. We've seen it appear in:
- Telegram replies (already sanitized)
- Telegram check-in pushes from heartbeat.py (NOW sanitized)
- Notion writes from tool params via the brain (NOW sanitized at dispatch boundary)
- Notion writes from forge_wellness_daily_summary.py summary line (NOW sanitized)
- Telegram pushes from morning-brief.py (NOW sanitized)
How to apply: any new forge script that calls Sonnet and emits the result to Telegram, Notion, Calendar, Gmail, or any external surface MUST do from forge_text_sanitize import strip_em_dashes and run the result through strip_em_dashes() before the call to push / page_create / sendMessage / etc. For tool param dicts (Notion properties, calendar event payloads), use sanitize_recursive(params) — recursively walks dicts/lists.
The canonical helper lives at forge/scripts/forge_text_sanitize.py. Two functions:
- strip_em_dashes(text) — single string in, sanitized string out.
- sanitize_recursive(value) — walks dicts / lists recursively, sanitizing strings.
The brain's _sanitize_reply and the dispatcher's tool-param scrub both delegate to this helper. Don't fork; if Sonnet starts emitting some new AI-tell, extend forge_text_sanitize.py once and every script benefits.
Also: when Sonnet writes narrative summaries (heartbeat, morning-brief), keep prompts strict about citing only data in the input, otherwise it confabulates ("BATHE launch party tonight" when the only calendar match is 6 days out). Combine factual prompt rules with python-side sanitization.
[Claude Code, bot-refiner-v2, 2026-04-29]