{"record":{"id":"a22f46699488a97f","repo":"Hmbown/CodeWhale","slug":"archive-this-pet-recording-before-accepting-more-telemetry-a22f46","errorCode":null,"errorMessage":"Archive this pet recording before accepting more telemetry.","messagePattern":"Archive this pet recording before accepting more telemetry\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"pet/src/core/pet-world.ts","lineNumber":293,"sourceCode":"    this.voices = [];\n  }\n\n  /** Branch at the current playhead; input is journalled for the next fixed tick.\n   * A live touch never needs to re-simulate the creature's entire lifetime. */\n  interact(kind: PetInteraction['kind'], x: number, y: number): void {\n    if (!['attention', 'food'].includes(kind) || !Number.isFinite(x) || !Number.isFinite(y) || Math.abs(x) > 1 || Math.abs(y) > 1)\n      throw new Error('Invalid pet interaction.');\n    if (this.branchTick !== this.tick) this.interactionLog.splice(this.interactionIndex);\n    this.branchTick = this.tick;\n    this.interactionLog.push({ timeMs: (this.tick + 1) * 1000 / HZ, kind, x, y });\n  }\n\n  /** Accept a live source packet at the next 400ms boundary. The accepted tape,\n   * including any missing intervals, is the exact replay authority for this host. */\n  acceptTelemetry(input: PetBucket): void {\n    validatePetBucket(input);\n    const sequence = Math.floor(this.tick / 12) + 1;\n    if (this.tapeLog.length >= 216_000) throw new Error('Archive this pet recording before accepting more telemetry.');\n    this.hasTelemetry = true;\n    if (this.segmented) {\n      const at = this.tapeLog.findIndex(b => b.sequence >= sequence);\n      const index = at < 0 ? this.tapeLog.length : at;\n      this.tapeLog.splice(index, at >= 0 && this.tapeLog[at].sequence === sequence ? 1 : 0,\n        { ...structuredClone(input), sequence, simTimeMs: sequence * 400 });\n      this.hashTape(index); return;\n    }\n    if (sequence >= 216_000) throw new Error('Archive the legacy recording before accepting more telemetry.');\n    const changedFrom = Math.min(sequence, this.tapeLog.length);\n    while (this.tapeLog.length <= sequence) {\n      const at = this.tapeLog.length;\n      this.tapeLog.push({ version: 1, sequence: at, simTimeMs: at * 400, durationMs: 400,\n        activity: .12, coherence: .25, attention: 0, channel: 'other', observed: 0, roamX: 0, roamY: 0, flip: 1, lit: 1,\n        onsets: Array(13).fill(0), activeMs: Array(13).fill(0), errors: 0, agentIds: [], waiting: false });\n    }\n    this.tapeLog[sequence] = { ...structuredClone(input), sequence, simTimeMs: sequence * 400 };\n    this.hashTape(changedFrom);","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/pet/src/core/pet-world.ts#L275-L311","documentation":"acceptTelemetry() appends one 400ms PetBucket per call into an in-memory tapeLog, and this throw caps that tape at 216,000 buckets (24 hours at 400ms per bucket). The limit keeps the host's replay tape bounded, so callers must archive the recording (persist and start a fresh PetWorld) before continuing.","triggerScenarios":"Calling acceptTelemetry() when this.tapeLog.length has reached 216,000 entries — i.e. continuously feeding live telemetry into one PetWorld instance for a full 24 simulated hours without archiving.","commonSituations":"A long-running session that keeps a single PetWorld alive for a day of continuous telemetry; a host that never rotates recordings; a replay/restore that re-accepts buckets on top of an already-full tape.","solutions":["Serialize/archive the current recording (export the tape + interactions) and start a fresh PetWorld before calling acceptTelemetry again.","Detect the limit proactively by checking the tape length before accepting more packets.","Rotate recordings at a smaller interval (e.g. hourly) so the 24h cap is never approached.","If replaying, verify you are not double-feeding buckets into a restored world."],"exampleFix":"// before\nworld.acceptTelemetry(bucket); // throws once tape is full\n// after\nif (world.isFull?.() ?? false) archive(world);\nworld.acceptTelemetry(bucket);","handlingStrategy":"try-catch","validationCode":"if (world.tapeLog?.length >= 216_000) archiveAndRotate(world);","typeGuard":"function canAcceptTelemetry(world): boolean { return Array.isArray(world.tapeLog) && world.tapeLog.length < 216_000; }","tryCatchPattern":"try { world.acceptTelemetry(bucket); } catch (e) { if (/Archive this pet recording/.test(e.message)) { await archive(world); world = new PetWorld(...); world.acceptTelemetry(bucket); } else throw e; }","preventionTips":["Rotate recordings on a schedule well below 24h of sim time.","Expose/track tape length in your host and rotate at a threshold like 200,000 buckets.","Never re-accept old buckets into a long-lived world after restore."],"tags":["telemetry","capacity-limit","replay"],"backgroundTag":"file-size-limit-exceeded","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-22T16:17:23.217Z"}