d0b87dad77
The Discord semantic thread-rename lane resolved the target thread from `_relay_auto_thread_info`, which read a single-slot-per-parent-chat cache (`adapter._auto_thread_by_chat[chat_id]`, populated from connector SendResult feedback). When two auto-threads spawned from the SAME parent channel, the second send overwrote the first's slot and the title turn's read raced the write — so only the FIRST thread in a channel ever got its semantic rename. Staging repro 2026-08-02: message A's thread renamed to "A Hundred Word Sword Story", sibling message B's thread stayed stuck at the raw first-words name. The connector now stamps `prospective_thread_id` on the inbound (the anchor message id, which is the id of the thread it will auto-create) — shipped for per-thread session keying. Reuse it here: it is deterministic and per-message, so it names the EXACT thread even when several auto-threads share one channel. `_relay_auto_thread_info` returns it directly (with an empty initial-name marker) and never consults the collision-prone per-chat cache; the connector's own created-name guard (`prefer_connector_created`) still enforces no-clobber, so no initial name is needed gateway-side. The send-result cache path stays as a fallback for older connectors that don't stamp the field. Tests: two new cases in test_relay_threads.py — prospective id wins over a poisoned cache entry, and two sibling threads in one channel each rename to their own thread id. Full gateway session + relay suites green (211 passed).