{"record":{"id":"1aec00fc157a2e19","repo":"thedotmack/claude-mem","slug":"sync-hub-status-projected-seq-exceeds-head-seq","errorCode":null,"errorMessage":"sync hub status: projected_seq exceeds head_seq","messagePattern":"sync hub status: projected_seq exceeds head_seq","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/services/sync/CloudSync.ts","lineNumber":683,"sourceCode":"      if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n        throw new Error('sync hub status: response must be an object');\n      }\n      const record = parsed as Record<string, unknown>;\n      if (record.protocol_version !== 2) {\n        throw new Error('sync hub status: response requires protocol_version 2');\n      }\n      if (\n        typeof record.epoch !== 'string'\n        || typeof record.head_seq !== 'string'\n        || typeof record.projected_seq !== 'string'\n      ) {\n        throw new Error('sync hub status: response requires decimal-string epoch/head_seq/projected_seq');\n      }\n      const epoch = assertCanonicalDecimal(record.epoch, { positive: true });\n      const headSeq = assertCanonicalDecimal(record.head_seq);\n      const projectedSeq = assertCanonicalDecimal(record.projected_seq);\n      if (compareCanonicalDecimals(projectedSeq, headSeq) > 0) {\n        throw new Error('sync hub status: projected_seq exceeds head_seq');\n      }\n      this.hubStatus = {\n        checkedAt,\n        reachable: true,\n        epoch,\n        headSeq,\n        projectedSeq,\n        error: null,\n      };\n    } catch (error) {\n      const raw = error instanceof Error ? error.message : String(error);\n      const safe = this.token === '' ? raw : raw.split(this.token).join('[REDACTED]');\n      this.hubStatus = {\n        checkedAt,\n        reachable: false,\n        epoch: null,\n        headSeq: null,\n        projectedSeq: null,","sourceCodeStart":665,"sourceCodeEnd":701,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/services/sync/CloudSync.ts#L665-L701","documentation":"Within a given epoch, projected_seq must never exceed head_seq (projection cannot run ahead of the head). probeHubStatus compares the two canonical decimals and throws 'sync hub status: projected_seq exceeds head_seq' when the hub reports an inconsistent state, refusing to build sync decisions on it.","triggerScenarios":"Hub returns projected_seq > head_seq, typically from a race between head advancement and projection publication, or from a buggy/reset head counter on the hub.","commonSituations":"Hub crash/recovery resetting head_seq while projections persisted, concurrent writers racing during compaction, clock/counter corruption after failover, hand-crafted status fixtures.","solutions":["Treat the hub as inconsistent: re-probe after a short delay to see if the hub self-corrects.","Check hub logs for head-sequence resets or failover events and repair hub state (recompute projected_seq or rebuild from the log).","Verify hub write ordering guarantees: head_seq must be advanced atomically before/with projected_seq updates.","If reproducible, report/fix the hub race where projection can be observed ahead of head."],"exampleFix":"// before (hub, unsynchronized writes)\nawait store.set('projected_seq', nextProjected);\nawait store.set('head_seq', nextHead);\n// after: advance head first, then projection\nawait store.set('head_seq', nextHead);\nawait store.set('projected_seq', Math.min(nextProjected, nextHead));","handlingStrategy":"validation","validationCode":"function seqOrderOk(status: { head_seq: string; projected_seq: string }): boolean {\n  return compareCanonicalDecimals(status.projected_seq, status.head_seq) <= 0;\n}\nif (!seqOrderOk(status)) throw new Error('hub reported projected_seq > head_seq; hub state inconsistent');","typeGuard":null,"tryCatchPattern":"try {\n  const status = await cloudSync.statusWithHubProbe();\n} catch (e) {\n  if (e.message === 'sync hub status: projected_seq exceeds head_seq') {\n    logger.error('hub invariant violated; re-probing after backoff', { hubUrl });\n    await sleep(5000);\n    status = await cloudSync.statusWithHubProbe();\n  } else throw e;\n}","preventionTips":["Advance head_seq atomically before publishing projected_seq on the hub","Verify hub state after crash recovery/failover (recompute projected_seq)","Re-probe once before treating this as a permanent hub fault — races can self-heal","Add hub-side invariant assertions: projected_seq must never exceed head_seq"],"tags":["consistency","sync-hub","invariant"],"backgroundTag":"value-out-of-range","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}