{"record":{"id":"f7fdd0c48b1e1c5e","repo":"Hmbown/CodeWhale","slug":"invalid-pet-world-checkpoint","errorCode":null,"errorMessage":"Invalid pet world checkpoint.","messagePattern":"Invalid pet world checkpoint\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/tui/pet_watch/pet-native.js","lineNumber":365,"sourceCode":"            || !integer(c.branchTick, -1, c.tick) || !integer(c.random, 0, 0xffffffff)\n            || !['swim', 'dive', 'roll', 'breathe', 'drift', 'doze', 'wake'].includes(c.behaviour)\n            || !range(c.until, 0, pet_sim_js_1.PET_MAX_SECONDS + 10) || ![c.targetX, c.targetY, c.x, c.y, c.flip].every(n => range(n, -1, 1))\n            || !range(c.lit, 0, 1) || !range(c.lastActivity, 0, c.tick / HZ)\n            || c.addressedAt !== null && !range(c.addressedAt, 0, c.tick / HZ)\n            || !range(c.waitSince, -1, c.tick / HZ) || typeof c.lastStill !== 'string' || c.lastStill.length > 2048\n            || !Array.isArray(c.members) || c.members.length > 6\n            || c.members.some(m => !m || typeof m.id !== 'string' || !m.id || m.id.length > 4096\n                || !integer(m.slot, 0, 5) || !range(m.phase, 0, Math.PI * 2) || typeof m.present !== 'boolean')\n            || new Set(c.members.map(m => m.id)).size !== c.members.length || new Set(c.members.map(m => m.slot)).size !== c.members.length\n            || c.food !== null && (!c.food || !range(c.food.time, 0, c.tick / HZ) || ![c.food.x, c.food.y].every(n => range(n, -1, 1)))\n            || !c.frame || c.frame.timeMs !== c.tick * 1000 / HZ || c.frame.behaviour !== c.behaviour\n            || !['none', 'orient', 'approach', 'call'].includes(c.frame.needs)\n            || !range(c.frame.surface, -.9, -.8) || !range(c.frame.caustic, 0, 1)\n            || c.frame.food !== null && (!c.frame.food || !range(c.frame.food.x, -1, 1) || !range(c.frame.food.y, -1, 1.21) || !range(c.frame.food.life, 0, 1))\n            || JSON.stringify(c.frame.pod) !== JSON.stringify(c.members)\n            || !Array.isArray(c.voices) || c.voices.length > 1024\n            || c.voices.some(v => !v || typeof v.id !== 'string' || v.id.length > 256))\n            throw new Error('Invalid pet world checkpoint.');\n        (0, pet_sim_js_1.validatePetState)(c.frame.state);\n        (0, pet_audio_js_1.renderPetPCM)(c.voices, 0, 0);\n        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];","sourceCodeStart":347,"sourceCodeEnd":383,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tui/pet_watch/pet-native.js#L347-L383","documentation":"PetWorld's checkpoint deserializer validates every field of a restored snapshot (frame needs mode, surface/caustic ranges, food coordinates, pod membership, voices array and per-voice id) before rebuilding the world. If any field fails these structural or range checks the constructor throws so a corrupt or hand-edited checkpoint is never loaded. It is a load-time integrity gate for persisted pet-world state.","triggerScenarios":"Constructing a PetWorld from a checkpoint object `c` whose frame.needs is not one of none/orient/approach/call, whose frame.surface or frame.caustic is outside [-0.9,-0.8] / [0,1], whose food entry exists but has missing/out-of-range x,y or life, whose frame.pod JSON differs from the provided members list, or whose voices array exceeds 1024 entries or contains entries without a string id of length <= 256.","commonSituations":"Restoring checkpoints saved by an older pet-native version whose frame schema changed; hand-editing or truncating a checkpoint JSON; a storage layer that partially wrote the checkpoint; loading a checkpoint from a different pet whose pod roster does not match the members argument.","solutions":["Compare the failing checkpoint's frame against the validator field-by-field (needs, surface, caustic, food, pod, voices) and fix or regenerate the offending field.","Re-create the checkpoint by recording a fresh session instead of restoring the corrupt one.","Confirm the checkpoint and code versions match (petCheckpointVersion) and migrate old-format checkpoints before constructing PetWorld.","Validate the checkpoint with the same range/shape predicates before passing it to the constructor to get a precise field-level error."],"exampleFix":"// before: frame.pod drifted from members after roster change\nnew PetWorld(points, tape, interactions, c.sim?.expressionVersion ?? 1, true) // throws\n// after: rebuild checkpoint frame.pod to match current members before restore\nc.frame.pod = structuredClone(members);\nnew PetWorld(points, tape, interactions, c.sim?.expressionVersion ?? 1, true);","handlingStrategy":"validation","validationCode":"function isValidCheckpoint(c, members) {\n  const range = (v, lo, hi) => typeof v === 'number' && v >= lo && v <= hi;\n  const f = c?.frame;\n  if (!f || !['none','orient','approach','call'].includes(f.needs)) return false;\n  if (!range(f.surface, -0.9, -0.8) || !range(f.caustic, 0, 1)) return false;\n  if (f.food !== null && (!f.food || !range(f.food.x, -1, 1) || !range(f.food.y, -1, 1.21) || !range(f.food.life, 0, 1))) return false;\n  if (JSON.stringify(f.pod) !== JSON.stringify(members)) return false;\n  if (!Array.isArray(c.voices) || c.voices.length > 1024) return false;\n  return c.voices.every(v => v && typeof v.id === 'string' && v.id.length <= 256);\n}","typeGuard":"const isCheckpoint = (c) => !!c && typeof c === 'object' && c.frame !== null && typeof c.frame === 'object' && Array.isArray(c.voices);","tryCatchPattern":"try {\n  const world = new PetWorld(points, tape, interactions, ver, v2);\n} catch (e) {\n  if (e.message === 'Invalid pet world checkpoint.') {\n    console.error('checkpoint failed validation, re-recording');\n    world = startFreshWorld();\n  } else throw e;\n}","preventionTips":["Validate checkpoints at write time with the same predicates the constructor uses","Never hand-edit checkpoint JSON; regenerate from a live session","Keep petCheckpointVersion in sync with the code version and migrate old checkpoints","Write checkpoints atomically so partial frames are never persisted"],"tags":["validation","checkpoint","persistence"],"backgroundTag":"schema-validation-failed","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}