{"record":{"id":"40ab9feae62bb15c","repo":"JuliusBrussee/caveman","slug":"cave-harness-build-mismatch","errorCode":"cave_harness_build_mismatch","errorMessage":"cave_harness_build_mismatch","messagePattern":"cave_harness_build_mismatch","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/execution-kernel.ts","lineNumber":76,"sourceCode":"      selected.reasoning !== expectedReasoning) {\n    throw new Error(\"cave_execution_plan_selection_mismatch\");\n  }\n}\n\nexport function prepareLockedHarnessExecution(input: {\n  build: CaveBuildLock;\n  harness: string;\n  adapterVersion: string;\n  upstreamVersion: string;\n  agentId?: string;\n  contextIR: ContextIR;\n  plan: CavePlan;\n}): LockedHarnessPreparation {\n  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\");","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/agent/src/execution-kernel.ts#L58-L94","documentation":"prepareLockedHarnessExecution verifies a CaveBuildLock against the harness identity being executed. It throws when the build lock's harness id, adapter_version, or upstream_version does not match the harness/adapterVersion/upstreamVersion passed in. This ensures a pinned build can only run on the exact harness that produced it.","triggerScenarios":"Calling prepared or streamAgentInternal with a build lock generated for a different harness id, or after upgrading the adapter_version or the upstream harness version without regenerating the lock.","commonSituations":"Upgrading the caveman agent or extension so upstream_version/adapter_version changed while an old build lock was reused; running a build lock against the wrong harness entry point; a stale cached lock file checked into the repo.","solutions":["Regenerate the build lock for the current harness/adapter/upstream versions.","Pin or reinstall the adapter so adapter_version matches build.harness.adapter_version.","Use the build lock with the harness id it was created for.","Check out/restore matching versions so harness.id and upstream_version align with the lock."],"exampleFix":"// before\nawait prepareLockedHarnessExecution({ build: oldLock, harness: \"cli\", adapterVersion: \"0.2.0\", upstreamVersion: \"1.9.0\", ... });\n// after\nconst lock = await buildCaveBuildLock({ harness: \"cli\", adapterVersion: \"0.2.0\", upstreamVersion: \"1.9.0\" });\nawait prepareLockedHarnessExecution({ build: lock, harness: \"cli\", adapterVersion: \"0.2.0\", upstreamVersion: \"1.9.0\", ... });","handlingStrategy":"try-catch","validationCode":"if (lock.harness.id !== harnessId || lock.harness.adapter_version !== adapterVersion || lock.harness.upstreamVersion !== upstreamVersion) {\n  lock = await rebuildCaveBuildLock({ harness: harnessId, adapterVersion, upstreamVersion });\n}","typeGuard":"function harnessMatches(lock: { harness: { id: string; adapter_version: string; upstream_version: string } }, h: { id: string; adapterVersion: string; upstreamVersion: string }): boolean {\n  return lock.harness.id === h.id && lock.harness.adapter_version === h.adapterVersion && lock.harness.upstream_version === h.upstreamVersion;\n}","tryCatchPattern":"try {\n  const prep = prepared({ build: lock, harness, adapterVersion, upstreamVersion, ... });\n} catch (err) {\n  if (err instanceof Error && err.message === \"cave_harness_build_mismatch\") {\n    const freshLock = await buildCaveBuildLock({ harness, adapterVersion, upstreamVersion });\n    return prepared({ build: freshLock, harness, adapterVersion, upstreamVersion, ... });\n  }\n  throw err;\n}","preventionTips":["Regenerate build locks whenever the adapter or upstream harness version changes.","Never commit stale lock files; generate locks in the same pipeline that executes them.","Compare lock.harness against your versions at startup, before any execution.","Pin adapter/upstream versions so they cannot drift between build and run."],"tags":["execution-kernel","version-mismatch","build-lock","harness"],"backgroundTag":"version-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"}