{"record":{"id":"1ea6ccbeeaa9e3fb","repo":"Hmbown/CodeWhale","slug":"pet-checkpoint-telemetry-does-not-match-its-clock-native","errorCode":null,"errorMessage":"Pet checkpoint telemetry does not match its clock.","messagePattern":"Pet checkpoint telemetry does not match its clock\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"pet/ios/Resources/pet-native.js","lineNumber":386,"sourceCode":"        const world = new PetWorld(points, tape, interactions, c.sim?.expressionVersion ?? 1, c.petCheckpointVersion === 2);\n        if (c.petCheckpointVersion === 2) {\n            world.hasTelemetry = c.hasTelemetry;\n            world.origin = structuredClone(c);\n        }\n        if (c.history !== world.historyDigest()\n            || c.bucketIndex >= 0 && world.tape[c.bucketIndex].simTimeMs > c.frame.timeMs + 1e-7\n            // acceptTelemetry may fill past gaps after the most recent fixed tick.\n            // Preserve that pending cursor exactly; it may lag only over empty gaps.\n            || world.tape.some((b, i) => i > c.bucketIndex && b.simTimeMs <= c.frame.timeMs + 1e-7\n                && (b.observed !== 0 || b.channel !== 'other' || b.errors || b.waiting || b.agentIds.length\n                    || b.onsets.some(Boolean) || b.activeMs.some(Boolean)))\n            || world.interactionLog.slice(0, c.interactionIndex).some(e => e.timeMs > c.frame.timeMs + 1e-7)\n            || world.interactionLog[c.interactionIndex]?.timeMs <= c.frame.timeMs + 1e-7)\n            throw new Error('Pet checkpoint does not match its recording.');\n        const candidate = world.tape[c.bucketIndex];\n        const telemetry = candidate && c.frame.timeMs < candidate.simTimeMs + candidate.durationMs ? candidate : undefined;\n        if (JSON.stringify(c.frame.telemetry) !== JSON.stringify(telemetry))\n            throw new Error('Pet checkpoint telemetry does not match its clock.');\n        world.sim.restore(c.sim);\n        world.score.restore(c.score);\n        world.random.restore(c.random);\n        world.accumulator = c.accumulator;\n        world.tick = c.tick;\n        world.bucketIndex = c.bucketIndex;\n        world.interactionIndex = c.interactionIndex;\n        world.branchTick = c.branchTick;\n        world.behaviour = c.behaviour;\n        world.until = c.until;\n        world.targetX = c.targetX;\n        world.targetY = c.targetY;\n        world.x = c.x;\n        world.y = c.y;\n        world.flip = c.flip;\n        world.lit = c.lit;\n        world.lastActivity = c.lastActivity;\n        world.addressedAt = c.addressedAt ?? -Infinity;","sourceCodeStart":368,"sourceCodeEnd":404,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/pet/ios/Resources/pet-native.js#L368-L404","documentation":"After the cursor check passes, PetWorld re-derives which tape bucket should hold the checkpoint's telemetry: the bucket at bucketIndex whose sim clock window (simTimeMs..simTimeMs+durationMs) contains frame.timeMs. It then compares that bucket (or undefined when the frame falls past the bucket's window) byte-for-byte against the telemetry snapshotted in the checkpoint. A mismatch means the checkpoint's stored telemetry frame was not the one the tape would replay at that time — the checkpoint and the simulation clock disagree.","triggerScenarios":"Restoring a checkpoint whose frame.telemetry was captured from a different tape bucket than bucketIndex — typically after segmented acceptTelemetry spliced/replaced the bucket at that index, after the tape was rebuilt from a different recording, or a checkpoint whose timeMs crosses a bucket boundary that later changed.","commonSituations":"Accepting corrected live telemetry that overwrote the bucket a checkpoint pointed at; loading checkpoints from a previous recording session; simulating the world independently and restoring into a PetWorld with a different tape history.","solutions":["Take a new checkpoint after accepting or splicing telemetry; do not restore older ones","Verify the checkpoint's telemetry frame is JSON-identical to world.tape[bucketIndex] for the same timeMs before restoring","Rebuild the tape from the same recording the checkpoint was made from","Persist checkpoint and tapeLog together so they cannot diverge"],"exampleFix":"// before\nworld.restoreCheckpoint(cpFromYesterday); // tape bucket since overwritten\n// after\nconst bucket = world.tape[cpFromYesterday.bucketIndex];\nif (bucket && JSON.stringify(cpFromYesterday.frame.telemetry) === JSON.stringify(bucket)) {\n  world.restoreCheckpoint(cpFromYesterday);\n} else {\n  world.restoreCheckpoint(world.checkpoint());\n}","handlingStrategy":"validation","validationCode":"function telemetryMatches(world, c) {\n  const b = world.tape[c.bucketIndex];\n  const expected = b && c.frame.timeMs < b.simTimeMs + b.durationMs ? b : undefined;\n  return JSON.stringify(c.frame.telemetry) === JSON.stringify(expected);\n}","typeGuard":null,"tryCatchPattern":"try {\n  world.restoreCheckpoint(cp);\n} catch (e) {\n  if (e.message.includes('telemetry does not match')) cp = world.checkpoint();\n  else throw e;\n}","preventionTips":["Archive the tape together with checkpoints so buckets cannot be overwritten under them","Re-checkpoint after segmented acceptTelemetry replaces any bucket","Verify tape/recording identity before restoring a foreign checkpoint"],"tags":["replay","telemetry","checkpoint"],"backgroundTag":"internal-invariant-violation","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-22T16:17:23.217Z"}