{"record":{"id":"43987809028dcc98","repo":"JuliusBrussee/caveman","slug":"invalid-decision-ledger-response","errorCode":null,"errorMessage":"invalid Decision Ledger response","messagePattern":"invalid Decision Ledger response","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":13756,"sourceCode":"  line(\"unresolved assumptions\", String(receipt.policy.unresolved_assumptions ?? 0));\n  console.log(\"\\nClaim status\");\n  line(\"compression reduction\", receipt.claim_status.compression_reduction ?? \"not_attested\");\n  line(\"task savings\", receipt.claim_status.task_savings ?? \"not_verified\");\n}\n\nfunction nativeWhy(argv: string[]) {\n  const json = argv.includes(\"--json\");\n  const decisionID = argv.find((arg) => !arg.startsWith(\"--\"));\n  if (!decisionID || !/^dec_[0-9a-f]{24}$/.test(decisionID)) {\n    console.error(`usage: ${invokedAs()} why <decision-id> [--json]`);\n    process.exitCode = 2;\n    return;\n  }\n  let explanation: NativeWhy;\n  try {\n    const parsed = JSON.parse(proxyExec([\"native-why\", \"--decision\", decisionID], process.env, false)) as NativeWhy;\n    if (parsed?.schema !== \"caveman.native.why.v1\" || parsed.decision_id !== decisionID || typeof parsed.input_basis !== \"object\") {\n      throw new Error(\"invalid Decision Ledger response\");\n    }\n    explanation = parsed;\n  } catch (error) {\n    if (process.exitCode) return;\n    console.error(`caveman why: ${(error as Error).message}`);\n    process.exitCode = 1;\n    return;\n  }\n  if (json) {\n    print(explanation);\n    return;\n  }\n  const line = (label: string, value: string) => console.log(`  ${label.padEnd(22)} ${value}`);\n  console.log(`Decision ${explanation.decision_id}`);\n  line(\"session\", explanation.session_id);\n  line(\"action\", explanation.action);\n  line(\"reason\", explanation.reason);\n  line(\"input basis\", JSON.stringify(explanation.input_basis));","sourceCodeStart":13738,"sourceCodeEnd":13774,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/5184b3d11ac6a1acb7d44b9bfaa31698157cff97/packages/cli/src/index.ts#L13738-L13774","documentation":"`caveman why <decision-id>` shells out to the local proxy (`proxyExec([\"native-why\", \"--decision\", id])`) and parses stdout as JSON. The response must carry schema `caveman.native.why.v1`, a decision_id equal to the requested one, and an object-typed input_basis. Any mismatch — or a JSON.parse failure — is reported as an invalid Decision Ledger response and the command exits 1.","triggerScenarios":"Version skew where the installed proxy emits a different schema version or shape; proxy stdout polluted by warnings/logs so parsing or field checks fail; requesting a decision id the proxy does not know so the returned decision_id differs; proxy binary missing so proxyExec itself fails.","commonSituations":"CLI upgraded but the local proxy/daemon still old (or vice versa); multiple caveman installs shadowing each other on PATH; decision ids copied from another environment's ledger; proxy started with verbose logging that writes to stdout.","solutions":["Confirm the decision id matches ^dec_[0-9a-f]{24}$ and originates from this environment's ledger","Upgrade CLI and proxy together so both speak schema `caveman.native.why.v1`","Run the proxy command directly (`<proxy-bin> native-why --decision <id>`) and inspect the JSON to see which field mismatches","Use `--json` to view the raw payload and distinguish parse errors from schema mismatches"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"const idOk = /^dec_[0-9a-f]{24}$/.test(decisionID);\nif (!idOk) throw new Error('decision id must be dec_ followed by 24 hex chars');","typeGuard":"const isNativeWhy = (v: unknown, id: string): v is NativeWhy =>\n  typeof v === 'object' && v !== null &&\n  (v as NativeWhy).schema === 'caveman.native.why.v1' &&\n  (v as NativeWhy).decision_id === id &&\n  typeof (v as NativeWhy).input_basis === 'object' &&\n  (v as NativeWhy).input_basis !== null;","tryCatchPattern":"try {\n  const parsed = JSON.parse(proxyExec(['native-why', '--decision', id], env, false));\n  if (!isNativeWhy(parsed, id)) throw new Error('invalid Decision Ledger response');\n} catch (e) {\n  // distinguish JSON.parse failure (stdout pollution) from field mismatch (version skew) before reporting\n  console.error(`caveman why: ${(e as Error).message}`);\n  process.exitCode = 1;\n}","preventionTips":["Upgrade CLI and proxy in lockstep so both speak caveman.native.why.v1","Never let the proxy write diagnostics to stdout — route them to stderr","Validate the decision-id shape first to get the usage error instead of the ledger error"],"tags":["cli","schema-validation","decision-ledger","version-skew","proxy"],"backgroundTag":"schema-validation-failed","analyzedSha":"5184b3d11ac6a1acb7d44b9bfaa31698157cff97","analyzedAt":"2026-08-18T03:14:35.516Z","contentChangedAt":"2026-08-18T03:14:35.516Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}