Build1 publisher3 min readPublished
Agents don't forget, they double-post: the case for action receipts over bigger context
A dev.to writeup argues the expensive agent bug is ambiguity after a timeout, and that durable per-action outcome records, not larger memory, are what stop duplicate writes.
The Engineer · Build desk
Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction

What happened
- A dev.to post argues that an AI agent can remember a 30-page conversation and still perform the same action twice.
- When a request times out, the agent remembers the goal, the plan and the tool call, but not whether the outside system changed, so it tries again.
- More context does not close the gap; a model can recall the exact request and still not know whether a server committed it before the connection disappeared.
- "Agent memory" often means conversation history, retrieved documents or durable project knowledge, which answer what the agent knew rather than what happened in another system.
- The author separates four layers; the first two help reasoning, and the last two prevent duplicate emails, repeated publications, double-created listings and other expensive retries.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
A developer post on dev.to makes a narrow and useful claim: an agent can hold a 30-page conversation and still perform the same action twice [1]. The reason is that when a request times out, the agent still knows its goal, its plan and the tool call it issued, but nothing about whether the outside system changed, so it tries again [2]. What most teams call agent memory means conversation history, retrieved documents, or durable project knowledge, and all of that answers what the agent knew rather than what happened somewhere else [4]. The author separates four layers and observes that the first two support reasoning while the last two are what prevent duplicate emails, repeated publications and double-created listings [5]. On that split, half the stack exists purely to keep the agent from acting twice [1]. More context does not close the gap: a model can recall the exact request and still not know whether a server committed it before the connection disappeared [3]. The asymmetry is the whole argument. Before submission, failure is simple, because nothing was sent and retrying may be safe [6]. After submission, a timeout, connection reset or unreadable response means either that the platform never received the request or that it completed the request and the response never came back [6]. Treating both as "failed" converts a transport problem into a duplicate-action bug [7]. The proposed fix is a state machine most happy-path workflows omit: planned to submitted, then succeeded, rejected, or outcome_unknown, with outcome_unknown moving into reconciling and out to succeeded, safe_to_retry or manual_review [8]. The author's point about outcome_unknown is the sharp one: it is not an error string to swallow but durable knowledge about the limit of what the system can currently prove [9]. The receipt must be written before the external request, because the exact failure that makes it valuable can otherwise prevent it from existing [10]. It carries an operation id, the operation and target, state, an intent fingerprint, submission time and an external id [11], with the fingerprint computed from an allowlisted or redacted view of the intent rather than from secrets [12]. That is not a log line: logs describe events, while a receipt is one record with a lifecycle that gets updated as knowledge changes [13]. The honest part of the post is the confession. The author's CLI writing to the DEV API already previewed mutations, demanded explicit confirmation, wrote a private intent file, and never retried a write after a network failure [14]. But the intent file stayed an intent file: success never advanced it to succeeded, ambiguity never advanced it to outcome_unknown, and the safety rule lived in the client while durable state lagged behind [15]. The corrected shape records intent, marks submitted, then writes rejected, outcome_unknown or succeeded with the returned external id [16]. There is deliberately no retry in the exception path, and tests treat success, explicit rejection and ambiguous failure as distinct receipt states [17]. Updates are replaced atomically through a private temporary file, so an interrupted process does not leave half a JSON document and turn the audit trail into its own ambiguous evidence [18]. Unknown outcomes get resolved with a read, not another write [19]: query by idempotency key or returned identifier, otherwise run a bounded search against the smallest safe fingerprint, mark succeeded when the effect exists, mark safe_to_retry only when absence is provable, and route everything else to manual review [20]. Only one of those three exits authorises a second write [2]. What to watch is your dependencies, not your model. The author notes that a platform with idempotency keys and exact read-after-write lookup is far easier to automate safely than one with neither [21], which makes that pair a procurement question for any endpoint your agents mutate.