{"record":{"id":"30f4594117958c4d","repo":"Hmbown/CodeWhale","slug":"invalid-runtime-replay-progress","errorCode":null,"errorMessage":"Invalid Runtime replay progress.","messagePattern":"Invalid Runtime replay progress\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"pet/scripts/lib/pet-runtime.mjs","lineNumber":54,"sourceCode":"      client.fetchImpl = async (input, init) => {\n        const response = await fetchImpl(input, init);\n        if (!response.body || !response.ok) return response;\n        // Also reject an older installed SDK that silently omits the requested\n        // progress option; it must not turn historical packets into live state.\n        if (response.headers.get('x-codewhale-event-progress') !== '1') {\n          await response.body.cancel();\n          const error = new Error('Runtime replay progress is unavailable.'); error.status = 501; throw error;\n        }\n        // Cancel the wrapped pipeline too: the original Response can be collected\n        // while its idle body is still being read through the replacement below.\n        const body = response.body.pipeThrough(new TransformStream({ transform(chunk, controller) { refresh(); controller.enqueue(chunk); } }), { signal });\n        return new Response(body, { status: response.status, headers: response.headers });\n      };\n      try {\n        for await (const record of client.threadEvents(threadId, { sinceSeq: cursor, signal, includeProgress: true })) {\n          if (record?.event === 'stream.progress') {\n            if (record.thread_id !== threadId || record.seq !== cursor || !['live', 'replaying'].includes(record.state))\n              throw new Error('Invalid Runtime replay progress.');\n            connected = record.state === 'live';\n            continue;\n          }\n          if (!isCodewhaleRuntimeRecord(record) || record.thread_id !== threadId || !Number.isSafeInteger(record.seq) || record.seq < 0)\n            throw new Error('Invalid Runtime envelope.');\n          if (record.seq <= cursor) continue;\n          // Sequence numbers belong to Runtime, and need not be consecutive.\n          // Its predecessor cursor detects loss without inventing a new counter.\n          if (record.previous_seq !== undefined && record.previous_seq !== cursor)\n            throw new Error('Runtime predecessor cursor does not match.');\n          if (record.event !== 'item.delta') {\n            // The existing importer retains unfinished lifetimes and a recent\n            // recurrence window, not a second copy of the entire raw journal.\n            if (revision % 256 === 0) trace.prune(Date.now() - 16_000);\n            try { trace.append([redact(record)]); }\n            catch (error) { fatal = true; throw error; }\n            revision++;\n          }","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/pet/scripts/lib/pet-runtime.mjs#L36-L72","documentation":"While iterating client.threadEvents() with includeProgress:true, the script validates each 'stream.progress' record: its thread_id must match the followed thread, its seq must equal the local cursor, and its state must be 'live' or 'replaying'. Any progress record violating this contract means the server's replay progress stream is inconsistent with the client's position, so followRuntime aborts with this error.","triggerScenarios":"A 'stream.progress' record arrives where record.thread_id differs from the requested threadId, record.seq !== cursor, or record.state is something other than 'live'/'replaying' (e.g. 'closed', 'error', or a renamed state from a newer Runtime server).","commonSituations":"Server and client version drift (server emits a new progress state string); a proxy or misrouted connection returning progress for a different thread; a server bug emitting progress at a seq the client hasn't reached yet.","solutions":["Log the offending record (thread_id/seq/state) to see which of the three checks failed before restarting.","Verify the Runtime server version supports the progress states 'live' and 'replaying' the client expects; upgrade client or server so they agree.","Confirm the --runtime URL points at the server actually owning the --thread ID (no shared proxy serving other threads).","Restart followRuntime from cursor 0 (no --resume offset) if a stale cursor is desynchronizing the stream."],"exampleFix":"// debug before the loop\nfor await (const record of client.threadEvents(threadId, { sinceSeq: cursor, signal, includeProgress: true })) {\n  if (record?.event === 'stream.progress' && (record.thread_id !== threadId || record.seq !== cursor || !['live','replaying'].includes(record.state)))\n    console.error('bad progress', JSON.stringify(record)); // inspect which field diverged\n  ...\n}","handlingStrategy":"type-guard","validationCode":"function validProgress(record, threadId, cursor) {\n  return record?.event === 'stream.progress' &&\n    record.thread_id === threadId &&\n    record.seq === cursor &&\n    ['live', 'replaying'].includes(record.state);\n}\n// call before trusting: if (!validProgress(record, threadId, cursor)) log & resync","typeGuard":"function isKnownProgressState(state) {\n  return state === 'live' || state === 'replaying';\n}","tryCatchPattern":"try {\n  for await (const record of client.threadEvents(threadId, opts)) {\n    if (record?.event === 'stream.progress' && !validProgress(record, threadId, cursor)) {\n      console.error('progress mismatch', JSON.stringify(record));\n      break; // resync from cursor 0 instead of crashing blind\n    }\n  }\n} catch (err) { /* reconnect with sinceSeq: 0 */ }","preventionTips":["Keep Runtime server and client versions aligned on the progress-state vocabulary.","Point --runtime at the server that owns the thread; avoid shared proxies serving multiple threads.","Log progress records at debug level so divergences are diagnosable."],"tags":["streaming","protocol-validation","runtime","replay"],"backgroundTag":"unexpected-response-shape","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"}