{
  "format": "recallweave-deck/1",
  "title": "Retries: one request, uncertain replies",
  "attribution": "Original RecallWeave questions, counter/register examples and worked explanations, 2026, authored with AI assistance. Conceptual references: RFC 9110 section 9.2.2, HTTP Semantics (https://www.rfc-editor.org/rfc/rfc9110.html#name-idempotent-methods); Malcolm Featonby, Amazon Builders' Library, Making retries safe with idempotent APIs (https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/). The fictional protocols are stated in each prompt; no source implementation, passage or exercise is reproduced.",
  "license": "CC0-1.0 for this original lesson wording and worked examples. Referenced sources retain their own terms and are not included. Educational review guidance remains in RecallWeave's AI-DISCLOSURE.md.",
  "concepts": [
    "Repeated state changes",
    "Operation identity",
    "Durable result records",
    "Limits of retry guarantees"
  ],
  "items": [
    {
      "id": "retry-increment-twice",
      "concept": "Repeated state changes",
      "prerequisites": [],
      "prompt": "A counter starts at 7. Every delivered ADD 3 command increments it by 3, with no duplicate detection. The same command is delivered and applied twice; nothing else runs. What is the final counter, and is this command idempotent for that state change?",
      "options": [
        "10; it is idempotent because the command text is unchanged.",
        "13; it is not idempotent because the second application changes the counter again.",
        "13; it is idempotent because both replies can say success.",
        "7; repeated command text automatically cancels both applications."
      ],
      "answer": 1,
      "explanation": "Each application adds 3 to the current value: 7 becomes 10, then 10 becomes 13. One application and two applications have different counter effects. Identical command text or identical success wording does not turn addition into an idempotent update.",
      "transfer": "Start at 7 and apply SET 10 twice instead. The values are 10 then 10. Compare intended state transitions, not whether two request strings happen to match."
    },
    {
      "id": "retry-assignment-twice",
      "concept": "Repeated state changes",
      "prerequisites": [],
      "prompt": "A register starts at 4. SET 12 replaces its value with 12. The same command is applied twice with no intervening operation. The service separately appends one audit entry for each delivery. Which statement correctly describes the requested register effect?",
      "options": [
        "The register becomes 24 because two deliveries add two copies of 12.",
        "The register effect is not idempotent because the audit has two entries.",
        "The register ends at 12; repeating SET 12 has the same requested register effect as applying it once.",
        "The register ends at 4 because an idempotent command cannot change state."
      ],
      "answer": 2,
      "explanation": "The first SET changes 4 to 12; the second leaves 12 at 12. That requested register effect is idempotent in the stated no-intervening-operation comparison. The two audit entries are separate delivery effects. Idempotent does not mean read-only, no logging, or no initial state change.",
      "transfer": "Suppose DELETE-if-present reports removed on its first delivery and already absent on its second. Different responses can accompany the same final requested absence; specify which effect you are comparing."
    },
    {
      "id": "retry-missing-reply",
      "concept": "Repeated state changes",
      "prerequisites": [],
      "prompt": "A client sends a non-idempotent increment once and times out without receiving a response. The protocol supplies no operation lookup or duplicate suppression. The increment might not have arrived, or it might have committed before its reply was lost. What does the timeout alone establish?",
      "options": [
        "The effect is unknown to the client; it does not prove either that the increment failed or that it committed.",
        "The server definitely made no change, so a retry cannot duplicate the increment.",
        "The increment definitely committed, so the client may report success.",
        "The server is guaranteed to undo any operation whose response is not received."
      ],
      "answer": 0,
      "explanation": "The client has observed a missing response, not the server's state. Both an undelivered request and a committed increment with a lost reply fit the observation. Reporting either definite failure or definite success would add information the timeout did not supply. An unprotected retry could add another increment if the first committed.",
      "transfer": "Name an observation that would resolve the uncertainty for a particular protocol, such as a trustworthy retained result lookup for the original operation ID. A newly invented ID does not identify the uncertain old operation."
    },
    {
      "id": "retry-historical-result",
      "concept": "Operation identity",
      "prerequisites": [
        "Repeated state changes"
      ],
      "prompt": "A teaching service keeps durable records keyed by exact operation ID. A first ID applies ADD n atomically with storing its result. A repeated ID with identical n returns that stored result without another addition. Starting at 0, ID A adds 2 and stores result 2; ID B then adds 5 and stores result 7. While both records remain, A with n=2 is received again. Which pair is correct?",
      "options": [
        "Reply 7; current counter 7.",
        "Reply 9; current counter 9.",
        "Reply 2; current counter 2.",
        "Reply 2; current counter 7."
      ],
      "answer": 3,
      "explanation": "A's retained result is 2, while B has since advanced the counter to 7. The declared replay rule returns A's historical result and does not reapply A or restore its former state. Returning 7 would be a current-state query, not the stipulated stored-result replay; adding again would produce 9 and violate this protocol.",
      "transfer": "After A's replay, imagine a separate current-value read. Under this trace it reports 7 while A's stored result remains 2. Label historical receipts and current observations separately."
    },
    {
      "id": "retry-changed-intent",
      "concept": "Operation identity",
      "prerequisites": [
        "Repeated state changes"
      ],
      "prompt": "A service binds each retained operation ID to its exact ADD amount and result. Same ID/same amount replays the stored result; same ID/different amount is refused without mutation. ID blue was accepted with amount 4, leaving the counter at 4. While that record remains, a caller sends blue with amount 9. What must this service do?",
      "options": [
        "Add 9 and silently update blue to the new request.",
        "Refuse the parameter mismatch and leave the counter at 4.",
        "Return the old result but replace the stored amount with 9.",
        "Apply an additional 5 so the counter matches the new requested amount."
      ],
      "answer": 1,
      "explanation": "The retained identity blue is already bound to amount 4. Amount 9 expresses a different operation under this contract, so the mismatch refuses before another effect or record change. The counter stays 4. Reusing a key is not permission to revise the original operation or silently choose one parameter set.",
      "transfer": "To intentionally request an additional ADD 9 under this service, use a new operation ID according to its contract. That creates another operation; it is not a repair of a lost reply for blue."
    },
    {
      "id": "retry-equal-parameters-new-ids",
      "concept": "Operation identity",
      "prerequisites": [
        "Repeated state changes"
      ],
      "prompt": "A counter starts at 1. A service suppresses repeats only when the exact caller and operation ID match a retained record; equal ADD amounts alone are not duplicates. One caller intentionally sends ID first with ADD 3 and then a different ID second with ADD 3. Both first deliveries are accepted. What is the counter?",
      "options": [
        "7; these are two distinct operations, each adding 3.",
        "4; identical amounts always mean the second request is a retry.",
        "1; requesting the same amount twice is a conflict.",
        "6; operation IDs replace the original counter value."
      ],
      "answer": 0,
      "explanation": "The caller deliberately chose two different IDs. Each first delivery therefore applies its ADD 3: 1 becomes 4 and then 7. Equal parameters can describe two separate intentions. A service that deduplicates by amount alone would suppress a legitimate second operation in this example.",
      "transfer": "Instead of sending ID second, repeat ID first with the same ADD 3 while its record remains. In that alternative trace, the counter stays at 4 after the replay because the identity, not just the parameters, matches."
    },
    {
      "id": "retry-caller-namespace",
      "concept": "Durable result records",
      "prerequisites": [
        "Operation identity"
      ],
      "prompt": "Two callers share a counter initially equal to 0. Deduplication records are keyed by the exact pair (caller, operation ID); each first pair atomically applies its ADD amount. Caller Ada sends (Ada, job-1), ADD 2. Caller Bo then sends (Bo, job-1), ADD 2. There are no other requests. What follows from this declared identity rule?",
      "options": [
        "Bo is refused because operation IDs are globally unique across all callers.",
        "Only Ada's request applies, so the counter is 2.",
        "Both distinct pairs apply, so the counter is 4.",
        "The counter becomes 1 because the repeated job-1 text replaces its value."
      ],
      "answer": 2,
      "explanation": "The keys are the complete pairs (Ada, job-1) and (Bo, job-1). They are distinct even though their second components match. Both first pairs add 2 to the shared counter, producing 4. This is the namespace rule stated by this service; an actual API's scope must be read rather than assumed.",
      "transfer": "If the same caller sends job-1 twice with the same amount while the record remains, only one first pair exists. State the namespace, identity comparison and retention rules before comparing keys."
    },
    {
      "id": "retry-record-effect-gap",
      "concept": "Durable result records",
      "prerequisites": [
        "Operation identity"
      ],
      "prompt": "A broken service durably changes a counter from 0 to 5 for operation K, then crashes before saving K's completion record. After restart the counter is still 5 but no K record exists. Its retry handler treats an absent record as a new ADD 5 and applies it. Which diagnosis fits this trace?",
      "options": [
        "A stored completion record is guaranteed whenever an effect is durable.",
        "The missing reply proves that the first addition was rolled back.",
        "Adding more client-side waiting would itself restore the lost record.",
        "The effect and its completion record were not committed together; the retry can make the counter 10."
      ],
      "answer": 3,
      "explanation": "The counter effect survived, but the record needed to recognize the same operation did not. Treating the retry as new adds a second 5, giving 10. This witness concerns the split commit boundary. Merely saving a record before an effect has the opposite possible gap—a record could survive without the effect—unless the declared operation makes both one atomic durable outcome.",
      "transfer": "Consider a record written durably before an addition that never commits. Replaying a success from that record would invent a completed effect. The teaching requirement concerns both pieces within one supported atomic boundary, not the order of two unrelated writes."
    },
    {
      "id": "retry-concurrent-check",
      "concept": "Durable result records",
      "prerequisites": [
        "Operation identity"
      ],
      "prompt": "A shared counter starts at 0. Workers W1 and W2 receive the same new operation ID K with ADD 1. Both first read 'no K record'. Without rechecking or an exclusive/atomic claim, W1 adds 1 and writes K; W2 then adds 1 and writes K. The counter increments themselves are atomic, so neither increment is lost. What does the final value show?",
      "options": [
        "The final value is 1 because atomic increments automatically deduplicate IDs.",
        "The final value is 2; a separate check followed by a write did not enforce one application for K.",
        "The final value is 0 because concurrent operations cancel.",
        "The final value is 2, which proves all later retries are safe even if records expire."
      ],
      "answer": 1,
      "explanation": "Both workers pass the absence check before either has established an exclusive claim. The two atomic counter increments therefore both occur and produce 2. Atomicity of each increment prevents a lost update; it does not make the earlier identity check and the effect one protected decision. Duplicate suppression needs a coordinated decision for the same identity under the service's stated contract.",
      "transfer": "Imagine that only one worker can atomically claim K and commit its effect/result, while the other receives the retained result. Then there is one application. That is a different synchronization rule from the two unprotected absence checks in the question."
    },
    {
      "id": "retry-retention-expiry",
      "concept": "Limits of retry guarantees",
      "prerequisites": [
        "Durable result records"
      ],
      "prompt": "A service applies ADD 2 for ID K once, changing a counter from 0 to 2. It retains K's deduplication record for exactly 60 seconds, then deletes that record without changing the counter. At 120 seconds an old identical K request arrives; this teaching service explicitly treats IDs with no current record as new. What happens, and what limit does this illustrate?",
      "options": [
        "The counter stays 2 because idempotency records necessarily last forever.",
        "The counter returns to 0 when the record expires.",
        "The counter becomes 4; duplicate suppression did not cover a retry after the stated retention window.",
        "The late request must be refused even though the stated handler treats it as new."
      ],
      "answer": 2,
      "explanation": "Deleting K's record does not reverse its first increment. At 120 seconds the handler sees no retained record and, by the explicit rule in the prompt, accepts another ADD 2, producing 4. The guarantee was limited by retained knowledge. Other services may refuse expired identifiers or use other rules; this result is not a universal expiry policy.",
      "transfer": "Before relying on an old ID, check the actual API's retention and expiry contract. A key's text can remain identical after the service has forgotten its history."
    },
    {
      "id": "retry-intervening-update",
      "concept": "Limits of retry guarantees",
      "prerequisites": [
        "Repeated state changes"
      ],
      "prompt": "SET v unconditionally replaces a register. SET 5 is idempotent when repeated with no intervening operation. Now apply this actual sequence: SET 5, then another writer's SET 9, then a delayed repeat of SET 5. There are no version checks or operation records. Which conclusion is correct?",
      "options": [
        "The final value is 5; idempotence of SET 5 alone does not protect the intervening writer's value.",
        "The final value is 9 because an idempotent command can never overwrite another update.",
        "The final value is 14 because assignments accumulate.",
        "The repeat is automatically rejected because its value is older."
      ],
      "answer": 0,
      "explanation": "The actual sequence is 5, then 9, then 5. Comparing SET 5 with its immediate repetition shows idempotence, but it does not make SET 5 commute with SET 9 or preserve another writer's intervening value. A version/precondition protocol could impose a different policy, but none is present in this trace.",
      "transfer": "Repeat SET 9 after SET 5 instead and the final value is 9. Order matters even though each individual assignment is idempotent under immediate repetition."
    },
    {
      "id": "retry-at-most-once-not-eventual",
      "concept": "Limits of retry guarantees",
      "prerequisites": [
        "Durable result records"
      ],
      "prompt": "A protocol guarantees at most one committed counter increment for each operation ID that it receives, while retaining the relevant records. A particular client's request is lost before reaching the service and is never delivered or retried. What can be concluded about that request?",
      "options": [
        "It must eventually increment the counter because duplicates are suppressed.",
        "It committed exactly once even though the service never received it.",
        "It must produce a success response after its record expires.",
        "It produces no increment; an at-most-once effect rule by itself does not guarantee eventual delivery or completion."
      ],
      "answer": 3,
      "explanation": "The service never receives this request, so it performs no increment for it. Zero effects satisfies at most one. That safety bound alone cannot make a lost message arrive, schedule another attempt, or guarantee eventual success. An exactly-once completion claim would require additional delivery, failure and durability assumptions beyond the stated bound.",
      "transfer": "A bounded retry policy can stop after several failures. Duplicate suppression may still hold while completion remains unknown or absent. Describe the observed result instead of treating a delivery guarantee as a consequence of the word idempotent."
    }
  ]
}
