{"record":{"id":"a6c67486d685b411","repo":"Hmbown/CodeWhale","slug":"world-requires-contiguous-version-1-pet-buckets-native","errorCode":null,"errorMessage":"World requires contiguous version 1 pet buckets.","messagePattern":"World requires contiguous version 1 pet buckets\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"pet/ios/Resources/pet-native.js","lineNumber":210,"sourceCode":"    get startTimeMs() { return this.origin?.frame.timeMs ?? 0; }\n    get endTimeMs() { return Math.max(this.frame.timeMs, (this.tapeLog.at(-1)?.simTimeMs ?? 0) + 400); }\n    get needsSegment() {\n        return !this.segmented && this.tapeLog.length < 1024 && this.interactionLog.length < 4096\n            || this.bucketIndex >= 1024 || this.interactionIndex >= 4096;\n    }\n    constructor(points, tape = [], interactions = [], expressionVersion = 2, segmented = false) {\n        if (tape.length > 216_000 || interactions.length > 100_000)\n            throw new Error('Pet recording exceeds its input limit.');\n        this.sim = new pet_sim_js_1.PetSim(points, 0xC0FFEE, expressionVersion);\n        this.segmented = segmented;\n        this.hasTelemetry = tape.length > 0;\n        this.tapeLog = structuredClone([...tape]);\n        this.interactionLog = structuredClone([...interactions]);\n        for (let i = 0; i < this.tape.length; i++) {\n            const b = this.tape[i];\n            (0, pet_telemetry_js_1.validatePetBucket)(b);\n            if (segmented ? i > 0 && b.sequence <= this.tape[i - 1].sequence : b.sequence !== i)\n                throw new Error('World requires contiguous version 1 pet buckets.');\n        }\n        for (let i = 0; i < this.interactionLog.length; i++) {\n            const e = this.interactionLog[i];\n            if (!Number.isFinite(e.timeMs) || e.timeMs < 0 || i > 0 && e.timeMs < this.interactionLog[i - 1].timeMs\n                || !['attention', 'food'].includes(e.kind) || !Number.isFinite(e.x) || !Number.isFinite(e.y)\n                || Math.abs(e.x) > 1 || Math.abs(e.y) > 1)\n                throw new Error('Invalid pet interaction.');\n        }\n        this.hashTape(0);\n        this.frame = this.makeFrame(0);\n        this.voices = this.score.voices(this.frame);\n        if (segmented)\n            this.origin = this.checkpoint();\n    }\n    checkpoint() {\n        return structuredClone({ petCheckpointVersion: this.segmented ? 2 : 1,\n            ...(this.segmented ? { historyStart: (this.origin?.tick ?? this.tick), hasTelemetry: this.hasTelemetry } : {}), history: this.historyDigest(),\n            sim: this.sim.checkpoint(), score: this.score.checkpoint(), accumulator: this.accumulator,","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/pet/ios/Resources/pet-native.js#L192-L228","documentation":"The PetWorld constructor enforces bucket sequence contiguity. In unsegmented mode each tape bucket's sequence must equal its index (0,1,2,...); in segmented mode sequences must be strictly increasing. Each bucket must also pass validatePetBucket (version 1 schema). Any deviation means the telemetry tape cannot be replayed deterministically, so construction fails.","triggerScenarios":"Constructing PetWorld with a tape whose bucket sequences have gaps or duplicates, buckets out of order, buckets from different recordings spliced together, or buckets not conforming to the version 1 schema caught by validatePetBucket.","commonSituations":"Manually editing or partially deleting telemetry buckets; merging two recordings whose sequences overlap; a producer upgrading bucket format while the consumer still expects version 1; off-by-one when regenerating tape after dropping corrupted buckets.","solutions":["Renumber bucket.sequence to match the array index (or strictly increasing for segmented mode) before constructing.","Re-export the tape from the original source instead of splicing recordings together.","Run validatePetBucket on each element and drop/repair failing buckets, then renumber.","Verify both producer and consumer agree on bucket schema version 1."],"exampleFix":"// before\nconst tape = loadedTape.filter(b => !b.corrupt); // sequence now has gaps\nconst world = new PetWorld(points, tape); // throws\n// after\nconst tape = loadedTape.filter(b => isValidV1(b)).map((b, i) => ({ ...b, sequence: i }));\nconst world = new PetWorld(points, tape);","handlingStrategy":"validation","validationCode":"function isContiguousV1Tape(tape, segmented) {\n  return tape.every((b, i) => validatePetBucket(b) &&\n    (segmented ? i === 0 || b.sequence > tape[i - 1].sequence : b.sequence === i));\n}","typeGuard":"const isV1Bucket = (b) => b != null && b.version === 1 && Number.isInteger(b.sequence) && b.sequence >= 0;","tryCatchPattern":"try {\n  world = new PetWorld(points, tape, interactions);\n} catch (e) {\n  if (e.message.includes('contiguous version 1 pet buckets')) {\n    const repaired = tape.filter(isV1Bucket).map((b, i) => ({ ...b, sequence: i }));\n    world = new PetWorld(points, repaired, interactions);\n  } else throw e;\n}","preventionTips":["Never splice or partially delete buckets without renumbering sequences.","Keep producer and consumer on the same bucket schema version (1).","Validate tapes in CI with validatePetBucket before shipping recordings."],"tags":["validation","telemetry","sequence"],"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"}