{"record":{"id":"6db1b40713814615","repo":"Hmbown/CodeWhale","slug":"invalid-pet-checkpoint-world","errorCode":null,"errorMessage":"Invalid pet checkpoint.","messagePattern":"Invalid pet checkpoint\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"pet/src/core/pet-world.ts","lineNumber":141,"sourceCode":"      frame: this.frame, voices: this.voices });\n  }\n\n  recording(withCheckpoint = true, completed = false): PetRecording {\n    const tapeEnd = completed ? this.bucketIndex + 1 : this.tapeLog.length;\n    const inputEnd = completed ? this.interactionIndex : this.interactionLog.length;\n    const history = this.historyDigest(tapeEnd, inputEnd);\n    return { petReplayVersion: this.segmented ? 2 : 1, expressionVersion: this.sim.expressionVersion,\n      tape: this.tapeLog.slice(0, tapeEnd), interactions: this.interactionLog.slice(0, inputEnd).map(e => ({ ...e })),\n      ...(this.origin ? { start: { ...structuredClone(this.origin), hasTelemetry: this.hasTelemetry, history } } : {}),\n      ...(withCheckpoint ? { checkpoint: { ...this.checkpoint(), history } } : {}) };\n  }\n\n  static fromRecording(points: [number, number][], value: unknown): PetWorld {\n    const r = value as PetRecording;\n    if (!r || ![1, 2].includes(r.petReplayVersion) || !Array.isArray(r.tape) || !Array.isArray(r.interactions)) throw new Error('Invalid pet recording.');\n    const version = r.expressionVersion === undefined ? 1 : r.expressionVersion;\n    if (![1, 2].includes(version)) throw new Error('Unsupported pet expression version.');\n    if (r.checkpoint !== undefined && !r.checkpoint || r.start !== undefined && !r.start) throw new Error('Invalid pet checkpoint.');\n    for (const c of [r.start, r.checkpoint]) if (c && (c.sim?.expressionVersion ?? 1) !== version) throw new Error('Pet expression version does not match its checkpoint.');\n    if (r.petReplayVersion === 1 && (r.start || r.checkpoint && r.checkpoint.petCheckpointVersion !== 1)) throw new Error('Invalid legacy pet recording.');\n    if (r.petReplayVersion === 2 && (!r.start || r.start.petCheckpointVersion !== 2 || r.start.historyStart !== r.start.tick)) 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) throw new Error('Pet segment checkpoints do not agree.');\n      world.origin = first.checkpoint();\n    }\n    return world;\n  }\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(): PetSegment {\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] as [number, number]);","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/pet/src/core/pet-world.ts#L123-L159","documentation":"fromRecording validates optional checkpoint fields: if start or checkpoint keys are present they must be truthy values, otherwise the recording is malformed. Note the sibling errors 'Invalid legacy pet recording' and 'The recording segment is missing its starting checkpoint' cover version-specific checkpoint violations.","triggerScenarios":"Passing a recording where r.checkpoint is defined but null/empty, or r.start is defined but null/empty — e.g. { checkpoint: null } after a failed serialization.","commonSituations":"A save routine that wrote the key but failed to serialize the checkpoint; manual JSON editing that blanked a checkpoint; partial writes from a crashed process.","solutions":["Remove the empty start/checkpoint key entirely (undefined means absent) instead of writing null.","Fix the save path so a checkpoint is either fully serialized or omitted.","Re-export the recording from the app.","Validate checkpoints are truthy objects before loading."],"exampleFix":"// before\nsave({ ...recording, checkpoint: null });\n// after\nsave({ ...recording, checkpoint: undefined }); // or omit the key entirely","handlingStrategy":"type-guard","validationCode":"function hasValidCheckpoints(rec) { return (rec.checkpoint === undefined || !!rec.checkpoint) && (rec.start === undefined || !!rec.start); }\nif (!hasValidCheckpoints(rec)) rec = { ...rec, checkpoint: rec.checkpoint || undefined, start: rec.start || undefined };","typeGuard":"const isCheckpoint = (c) => !!c && typeof c === 'object' && typeof c.petCheckpointVersion === 'number';","tryCatchPattern":"try { PetWorld.fromRecording(points, rec); } catch (e) { if (e.message === 'Invalid pet checkpoint.') reloadFromExport(); }","preventionTips":["When serializing, omit empty checkpoint keys instead of writing null.","Use a save routine that writes checkpoint and data atomically."],"tags":["validation","deserialization"],"backgroundTag":"schema-validation-failed","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}