> ## Content Index
> Fetch the complete content index at: https://devinside.cloud/llms.txt
> Use this file to discover other available public pages before exploring further.

# Success must not erase the path to success.
- URL: https://devinside.cloud/the-retry-that-erased-the-failure-attempt-history-and-log-retention/
- Published: 2026-11-12T15:49:29.000Z
- Updated: 2026-11-13T00:58:20.000Z
- Description: The operation's current status is successful. The incident report says there were no failures. The first statement can be correct while the second is false.
- Author: Marcin Borecki
- Tags: Engineering, Reliability & Telemetry, #eng22, #devinside-review

Historical edition · Sources and examples scoped to 2026-03-05.

The operation's current status is successful. The incident report says there were no failures. The first statement can be correct while the second is false.

One attempt timed out. A second attempt completed. If the application overwrites a single status row after each observation, the final row describes where the operation ended. It no longer describes the route taken to get there.

That can be an excellent current-state projection and a poor incident history. The problem begins when the same table is asked to answer both questions without preserving enough evidence for either distinction.

Play the event sequence in the model. A failed first attempt remains in the append-only history while the latest projection turns green after the second attempt. Then inject a duplicate, a conflicting event identity and a retention cutoff. The counts and projection are derived from the accepted events.

This is an event-ledger model, not a database benchmark or a distributed delivery guarantee. It demonstrates why final state, attempt history and retained evidence deserve separate contracts.

## Give the operation and the attempt different names

An operation is the intended outcome. An attempt is one execution undertaken toward it. An observation is a fact about an attempt or operation at a particular point in the protocol. These identities should not be collapsed because all three fit conveniently into one log line.

```csharp
public sealed record AttemptEvent(
    string EventId,
    string OperationId,
    int Attempt,
    long Sequence,
    string Kind,
    string? ErrorCode);

```

The sequence field needs a defined scope. A sequence increasing within one operation is not a global clock for unrelated work. A timestamp can help people navigate observations, but clock time alone may not provide the ordering guarantee the projection requires.

![Three identities describe different things](https://devinside.cloud/content/images/2026/11/devinside/v4/ENG22/three-identities.svg)

[Inspect the full diagram ↗](https://devinside.cloud/content/images/2026/11/devinside/v4/ENG22/three-identities.svg)Swipe the drawing to inspect it.

In the example, attempt one has a start and a failure observation; attempt two has a start and a completion observation. The operation eventually succeeds. Counting one failed attempt does not mean the operation's final outcome is failure, and counting one successful operation does not mean it consumed only one attempt.

## A projection is intentionally forgetful

A current-status projection can replace `Running` with `Failed`, then `Running` with `Succeeded`. It serves the reader who needs to know what to do now. The event log serves the engineer who needs to understand what happened before.

The projection is not defective merely because it omits previous states. It becomes misleading when it is presented as the only incident record. A green latest row cannot answer how often a dependency failed, whether retries overlapped, or which error preceded recovery.

The visual makes that forgetfulness visible. Each accepted event moves into the history. A copy updates the current-state slot, replacing its previous label. The replaced label remains in history rather than fading out of the system's explanation.

![The projection may forget; the history need not](https://devinside.cloud/content/images/2026/11/devinside/v4/ENG22/history-projection.svg)

[Inspect the full diagram ↗](https://devinside.cloud/content/images/2026/11/devinside/v4/ENG22/history-projection.svg)Swipe the drawing to inspect it.

## Persist history and its projection under one relevant boundary

If the application stores an event and updates its projection separately, a failure between those operations can leave them inconsistent. A small local database can often put both changes in one transaction. A distributed design may need another protocol, but it still needs an explicit recovery story.

```sql
BEGIN TRANSACTION;

-- Insert the new event only after checking identity consistency.
-- Advance the operation projection under its sequence rule.

COMMIT;

```

An UPSERT can help maintain a projection, but it does not decide whether an incoming observation is newer, duplicated or conflicting. SQLite's [3.24.0 release record](https://www.sqlite.org/releaselog/3%5F24%5F0.html?ref=devinside.cloud) establishes the historical availability of UPSERT support. The surrounding event semantics remain an application responsibility.

The important question is what a restart sees. If an accepted event exists, can the projection be reconstructed or checked against it? If the projection claims success but the relevant history is absent, can the system explain whether retention removed it or whether persistence failed?

## A duplicate is the same identity with the same meaning

Repeated delivery is common. The receiver can recognize an exact repeat without creating another event or another effect. But an existing event identity with a different payload is not a harmless duplicate.

One policy compares the canonical event content with the stored record. If they agree, acknowledge the duplicate. If they differ, reject the conflict and preserve the original. Silently overwriting the prior event would rewrite the explanation under a stable name.

```csharp
if (existing is not null && existing != incoming)
    throw new InvalidOperationException("Conflicting event identity.");

```

This fragment assumes value equality matches the canonical event contract. A production design must define normalization, optional fields and representation so that harmless encoding differences are not confused with semantic changes, while real changes are not normalized away.

![Identity reuse must preserve the same meaning](https://devinside.cloud/content/images/2026/11/devinside/v4/ENG22/duplicate-conflict.svg)

[Inspect the full diagram ↗](https://devinside.cloud/content/images/2026/11/devinside/v4/ENG22/duplicate-conflict.svg)Swipe the drawing to inspect it.

## Order is part of the projection contract

If an old failure arrives after a newer success, last-arrival-wins can regress the current status. A sequence-aware projection can refuse to replace a newer state with an older observation. The history can still record that the old observation arrived, according to the event and audit policy.

Do not assume that a queue's ordering promise solves every case. Retries, multiple partitions, different producers and replay can introduce other orderings. The application should state which ordering it requires and how it handles observations outside that contract.

The worked model uses a known per-operation sequence. It is not a general merge algorithm for arbitrary concurrent histories. That limitation is useful because it makes the expected current state independently calculable.

## Retention changes which questions remain answerable

Delete the first attempt's observations after the operation succeeds. The latest projection remains correct, but a query over retained history can no longer explain the initial timeout. It is wrong to reinterpret that missing evidence as proof that no timeout occurred.

Retention therefore needs query-level acceptance criteria. Which investigations must remain possible, for how long, and from which retained records or aggregates? A storage policy is an information policy because deletion can make a past question unanswerable.

![Deleting evidence changes answerable questions](https://devinside.cloud/content/images/2026/11/devinside/v4/ENG22/retention.svg)

[Inspect the full diagram ↗](https://devinside.cloud/content/images/2026/11/devinside/v4/ENG22/retention.svg)Swipe the drawing to inspect it.

The model reports both the accepted lifetime history and the currently retained subset so the difference is explicit. A real service may not retain both forever, but it should not let a shorter window silently change the meaning of a failure metric.

This also affects denominators. Failed attempts, failed operations and operations requiring retry are three different metrics. A system can have a low final failure rate while spending substantial time and resources on retries. All three can matter without any one being the universally correct number.

## Record uncertainty before the successful retry erases it

An attempt can end with an unknown effect: the caller timed out after sending work but cannot tell whether the receiver committed. That state deserves its own representation. Labeling it failed can encourage blind repetition; labeling it successful can skip necessary reconciliation.

If a later attempt resolves the operation, keep the relationship between the uncertainty and the resolution. The final success should not rewrite the earlier observation into something the caller did not know at the time.

The original contemporary laboratory includes actual transaction and reopen behavior separately. This historical edition uses a synthetic event sequence rather than importing those later execution results or elapsed times.

## Test explanation, not just the final color

After the modeled sequence, assert that the projection says success and that the first attempt's failure remains in history. Deliver the same event again and require no additional accepted event. Deliver a conflicting payload under the same event identity and require a visible refusal. Apply retention and verify which diagnostic query becomes incomplete.

Those tests protect different promises. A suite that checks only the final status can pass while the history becomes unreliable. A suite that checks only appended rows can pass while the current-state projection regresses.

The engineering goal is a system that can tell both stories accurately: what the user can rely on now, and what work and uncertainty led to that outcome. A successful retry is a reason to update the current state, not a reason to make the earlier failure disappear from the explanation.

GO FURTHER

## Inspect the contemporary laboratory.

This is a newly reconstructed historical edition, not a claim of earlier authorship. Later executed experiments, their exact environments and original results are preserved in a separate notebook.

[Open the current laboratory notebook ↗](https://devinside.cloud/lab-notebooks/v4/ENG22.html)

[Download the current reconstruction sources ↗](https://devinside.cloud/content/files/v4/ENG22-reconstruction.zip)