{"record":{"id":"f0dc4542e81fbf53","repo":"JuliusBrussee/caveman","slug":"cave-harness-context-ir-mismatch","errorCode":"cave_harness_context_ir_mismatch","errorMessage":"cave_harness_context_ir_mismatch","messagePattern":"cave_harness_context_ir_mismatch","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/execution-kernel.ts","lineNumber":90,"sourceCode":"  const build = parseCaveBuildLock(input.build);\n  if (build.harness.id !== input.harness ||\n      build.harness.adapter_version !== input.adapterVersion ||\n      build.harness.upstream_version !== input.upstreamVersion) {\n    throw new Error(\"cave_harness_build_mismatch\");\n  }\n  if (input.agentId !== undefined && build.agent_id !== input.agentId) {\n    throw new Error(\"cave_harness_agent_mismatch\");\n  }\n  if (stableStringify(input.plan) !== stableStringify(build.selected_plan)) {\n    throw new Error(\"cave_harness_plan_mismatch\");\n  }\n  const planSHA256 = sha256(stableStringify(input.plan));\n  if (planSHA256 !== build.plan_sha256) {\n    throw new Error(\"cave_harness_plan_digest_mismatch\");\n  }\n  const contextIRSHA256 = sha256(stableStringify(contextIRToWire(input.contextIR)));\n  if (contextIRSHA256 !== build.context_ir_sha256) {\n    throw new Error(\"cave_harness_context_ir_mismatch\");\n  }\n  const [provider, ...modelParts] = input.plan.model.split(\"/\");\n  const model = modelParts.join(\"/\");\n  if (!provider || !model) throw new Error(\"cave_harness_model_invalid\");\n  return Object.freeze({\n    build,\n    plan: build.selected_plan,\n    planSHA256,\n    contextIRSHA256,\n    provider,\n    model,\n  });\n}\n\nexport interface ProviderUsageEvidence {\n  provider: string;\n  model: string;\n  inputTokens: number;","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/agent/src/execution-kernel.ts#L72-L108","documentation":"The kernel serializes the runtime context IR to its wire form and compares its SHA-256 against build.context_ir_sha256 in the lock. It throws when the context IR differs from what was locked, ensuring the model sees exactly the locked context during a locked harness execution.","triggerScenarios":"Calling prepared or streamAgentInternal with a contextIR whose wire serialization hash differs from build.context_ir_sha256 — any change to context contents, ordering, or IR schema version triggers it.","commonSituations":"Dynamic context (timestamps, tool results, env) differing between lock build and execution; a context compaction or trimming step running before execution; IR schema/serialization change after an upgrade; building the lock in one process and executing with slightly different context in another.","solutions":["Rebuild the build lock using the exact contextIR that will be executed.","Pass the same contextIR (byte-identical after wire serialization) used at lock time.","Remove non-deterministic fields (timestamps, random ids) from the context IR or make them deterministic for locked runs.","Verify both sides use the same contextIRToWire serialization version."],"exampleFix":"// before\nconst contextIR = buildContextIR({ now: new Date() }); // lock built earlier, different now\nawait prepared({ build: lock, contextIR });\n// after\nconst contextIR = buildContextIR({ now: lock.context_ir.now });\nawait prepared({ build: lock, contextIR });","handlingStrategy":"validation","validationCode":"import { createHash } from \"node:crypto\";\nconst digest = createHash(\"sha256\").update(stableStringify(contextIRToWire(contextIR))).digest(\"hex\");\nif (digest !== lock.context_ir_sha256) {\n  lock = await buildCaveBuildLock({ plan, contextIR });\n}","typeGuard":"function contextIRMatchesLock(contextIR: unknown, lock: { context_ir_sha256: string }): boolean {\n  return sha256(stableStringify(contextIRToWire(contextIR))) === lock.context_ir_sha256;\n}","tryCatchPattern":"try {\n  await prepared({ build: lock, contextIR, ... });\n} catch (err) {\n  if (err instanceof Error && err.message === \"cave_harness_context_ir_mismatch\") {\n    const fresh = await buildCaveBuildLock({ plan, contextIR });\n    return prepared({ build: fresh, contextIR, ... });\n  }\n  throw err;\n}","preventionTips":["Build the lock and execute in the same step so context cannot drift.","Strip or pin non-deterministic context fields (timestamps, ids) for locked runs.","Run compaction/trimming of context before lock creation, not after.","Keep contextIRToWire serialization version identical on both sides of the lock."],"tags":["execution-kernel","context","checksum","build-lock"],"backgroundTag":"checksum-mismatch","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}