fix(coach): markdown-strip safety-net + tier-aware speak-endpoint
Backend:
- New stripMarkdown() util (utils/strip-markdown.ts) — handles **bold**,
bullet-lists, headings, code-fences, links, blockquotes
- /api/coach/message: applies stripMarkdown(text) post-LLM as safety-net
because Haiku/Llama keep emitting markdown despite explicit prompt rule
Frontend:
- lyra.tsx voice-flow: hardcoded /api/coach/speak-openai → /api/coach/speak
(tier-aware dispatcher: Free=Google, Pro=Cartesia, Legend=ElevenLabs)
- Added Metro debug-logs at TTS call-site for endpoint + status visibility
- detectEmotion extracted to lib/lyraResponse.ts (was inline duplicate)
- RiveAvatar: small type-export adjustment for shared Emotion type
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>