{"record":{"id":"af39dacfaa05ad02","repo":"JuliusBrussee/caveman","slug":"cave-harness-plan-digest-mismatch","errorCode":"cave_harness_plan_digest_mismatch","errorMessage":"cave_harness_plan_digest_mismatch","messagePattern":"cave_harness_plan_digest_mismatch","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/execution-kernel.ts","lineNumber":86,"sourceCode":"  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\");\n  return Object.freeze({\n    build,\n    plan: build.selected_plan,\n    planSHA256,\n    contextIRSHA256,\n    provider,\n    model,\n  });\n}\n","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/execution-kernel.ts#L68-L104","documentation":"Thrown while preparing a locked harness (packages/agent/src/execution-kernel.ts:86): the SHA-256 digest of the stable-stringified plan does not match the plan_sha256 recorded in the CaveBuildLock. This is a digest-level integrity check on the same plan identity the equality check (cave_harness_plan_mismatch) guards; it fires when the plan content hashes differently than what was locked.","triggerScenarios":"Same class as cave_harness_plan_mismatch but caught at digest level: plan bytes changed (model, reasoning, tool/context entries, or even serialization-relevant structure) relative to the locked plan, while the plan equality comparison path leads here via a mutated lock or plan.","commonSituations":"Lock file hand-edited so selected_plan and plan_sha256 are inconsistent; plan mutated in place after lock creation; version change altering stable-stringify output shape; corrupted lock file.","solutions":["Regenerate the lock with the normal build pipeline — never hand-edit lock contents.","If it persists after a clean rebuild, verify the lock file is not corrupted (re-parse it) and that the same package version produced the digest.","Pass the locked plan object (build.selected_plan) to the execution call unchanged."],"exampleFix":"# before\n# lock.json hand-edited (selected_plan changed, plan_sha256 left stale)\n\n# after\nrm lock.json && caveman build # regenerate both plan and digest atomically","handlingStrategy":"validation","validationCode":"import { createHash } from \"node:crypto\";\nconst digest = createHash(\"sha256\").update(stableStringify(plan)).digest(\"hex\");\nif (digest !== lock.plan_sha256) {\n  throw new Error(\"plan digest drifted from lock — rebuild required\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never hand-edit lock files; plan and digest are written atomically by the build step.","After framework upgrades, regenerate locks rather than reusing committed ones.","Add a CI step that verifies sha256(plan) === lock.plan_sha256 for every committed lock."],"tags":["lockfile","integrity","sha256","plan"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}