refactor(telegram): transactional-state guard — no booking dies on a shrug
Root-cause fix for the recurring bug class where a typed message at a
booking step was misrouted and destroyed the transaction (e.g. "اوکیه لینک
رو بده" over the confirm card read as unrelated, which cleared the
booking one tap before payment and forwarded a context-free turn to the
core — the user's own confirmation nuked their booking).
New bot/txn_intent.py classifies typed text at a transactional step into AFFIRM / CANCEL / PIVOT / OTHER (multilingual, digit-script agnostic, conservative: PIVOT needs positive new-request evidence). The booking text handlers now enforce two invariants:
- an in-progress booking ends ONLY on an explicit CANCEL or a clear PIVOT — a confirmation completes it (both confirm-card and collect steps), everything else nudges with state intact;
- the
✅ tap and a typed "yes" share one _finalize_booking path, so the two ways of confirming behave identically.
Adds tests/test_txn_intent.py (stdlib-only, runs under pytest or as a script) covering the transcript cases and the no-accidental-pivot invariant, and docs/ONE_BRAIN_MIGRATION.md — the plan to move transactional state into the core Workflow so the seam that generates this bug class is removed, not just patched.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com