{"record":{"id":"6fdf5b551314a1e3","repo":"Hmbown/CodeWhale","slug":"pet-segment-checkpoints-do-not-agree-native","errorCode":null,"errorMessage":"Pet segment checkpoints do not agree.","messagePattern":"Pet segment checkpoints do not agree\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"pet/ios/Resources/pet-native.js","lineNumber":265,"sourceCode":"        if (!r || ![1, 2].includes(r.petReplayVersion) || !Array.isArray(r.tape) || !Array.isArray(r.interactions))\n            throw new Error('Invalid pet recording.');\n        const version = r.expressionVersion === undefined ? 1 : r.expressionVersion;\n        if (![1, 2].includes(version))\n            throw new Error('Unsupported pet expression version.');\n        if (r.checkpoint !== undefined && !r.checkpoint || r.start !== undefined && !r.start)\n            throw new Error('Invalid pet checkpoint.');\n        for (const c of [r.start, r.checkpoint])\n            if (c && (c.sim?.expressionVersion ?? 1) !== version)\n                throw new Error('Pet expression version does not match its checkpoint.');\n        if (r.petReplayVersion === 1 && (r.start || r.checkpoint && r.checkpoint.petCheckpointVersion !== 1))\n            throw new Error('Invalid legacy pet recording.');\n        if (r.petReplayVersion === 2 && (!r.start || r.start.petCheckpointVersion !== 2 || r.start.historyStart !== r.start.tick))\n            throw new Error('The recording segment is missing its starting checkpoint.');\n        const first = r.start && PetWorld.restore(points, r.tape, r.interactions, r.start);\n        const world = r.checkpoint ? PetWorld.restore(points, r.tape, r.interactions, r.checkpoint) : first ?? new PetWorld(points, r.tape, r.interactions, version);\n        if (first) {\n            if (!world.segmented || world.tick < first.tick || r.checkpoint && r.checkpoint.historyStart !== first.tick)\n                throw new Error('Pet segment checkpoints do not agree.');\n            world.origin = first.checkpoint();\n        }\n        return world;\n    }\n    /** Retire only consumed input. The exact origin makes each archived segment\n     * independently replayable; no particle, random stream or score is reset. */\n    prepareSegment() {\n        const dropTape = Math.max(0, this.bucketIndex), dropInputs = this.interactionIndex, previous = this.origin;\n        const tape = this.tapeLog.slice(dropTape), interactions = this.interactionLog.slice(dropInputs);\n        const points = this.sim.p.map(p => [p.hx, p.hy]);\n        const c = this.checkpoint();\n        c.petCheckpointVersion = 2;\n        c.historyStart = this.tick;\n        c.hasTelemetry = this.hasTelemetry;\n        c.bucketIndex -= dropTape;\n        c.interactionIndex = 0;\n        c.history = new PetWorld(points, tape, interactions, this.sim.expressionVersion, true).historyDigest();\n        const next = PetWorld.restore(points, tape, interactions, c);","sourceCodeStart":247,"sourceCodeEnd":283,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/pet/ios/Resources/pet-native.js#L247-L283","documentation":"When a v2 recording has both a start checkpoint and a later checkpoint, fromRecording restores the world from the later checkpoint and cross-checks it against the start: the restored world must be segmented, its tick must not precede the start tick, and if a checkpoint exists its historyStart must equal the start tick. Any mismatch means the two checkpoints describe inconsistent segment boundaries.","triggerScenarios":"Passing a v2 recording where checkpoint.historyStart !== start.tick, where the restored world is not segmented, or where world.tick < start.tick.","commonSituations":"Combining chunks from two different export sessions; an interrupted archive/commit in prepareSegment leaving mismatched halves; editing ticks or historyStart by hand; re-serializing only part of the recording.","solutions":["Re-export the whole segment from a single PetWorld via prepareSegment()/recording(true, true) so start and checkpoint agree.","Ensure chunk reassembly covers one contiguous export session (same world, uninterrupted ticks).","Remove the mid-recording checkpoint and keep only start, letting fromRecording replay from the start.","Verify checkpoint.historyStart equals start.tick before importing."],"exampleFix":"// before\nconst mixed = { ...segA, checkpoint: segB.checkpoint }; // checkpoints from different sessions\n// after\nif (mixed.checkpoint.historyStart !== mixed.start.tick) throw new Error('segments do not belong together');\nconst world = PetWorld.fromRecording(points, { ...mixed, checkpoint: undefined }); // replay from start","handlingStrategy":"validation","validationCode":"if (r.start && r.checkpoint) {\n  if (r.checkpoint.historyStart !== r.start.tick) throw new Error('checkpoints disagree');\n  if (r.checkpoint.tick < r.start.tick) throw new Error('checkpoint precedes start');\n}","typeGuard":"const checkpointsAgree = (r: any) => !r.start || !r.checkpoint ||\n  r.checkpoint.historyStart === r.start.tick && r.checkpoint.tick >= r.start.tick;","tryCatchPattern":"try { world = PetWorld.fromRecording(points, r); }\ncatch (e) {\n  if (e.message === 'Pet segment checkpoints do not agree.') {\n    delete r.checkpoint; // replay from start instead of trusting the bad checkpoint\n    world = PetWorld.fromRecording(points, r);\n  } else throw e;\n}","preventionTips":["Never merge chunks or checkpoints from two different export sessions.","Complete prepareSegment commits atomically; discard partial archives.","Keep segment archives immutable once written."],"tags":["consistency","segmentation","replay"],"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"}