{"record":{"id":"8abdf23edbf734dc","repo":"Hmbown/CodeWhale","slug":"non-contiguous-pet-tape","errorCode":null,"errorMessage":"Non-contiguous pet tape.","messagePattern":"Non-contiguous pet tape\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/tui/pet_watch/pet-native.js","lineNumber":1120,"sourceCode":"    (0, pet_sim_js_1.validatePetState)(value);\n    const b = value;\n    if (!b || typeof b !== 'object' || b.version !== 1 || !Number.isSafeInteger(b.sequence) || b.sequence < 0 || b.sequence > pet_sim_js_1.PET_MAX_SECONDS * 2.5\n        || b.simTimeMs !== b.sequence * exports.PET_BIN_MS || b.durationMs !== exports.PET_BIN_MS\n        || !model_js_1.CATEGORIES.includes(b.channel) || typeof b.waiting !== 'boolean'\n        || !Array.isArray(b.agentIds) || b.agentIds.length > 250_000 || b.agentIds.some(id => typeof id !== 'string' || !id || id.length > 4096)\n        || !Number.isSafeInteger(b.errors) || b.errors < 0 || b.errors > 250_000\n        || !Array.isArray(b.onsets) || b.onsets.length !== 13 || b.onsets.some(n => !Number.isSafeInteger(n) || n < 0 || n > 250_000)\n        || !Array.isArray(b.activeMs) || b.activeMs.length !== 13 || b.activeMs.some(n => !Number.isFinite(n) || n < 0 || n > 100_000_000))\n        throw new Error('Invalid version 1 pet bucket.');\n}\nfunction decodePetJSONL(text) {\n    if (text.length > 64 * 1024 * 1024)\n        throw new Error('Pet tape exceeds 64 MiB.');\n    const rows = text.split(/\\r?\\n/).filter(line => line.trim()).map(line => JSON.parse(line));\n    if (rows.length > 216_000)\n        throw new Error('Pet tape exceeds 24 hours.');\n    return rows.map((row, i) => { validatePetBucket(row); if (row.sequence !== i)\n        throw new Error('Non-contiguous pet tape.'); return row; });\n}\n/** A live file must advance before its contents count as a new observation.\n * Existing bytes, duplicate samples and a restarted sequence establish a\n * baseline; they never replay an old onset or human request. Drivers supply a\n * bounded tail and reset this cursor after suspension or a new attachment. */\nclass PetLiveTape {\n    sequence;\n    reset() { this.sequence = undefined; }\n    readTail(text) {\n        if (!text) {\n            this.reset();\n            return;\n        }\n        if (text.length > 262_144) {\n            this.reset();\n            throw new Error('Live pet input exceeds its tail limit.');\n        }\n        if (!text.endsWith('\\n'))","sourceCodeStart":1102,"sourceCodeEnd":1138,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tui/pet_watch/pet-native.js#L1102-L1138","documentation":"decodePetJSONL() requires each row's 'sequence' field to equal its 0-based index in the file, proving the tape is contiguous. A gap or restart in sequence numbers means rows were dropped, reordered, or a new tape was appended to an old one, so the parser rejects the whole file.","triggerScenarios":"Decoding a JSONL tape where any row's sequence !== its row index — e.g. lines were deleted, rows were written out of order, multiple sessions' tapes were concatenated, or the sequence counter restarted at 0 mid-file.","commonSituations":"Manually editing/trimming the tape file; merging tapes from two runs; a crashed writer that skipped a line; appending a new session's tape (sequence restarted at 0) to an existing file.","solutions":["Regenerate or repair the tape so sequence numbers run 0..n-1 with no gaps.","Reindex the rows before decoding: rows.map((row,i)=>({...row,sequence:i})).","Do not concatenate tapes; keep one file per session and decode them separately.","Delete the corrupted tape and let the pet-watch driver start a fresh one."],"exampleFix":"// before\nconst tape = decodePetJSONL(raw); // throws 'Non-contiguous pet tape.'\n// after\nconst rows = raw.split(/\\r?\\n/).filter(Boolean).map(JSON.parse).map((r, i) => ({ ...r, sequence: i }));\nconst tape = decodePetJSONL(rows.map(r => JSON.stringify(r)).join('\\n'));","handlingStrategy":"validation","validationCode":"function isContiguous(raw) {\n  const rows = raw.split(/\\r?\\n/).filter(l => l.trim()).map(JSON.parse);\n  return rows.every((r, i) => r.sequence === i);\n}","typeGuard":"function hasContiguousSequence(rows) {\n  return Array.isArray(rows) && rows.every((r, i) =>\n    r != null && typeof r.sequence === 'number' && r.sequence === i);\n}","tryCatchPattern":"try {\n  const tape = decodePetJSONL(raw);\n} catch (e) {\n  if (e.message === 'Non-contiguous pet tape.') {\n    // reindex and retry, or start a fresh tape\n    const repaired = raw.split(/\\r?\\n/).filter(Boolean)\n      .map((l, i) => JSON.stringify({ ...JSON.parse(l), sequence: i })).join('\\n');\n    const tape = decodePetJSONL(repaired);\n  } else throw e;\n}","preventionTips":["Never hand-edit or splice tape files; regenerate instead.","Keep one tape per session; do not concatenate.","After a writer crash, rebuild the tape rather than patching lines.","Validate sequence continuity at write time, not read time."],"tags":["input-validation","jsonl","data-integrity"],"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-23T02:17:17.105Z"}