6532d9d8da
The outer final send is bracketed by the adapter against the event that OPENED the chain, so a terminal reply was recorded under the first message's id. When two turns of one chain answered with the same text, the terminal reply computed the earlier row's obligation id, replaced its outstanding row and marked it delivered, so a first reply the platform had refused was never redelivered. MessageEvent gains a documented ledger_message_id that the obligation hash prefers, the queued follow-up returns the terminal turn's inbound id (innermost wins on nested chains), and the handler sets it before the adapter brackets the send. Reply routing is untouched: the anchor still comes from the event. Three of the four new tests fail without this change; the whole tests/gateway suite shows the same failure set before and after.