{"record":{"id":"718384ced5a08757","repo":"Hmbown/CodeWhale","slug":"invalid-legacy-pet-recording","errorCode":null,"errorMessage":"Invalid legacy pet recording.","messagePattern":"Invalid legacy pet recording\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/tui/pet_watch/pet-native.js","lineNumber":258,"sourceCode":"        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    static fromRecording(points, value) {\n        const r = value;\n        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();","sourceCodeStart":240,"sourceCodeEnd":276,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tui/pet_watch/pet-native.js#L240-L276","documentation":"Version 1 (legacy, non-segmented) recordings must be self-contained from tick 0: they must not carry a start checkpoint, and any checkpoint they carry must be a v1 checkpoint (petCheckpointVersion === 1). If a legacy recording contains a start, or its checkpoint claims a newer checkpoint version, it is neither a valid v1 recording nor a valid v2 segment and is rejected.","triggerScenarios":"Calling `PetWorld.fromRecording(points, r)` with r.petReplayVersion === 1 while either r.start is set, or r.checkpoint is set with r.checkpoint.petCheckpointVersion !== 1.","commonSituations":"A v2 segment file renamed or mislabeled as v1; a producer writing checkpointVersion 2 checkpoints into legacy recordings; mixing fields from v1 and v2 exports during a manual migration.","solutions":["Set petReplayVersion to 2 if the recording genuinely has a start checkpoint and v2 checkpoint format.","Remove the start key and use a v1 (petCheckpointVersion 1) checkpoint if it truly is a legacy recording.","Re-export the recording from the app version that produced it so version fields are self-consistent.","Do not hand-merge v1 and v2 recording fields; regenerate the file instead."],"exampleFix":"// before\n{ petReplayVersion: 1, start: {...}, checkpoint: { petCheckpointVersion: 2, ... } } // throws\n// after\n{ petReplayVersion: 2, start: {...}, checkpoint: { petCheckpointVersion: 2, ... } }","handlingStrategy":"validation","validationCode":"if (r.petReplayVersion === 1 && (r.start || (r.checkpoint && r.checkpoint.petCheckpointVersion !== 1)))\n  throw new Error('File is a v2-style recording labeled v1');","typeGuard":null,"tryCatchPattern":"try {\n  world = PetWorld.fromRecording(points, r);\n} catch (err) {\n  if (err.message === 'Invalid legacy pet recording.') {\n    // try re-labeled as v2 segment\n    world = PetWorld.fromRecording(points, { ...r, petReplayVersion: 2 });\n  } else throw err;\n}","preventionTips":["Never rename or relabel recording files between format versions.","Keep v1 checkpoints (petCheckpointVersion 1) out of v1 recordings' start field.","Migrate legacy files with an explicit conversion step, not by editing fields.","Store the producing app version with the file for provenance."],"tags":["versioning","legacy","deserialization"],"backgroundTag":"incompatible-source-type","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T16:17:23.217Z"}