- Thread tools are bound server-side to the chat's own thread. The model
used to pass contact_id, so practice mode could read any conversation it
named; a model-supplied contact_id is now only checked, never trusted, and
the prompts no longer hand it one.
- Practice chats need no persona. They're stored under PRACTICE_PERSONA_ID
and run with an inert stand-in, so deleting or editing personas can't hide
or break them. persona_id is optional on create for as_contact.
- The per-thread list filters in SQL (list_persona_chats_for_contact, served
by idx_persona_chat_anchor_contact) instead of decoding every transcript.
- fetch_mms_image checks the content type and a 20 MB cap before reading
the body, so a video attachment isn't downloaded in full.
- get_photos_near_time unions tags over every path sharing the content, per
the multi-library model.
- look_at_photo only opens indexed photos, so an excluded folder can't be
read by guessing a path.
- One date parser: get_photos_near_time uses date_info::parse_center.
- Practice prompt source rewrapped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>