What happens when the server deleted an entity that was edited locally.
serverWinsPreserveLocal: the server's deletion wins for the push — replay never recreates
the entity — and the local capture is preserved: its queue entry moves to quarantined with
reason deletedOnServer. It is never SILENTLY destroyed — that is the one outcome this
contract exists to prevent.
⚠️ The entity stays on the device until the operator destroys the capture. Its local
record holds the operator's work, which the pull never sweeps (db/features.ts). Destroying
the capture (discardQuarantined) removes that record too, since the server has nothing to
give back. This sentence read « the entity leaves the map » until 25/09/2026: no code did that
on the push, and the destruction removed only the queue entry.
⚠️ This sentence used to read « It is never destroyed », and the absolute form had
a cost that was measured rather than argued. A quarantined entry had NO exit at all: not
the drain (REPLAYABLE_STATUSES is failed + pending), not the purge, not any UI
gesture. On a field device the class only grew — visible, counted, unresolvable. « Never
destroyed » protected the capture from being lost and condemned the operator to carry it
forever.
The amendment names what the contract actually defends: the loss the operator did not
see. Two exits, arbitrated by Mattieu on 07/08/2026, and each covers the half it fits:
Requeue when the CAUSE is lifted.retryBudgetExhausted, layerNoLongerWritable and
notImplementedByServer name a condition that can be lifted — the network answered, the
layer regained its write target, the server was upgraded. Those entries go back to
pending. The other two cannot: replaying a deletedOnServer would recreate what the
server deleted, and rejectedByServer is defined as a reason replay cannot fix.
Two more have joined them since: authRequired (03/09/2026 — the operator signs back in)
and dialectNotSupported (17/09/2026 — the layer's declaration changes). The list that
decides is REQUEUEABLE in write/quarantine-api.ts.
⚠️ The third one was added on 09/08/2026, and its absence had turned exit 1 into exit 2 for
a whole class of captures. Every transient server outage was reported as
rejectedByServer, so the only exit left for a capture caught during a maintenance
window was the confirmed destruction below — which the operator would have confirmed in
good faith, having been told replay could not fix it.
Destruction the operator CONFIRMS, having seen the capture enumerated. A capture
that was shown, itemised and then explicitly discarded is not a capture that was lost.
🛑 What is still forbidden, and it is the whole point: a retention cap, a purge sweep, or
any path that drops an entry without a human seeing exactly what is dropped.
What happens when the server deleted an entity that was edited locally.
serverWinsPreserveLocal: the server's deletion wins for the push — replay never recreates the entity — and the local capture is preserved: its queue entry moves toquarantinedwith reasondeletedOnServer. It is never SILENTLY destroyed — that is the one outcome this contract exists to prevent.⚠️ The entity stays on the device until the operator destroys the capture. Its local record holds the operator's work, which the pull never sweeps (
db/features.ts). Destroying the capture (discardQuarantined) removes that record too, since the server has nothing to give back. This sentence read « the entity leaves the map » until 25/09/2026: no code did that on the push, and the destruction removed only the queue entry.⚠️ This sentence used to read « It is never destroyed », and the absolute form had a cost that was measured rather than argued. A quarantined entry had NO exit at all: not the drain (
REPLAYABLE_STATUSESisfailed+pending), not the purge, not any UI gesture. On a field device the class only grew — visible, counted, unresolvable. « Never destroyed » protected the capture from being lost and condemned the operator to carry it forever.The amendment names what the contract actually defends: the loss the operator did not see. Two exits, arbitrated by Mattieu on 07/08/2026, and each covers the half it fits:
Requeue when the CAUSE is lifted.
retryBudgetExhausted,layerNoLongerWritableandnotImplementedByServername a condition that can be lifted — the network answered, the layer regained its write target, the server was upgraded. Those entries go back topending. The other two cannot: replaying adeletedOnServerwould recreate what the server deleted, andrejectedByServeris defined as a reason replay cannot fix.Two more have joined them since:
authRequired(03/09/2026 — the operator signs back in) anddialectNotSupported(17/09/2026 — the layer's declaration changes). The list that decides isREQUEUEABLEinwrite/quarantine-api.ts.⚠️ The third one was added on 09/08/2026, and its absence had turned exit 1 into exit 2 for a whole class of captures. Every transient server outage was reported as
rejectedByServer, so the only exit left for a capture caught during a maintenance window was the confirmed destruction below — which the operator would have confirmed in good faith, having been told replay could not fix it.Destruction the operator CONFIRMS, having seen the capture enumerated. A capture that was shown, itemised and then explicitly discarded is not a capture that was lost.
🛑 What is still forbidden, and it is the whole point: a retention cap, a purge sweep, or any path that drops an entry without a human seeing exactly what is dropped.