{"record":{"id":"60ec1ff581ef1cda","repo":"thedotmack/claude-mem","slug":"sync-hub-push-acknowledgment-seq-exceeds-head-seq","errorCode":null,"errorMessage":"sync hub push: acknowledgment seq exceeds head_seq","messagePattern":"sync hub push: acknowledgment seq exceeds head_seq","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/services/sync/CloudSync.ts","lineNumber":1074,"sourceCode":"    for (const [key, expected] of sentCounts) {\n      const actual = ackCounts.get(key) ?? 0;\n      if (actual !== expected) {\n        throw new Error(\n          `sync hub push: 200 response acknowledgment multiplicity mismatch (expected ${expected}, received ${actual})`\n        );\n      }\n    }\n    if (ackCounts.size !== sentCounts.size) {\n      // Defensive: the unknown-tuple branch above should make this impossible.\n      throw new Error('sync hub push: 200 response acknowledgment multiset mismatch');\n    }\n\n    if (compareCanonicalDecimals(response.head_seq, response.projected_seq) > 0) {\n      throw new Error('sync hub push: checkpoint order requires head_seq <= projected_seq');\n    }\n    for (const ack of response.acked) {\n      if (compareCanonicalDecimals(ack.seq, response.head_seq) > 0) {\n        throw new Error('sync hub push: acknowledgment seq exceeds head_seq');\n      }\n      if (compareCanonicalDecimals(ack.seq, response.projected_seq) > 0) {\n        throw new Error('sync hub push: sent operation is not covered by projected_seq');\n      }\n    }\n  }\n\n  /**\n   * Stamp rows / delete outbox entries for a fully validated acknowledgment\n   * multiset. The hub may return entries in any order.\n   */\n  private stampAcked(acked: AckedOp[], pushed: WireOp[]): void {\n    const now = Date.now();\n    const bodies = new Map(pushed.map(op => {\n      const body = parseCanonicalOperation(op);\n      return [operationTupleKey({\n        id: body.id,\n        kind: body.kind,","sourceCodeStart":1056,"sourceCodeEnd":1092,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/e2d1df569a8f04075d40e92461128ece7cf04c82/src/services/sync/CloudSync.ts#L1056-L1092","documentation":"An acked operation's seq is greater than the head_seq reported in the same response — the hub acknowledged a log position beyond the durable head it itself declares. Internal inconsistency; caught before stampAcked, so nothing changes locally and flush() retries with backoff.","triggerScenarios":"head_seq computed from a stale replica while acks carry fresh seqs; a hub bug computing head_seq before the append transaction commits; log truncation/rollback between computing head and emitting acks.","commonSituations":"Hub scaled to multi-replica reads without read-your-writes; a hub refactor reordered head computation vs append; snapshot isolation issues in the hub's response assembly.","solutions":["Reproduce with a single-op push and compare ack.seq against reported head_seq","On the hub, derive head_seq and ack seqs from one consistent point (same transaction/read) when assembling the response","Ensure reads for the response come from the authoritative log, not a lagging replica","Redeploy the fixed hub; clients recover automatically on the next retry"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Hub-side self-check: no ack may outrun the reported head:\nconst maxAckSeq = acked.reduce((m, a) => (BigInt(a.seq) > BigInt(m) ? a.seq : m), '0');\nif (BigInt(maxAckSeq) > BigInt(headSeq)) throw new Error('ack seq beyond head — refuse to respond');","typeGuard":"function acksWithinHead(acked: { seq: string }[], head_seq: string): boolean {\n  return acked.every(a => BigInt(a.seq) <= BigInt(head_seq));\n}","tryCatchPattern":"if (/acknowledgment seq exceeds head_seq/.test(sync.status().lastError ?? '')) {\n  // inconsistent response assembly on the hub: compute head and acks from one transaction/read\n}","preventionTips":["Assemble the push response (acks, head_seq, projected_seq) from a single consistent snapshot","Never read sequence fields from lagging replicas for the response path","Add a hub invariant test covering concurrent appends during response assembly"],"tags":["sync","hub","integrity","sequence","ack","invariant"],"backgroundTag":"sequence-invariant-violation","analyzedSha":"e2d1df569a8f04075d40e92461128ece7cf04c82","analyzedAt":"2026-08-20T23:58:13.836Z","contentChangedAt":"2026-08-20T23:58:13.836Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}