Engineering
Not Confirmed Is a Real Outcome
A write can leave your system, time out, and still succeed. Treating that as a failure can create the duplicate you were trying to prevent.
There is a failure state that a lot of internal software quietly pretends does not exist.
You send a write.
The request leaves your application.
Then the response disappears.
Maybe the provider is slow.
Maybe the connection drops.
Maybe a proxy returns something unreadable.
Maybe your own service times out while the system on the other side keeps working.
At that point, one thing is true:
You do not know whether the write happened.
That is not the same as failure.
And pretending it is can create a much worse failure.
The dangerous retry
Reads are easy to reason about.
If a read times out, try again. You are asking a question. Asking it twice does not usually create a second invoice, send another notice, or complete the same action twice.
Writes are different.
Imagine software sends an instruction to create an accounting record.
The provider receives it and starts processing it.
Your application does not get the answer in time.
If your UI says Failed — try again, the operator does exactly what the software told them to do.
Now the second request lands too.
The original problem was uncertainty.
The software just turned it into a duplicate.
We needed a third state
The clean model is not:
success / failure
It is closer to:
not sent / refused / unknown / confirmed
Those states mean different things.
Not sent means the request never crossed the boundary. The system can safely say nothing happened.
Refused means the owner of the operation answered clearly: the record was not created, the precondition failed, the item was already closed, or the action was not allowed.
Unknown means the request was sent, but the application cannot prove what happened next.
Confirmed means the resulting business state can actually be observed.
That third state — unknown — is uncomfortable.
It is also honest.
A write timeout should not mean “failed”
We ended up giving writes a separate deadline from reads.
A normal read can give up quickly.
A write gets more time because the request may already be executing somewhere else.
More importantly, when that write deadline expires, the code does not convert it into a normal failure.
It becomes an unknown outcome.
The same thing happens if the request was sent and the application gets back an answer it cannot safely interpret.
Once the write has crossed the boundary, ambiguity matters.
The client also does not automatically resend it.
That rule is intentionally boring:
If the first write may have landed, do not create a second one just because the acknowledgement disappeared.
The interface has to tell the same truth
Backend correctness is not enough if the UI gives the operator the wrong mental model.
The message we settled on is deliberately plain:
Not confirmed. Refresh to check before trying again.
That wording does three useful things.
It does not claim success.
It does not claim failure.
And it tells the person what to do next without encouraging a duplicate write.
The control stays latched rather than immediately inviting another click.
The operator checks the resulting state first.
Only after the system knows what happened should another action be possible.
This is really an idempotency problem
Good write design has several layers.
An idempotency key can help the receiving system recognize the same logical request twice.
Duplicate checks can block a second record that looks like the first.
Preconditions can stop an action when the source state changed underneath it.
Verification can independently read the resulting state after a write.
But none of those eliminate the need to represent uncertainty.
The caller still needs to know the difference between:
I never sent it
and
I sent it but lost the receipt.
That distinction belongs in the API, in the logs, and in the interface.
“Unknown” is not a weak answer
Software teams often avoid unknown states because they look unfinished.
A green success badge feels better.
A red failure badge feels decisive.
Unknown feels messy.
But operational software is supposed to describe reality, not make reality look cleaner than it is.
Sometimes the most accurate state is:
- the request left
- the provider may have changed something
- we cannot prove the result yet
- do not repeat the action until we check
That is useful information.
In financial systems, messaging systems, work-order tools, and any workflow where an action has side effects, that state can be the difference between recovery and duplication.
The larger lesson
A dependable system is not one that always knows the answer immediately.
It is one that knows what it knows.
And just as importantly:
what it does not know yet.
The more software is allowed to take real action, the more important that distinction becomes.
“Not confirmed” is not an error message we failed to clean up.
It is a first-class operating state.
And in the right system, it is one of the safeguards that keeps uncertainty from turning into damage.