{"record":{"id":"80ab0bb9ce25f8f1","repo":"Hmbown/CodeWhale","slug":"invalid-pet-world-checkpoint-80ab0b","errorCode":null,"errorMessage":"Invalid pet world checkpoint.","messagePattern":"Invalid pet world checkpoint\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"pet/src/core/pet-world.ts","lineNumber":237,"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_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    validatePetState(c.frame.state);\n    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) { world.hasTelemetry = c.hasTelemetry!; world.origin = structuredClone(c); }\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)) throw new Error('Pet checkpoint telemetry does not match its clock.');\n    world.sim.restore(c.sim); world.score.restore(c.score); world.random.restore(c.random);","sourceCodeStart":219,"sourceCodeEnd":255,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/pet/src/core/pet-world.ts#L219-L255","documentation":"PetWorld.restore performs deep validation of a checkpoint before rebuilding a world: frame field ranges and enums, food bounds, pod matching the member list, voice limits/ids, pet state, and more. If any structural invariant of the checkpoint blob fails, restore refuses to construct a world from corrupted or foreign data.","triggerScenarios":"Calling PetWorld.restore(points, tape, interactions, c) with a checkpoint whose frame fields are out of range, frame.pod differs from c.members, voices exceed 1024 entries or have invalid ids, or which was produced by a different/older schema.","commonSituations":"Hand-edited or partially serialized checkpoints; truncation during storage; loading a checkpoint saved by another app version whose schema drifted; JSON round-trips that drop undefined fields.","solutions":["Obtain checkpoints only from world.checkpoint()/recording() output of a matching library version.","Verify the checkpoint blob was stored/loaded losslessly (no truncation, no manual edits).","If migrating across versions, run the checkpoint through the library's migration/validation path before restore."],"exampleFix":"// before\nconst c = JSON.parse(partialString); // truncated\nPetWorld.restore(points, tape, interactions, c); // throws\n// after\nif (!isPetCheckpoint(c)) throw new Error('not a checkpoint');\nconst world = PetWorld.restore(points, tape, interactions, c);","handlingStrategy":"type-guard","validationCode":"// Structural pre-check before restore:\nif (!c?.frame || !['none','orient','approach','call'].includes(c.frame.needs) ||\n    !Array.isArray(c.voices) || c.voices.length > 1024 ||\n    JSON.stringify(c.frame.pod) !== JSON.stringify(c.members))\n  throw new Error('checkpoint fails structural pre-check');","typeGuard":"function isPetCheckpoint(v: unknown): v is PetCheckpoint {\n  const c = v as PetCheckpoint;\n  return !!c && !!c.frame && typeof c.frame.timeMs === 'number' &&\n    Array.isArray(c.voices) && c.voices.length <= 1024 &&\n    (!c.petCheckpointVersion || [1, 2].includes(c.petCheckpointVersion));\n}","tryCatchPattern":"try {\n  const world = PetWorld.restore(points, tape, interactions, c);\n} catch (e) {\n  if (e.message === 'Invalid pet world checkpoint.') {\n    // discard corrupted blob or re-export from the source world\n  } else throw e;\n}","preventionTips":["Only feed library-produced checkpoint blobs into restore.","Guard storage against truncation (checksum the blob).","Validate checkpoints at load time before restore."],"tags":["checkpoint","schema-validation","restore"],"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-23T08:17:48.524Z"}