Connect by JBRH Open Connect

Why 'sent' must require provider evidence

outbound.py is the single send boundary, shared by the engine and by a person, and it reports a message as sent only once the provider has acknowledged it. Everything else is failed or uncertain — a real third state, displayed as itself rather than resolved by optimism, because re-sending on a maybe is how a customer receives the same reply twice.

Status
Available What this means
Audience
both, developer
Last verified
Product version
6.3.2

Three states#

StateEvidenceWhat it means for the customerWhat happens next
SentThe provider acknowledged the messageIt is with the provider; delivery is a separate questionRecorded against the thread with the acknowledgement
FailedThe provider refused it, or a gate didNothing was sentThe reason is shown — a refusal, a suppression, a spent allowance
UncertainNone either way — the handoff completed without an answerUnknown: it may be in flight, it may never have leftShown as uncertain, resolved by evidence rather than by a retry

Most systems have two states because the third is uncomfortable. It appears anyway — a connection dropped after the request left and before the response arrived is an ordinary event on any network — and the choice is only whether to represent it or to pick a side and be wrong some of the time.

Why guessing costs more than admitting#

Guessing *failed* and re-sending duplicates the message. The customer gets the same reply twice, which reads as carelessness in a way a delay does not, and on a thread with a quotation or a commitment it is worse than that.

Guessing *sent* loses the message. Nobody follows up, because the record says the work is done, and the failure is discovered when the customer asks why nobody replied — the one moment at which the answer cannot be recovered gracefully.

Keeping the state honest costs one thing: somebody has to look. That is the trade, and it is the right way round, because the looking is bounded and the alternatives are not.

Resolving an uncertain send#

  1. Read the provider's own record for that window and compare it with Connect's.

    Result This is the fastest audit available and it generalises: on the phone side, a call the carrier logs as completed with no matching row on our side is a defect every time. The same comparison settles a message.

  2. Treat a 4xx as an answer.

    Result A 4xx is the provider saying no. It is never retried, on any path here, because retrying a refusal produces the same refusal and obscures the original one.

  3. Treat a timeout as an unknown, and retry it at most as the path's rule allows.

    Result On the call path, a dial the carrier answered with 408, 503 or 504 is dialled once more, and a leg that never joins is written off after a bounded wait rather than waited on indefinitely.

  4. If evidence says the message went, mark it and move on; if it says nothing did, send once, deliberately.

    Result The decision is recorded with the person who made it, which is what the audit trail is for.

What is not evidence of a send#

  • A model saying it sent something. Tool output is a claim about an intention. The record is what the boundary wrote after the provider answered.
  • A draft that exists. A held draft has not been handed to any provider: there is no message in flight, no read receipt and nothing in a sent folder. It is not a slow reply, it is no reply.
  • A successful write-back. Marking a message read or labelling it in Gmail is a separate operation, and a write-back failure never blocks the reply — which also means its success says nothing about the reply.
  • Delivery. Acknowledgement is the provider accepting the message. A later bounce, a spam placement or a silent drop are delivery outcomes, and they do not retroactively make the send a failure.

Questions#

Why does the screen say uncertain instead of just retrying?

Because a retry on a maybe is a duplicate on the customer's side, and there is no evidence yet that would distinguish the two cases. Showing the state as it is puts the decision in front of a person along with the means to settle it — the provider's own record.

Does a bounce mean the message was never sent?

No. A bounce happens after the provider accepted the message, so the send was real and the delivery failed. The two are recorded separately because the remedies are different: a bounce points at the address or the receiving server, not at the send.

Is the send boundary the same for the engine and for a person?

The same one. outbound.py is where every outbound crosses, whether the engine wrote it or somebody approved it from the queue, which is why the evidence rule holds uniformly and there is no second path with weaker bookkeeping.