Files
orca/tests
Brennan BensonandMerge Sim 027acb4efa fix(native-chat): settle a structured send on admission, not on the provider echo (#19863)
* fix(native-chat): settle a structured send on admission, not on the provider echo

Sending a message in structured native chat raised "Message delivery is
unconfirmed." with a Retry button on a message that had in fact been
delivered. Measured across 14 days of local journals: 44 of 173 delivered
sends (25.4%) tripped it.

The dispatch path wrote the message to the provider, then waited a fixed
10s for the provider to echo the message's uuid back. That echo is emitted
when the provider STARTS the turn, so a message queued behind a running
turn cannot be echoed until that turn ends. Echo latency is bounded by the
previous turn's duration, which is unbounded -- one send took 105 minutes.
The 10s constant sat at the p75 of real echo latency, with the slowest
clean send at 9.76s, a margin of 0.24s. No constant can work: the wait was
measuring the wrong event.

The false banner was not cosmetic. It invited a Retry, and Retry bypassed
the operation ledger to redeliver. One message reached the model five times
through that path.

Dispatch now returns as soon as the transport write completes and writes no
dispatch row; the submission stays `pending`, a neutral state, and the
provider's echo settles it `accepted` through the late-settlement channel
whenever the turn ahead of it ends. Delivery doubt is reachable only from
process facts -- a refused write, a dead child, a dead host -- never from
elapsed time.

Retry re-delivers only where the recorded reason proves the message never
reached the provider. The list is deliberately fail-closed: refusing a
legitimate retry costs the user a re-type, while allowing an illegitimate
one sends the model a second copy of their message. A refused entry now
leaves the outbox with an explicit notice instead of parking at the head,
where it would have wedged every message queued behind it.

The send-response classification moves to a pure module beside the existing
outbox reconciler, so both writers of an entry's state now live together and
the decision is unit-testable rather than reachable only through the hook.

Scope and known gaps:
- Codex carries the same 10s stopwatch. It has no late-settlement channel,
  matches waiters by queue order rather than identity, and has no waiter
  lifecycle at all, so there was no safe subset to land here. A marker
  constant records the debt and deletes itself when that lands.
- A message refused re-delivery loses its standing delivery notice and
  leaves only a transient error line. A passive "waiting to be accepted"
  affordance is the follow-up.
- The restart reconciler that would decide a dead child or a dead host on
  evidence rather than refusing them is fully written and has never had a
  production caller. Wiring it is the next change, and it removes the
  re-type cost above.

* fix(native-chat): harden structured dispatch settlement

* fix(native-chat): preserve dispatch recovery evidence

* fix(native-chat): preserve pending send compatibility

* fix(native-chat): satisfy native import audit

* fix(native-chat): bound legacy send settlement

---------

Co-authored-by: Merge Sim <sim@local>
2026-09-10 16:29:02 -07:00
..