{"record":{"id":"49366716118d2543","repo":"stablyai/orca","slug":"codex-reset-attempt-journal-identity-changed","errorCode":null,"errorMessage":"Codex reset attempt journal identity changed","messagePattern":"Codex reset attempt journal identity changed","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mobile/src/storage/codex-reset-attempt-journal.ts","lineNumber":173,"sourceCode":"    // Why: the key must survive a committed provider mutation whose response is\n    // lost; no reset RPC may start until this write has completed successfully.\n    await AsyncStorage.setItem(key, JSON.stringify(attempt))\n    return attempt\n  })\n}\n\nexport async function clearCodexResetAttemptAfterAuthoritativeResponse(\n  identity: AttemptIdentity & { idempotencyKey: string }\n): Promise<void> {\n  return withScopeMutation(identity, async () => {\n    const key = storageKey(identity)\n    const raw = await AsyncStorage.getItem(key)\n    if (raw === null) {\n      return\n    }\n    const current = parseAttempt(raw, identity)\n    if (current.idempotencyKey !== identity.idempotencyKey) {\n      throw new Error('Codex reset attempt journal identity changed')\n    }\n    await AsyncStorage.removeItem(key)\n  })\n}\n\n/** Test-only: drain in-memory queues while preserving the durable storage mock. */\nexport function resetCodexResetAttemptJournalForTests(): void {\n  scopeMutations.clear()\n}\n","sourceCodeStart":155,"sourceCodeEnd":183,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/mobile/src/storage/codex-reset-attempt-journal.ts#L155-L183","documentation":"Thrown by `clearCodexResetAttemptAfterAuthoritativeResponse` when the stored attempt's `idempotencyKey` does not equal the `identity.idempotencyKey` passed in. The clear is meant to run only after the authoritative provider response confirms a specific attempt completed; a mismatch means a different/older attempt is in the journal (a newer reset started, or the wrong key was supplied) and clearing it would delete state still needed for in-flight idempotency.","triggerScenarios":"Calling clear with an `idempotencyKey` that differs from the one persisted: a second reset created a new attempt (new key) between the original reset and this clear, or the caller is clearing with a stale/incorrect key.","commonSituations":"User retried the reset before the first response arrived, generating a new idempotency key; the clear callback fired with an old captured key after a key rotation; concurrent reset attempts racing through the serialized `withScopeMutation` queue.","solutions":["Pass the exact `idempotencyKey` returned by `getOrCreateCodexResetAttempt` that corresponds to the response being confirmed.","If a new reset superseded the old one, do not clear — the new attempt still needs its journal entry.","Ensure only one reset flow is in flight per account scope at a time (the `withScopeMutation` queue serializes, but distinct callers should coordinate keys).","Capture the idempotency key at attempt-creation time and thread the same value through to the clear call."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Thread the exact key from creation through to clear.\nconst attempt = await getOrCreateCodexResetAttempt(identity)\n// ...perform reset with attempt.idempotencyKey...\nawait clearCodexResetAttemptAfterAuthoritativeResponse({ ...identity, idempotencyKey: attempt.idempotencyKey })","typeGuard":null,"tryCatchPattern":"try {\n  await clearCodexResetAttemptAfterAuthoritativeResponse({ ...identity, idempotencyKey })\n} catch (err) {\n  if (err instanceof Error && err.message === 'Codex reset attempt journal identity changed') {\n    // a newer attempt superseded this one — do not clear; leave journal intact\n  } else throw err\n}","preventionTips":["Capture the idempotency key at creation and pass the same instance to clear.","Prevent concurrent reset flows per account scope so keys don't rotate mid-flight.","Treat a mismatch as 'do not clear' — the current attempt still needs its journal entry."],"tags":["storage","idempotency","concurrency","identity"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}