{"record":{"id":"58a8c6c1f3215e89","repo":"Hmbown/CodeWhale","slug":"no-pet-segment-was-prepared-58a8c6","errorCode":null,"errorMessage":"No pet segment was prepared.","messagePattern":"No pet segment was prepared\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"pet/src/core/pet-native.ts","lineNumber":54,"sourceCode":"    }\n    return JSON.stringify({ ...frame, digest: digest(sim), style: sim.frame, activity: this.engine.activity(frame.timeMs),\n      points: sim.p.map(p => [p.x, p.y]),\n      still: { points: this.stillProjection.points, style: this.stillProjection.style, state } });\n  }\n  /** Losing a producer invalidates outstanding coverage, never the creature. */\n  disconnectEngine(): void { this.engine = new PetEngineTelemetry(); this.world.voices = []; }\n  interact(kind: PetInteraction['kind'], x: number, y: number): void { this.world.interact(kind, x, y); }\n  interactions(): string { return JSON.stringify(this.world.interactions); }\n  accept(packet: string): void { this.world.acceptTelemetry(JSON.parse(packet)); }\n  acceptLiveTail(text: string): boolean {\n    const packet = this.liveTape.readTail(text); if (!packet) return false;\n    this.world.acceptTelemetry(packet); return true;\n  }\n  resetLiveInput(): number { this.liveTape.reset(); return this.resumeEngine(); }\n  recording(withCheckpoint = false): string { return JSON.stringify(this.world.recording(withCheckpoint)); }\n  needsSegment(): boolean { return this.world.needsSegment; }\n  prepareSegment(): string { this.segment = this.world.prepareSegment(); return JSON.stringify(this.segment.recording); }\n  commitSegment(): void { if (!this.segment) throw new Error('No pet segment was prepared.'); this.segment.commit(); this.segment = undefined; }\n  checkpoint(): string { return JSON.stringify(this.world.checkpoint()); }\n  recordingChunk(index: number, completed = false): string | null { return this.world.recordingChunk(index, completed); }\n  restoreCheckpoint(text: string): void {\n    if (text.length > 512 * 1024) throw new Error('Pet checkpoint exceeds its size limit.');\n    this.restoreRecording(JSON.stringify({ ...this.world.recording(false), checkpoint: JSON.parse(text) }));\n  }\n  restoreRecording(text: string): void {\n    if (text.length > 8 * 1024 * 1024) throw new Error('Native habitat exceeds 8 MiB.');\n    const points = this.world.sim.p.map(p => [p.hx, p.hy] as [number, number]);\n    this.world = PetWorld.fromRecording(points, JSON.parse(text));\n    this.liveTape.reset();\n    this.segment = undefined; this.engineTick = Math.round(this.world.frame.timeMs * 30 / 1000); this.engine = new PetEngineTelemetry();\n  }\n  /** Resume a live host at the first unrecorded bucket. Keep every accepted\n   * interval, but never present its last observed frame as current evidence. */\n  resumeEngine(): number {\n    this.world.resumeObservation();\n    this.engineTick = Math.round(this.world.frame.timeMs * 30 / 1000);","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/pet/src/core/pet-native.ts#L36-L72","documentation":"commitSegment() finalizes a recording segment previously created with prepareSegment(). If prepareSegment() was never called — or the segment was already committed, which clears this.segment — the internal this.segment is undefined and the call throws. It is an ordering/state guard, not a data problem.","triggerScenarios":"Calling pet.commitSegment() without a prior pet.prepareSegment(); calling commitSegment() twice in a row (the first commit sets this.segment = undefined); calling commitSegment() after restoreRecording/restoreCheckpoint, which reset this.segment to undefined.","commonSituations":"Double-flushing a recording pipeline; racing timers that both call commitSegment; restarting/restoring a session between prepare and commit.","solutions":["Gate the commit on needsSegment()/prepareSegment(): call prepareSegment() first, then commitSegment() exactly once","Track a boolean 'segmentOpen' in the caller and skip the second commit","Re-create the segment (prepareSegment) if the world was restored between prepare and commit","Catch the error and treat it as a no-op if your commit path is idempotent by design"],"exampleFix":"// before\npet.commitSegment();\n// after\nif (pet.needsSegment() === false) { pet.prepareSegment(); }\npet.commitSegment();","handlingStrategy":"try-catch","validationCode":"if (!segmentOpen) { pet.prepareSegment(); segmentOpen = true; }","typeGuard":null,"tryCatchPattern":"try {\n  pet.commitSegment();\n  segmentOpen = false;\n} catch (err) {\n  if (err.message === 'No pet segment was prepared.') { segmentOpen = false; }\n  else throw err;\n}","preventionTips":["Always pair prepareSegment()/commitSegment() in one function","Track segment-open state explicitly in the caller","Never interleave restore calls between prepare and commit"],"tags":["state","lifecycle","ordering"],"backgroundTag":"invalid-state-transition","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"}