{"record":{"id":"09fab7ec9dd853cc","repo":"JuliusBrussee/caveman","slug":"cave-transform-safety-mismatch","errorCode":"cave_transform_safety_mismatch","errorMessage":"cave_transform_safety_mismatch:${segment.id}","messagePattern":"cave_transform_safety_mismatch:(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/runtime.ts","lineNumber":2647,"sourceCode":"  for (const route of plan.segment_routes) {\n    if (!known.has(route.transform_id)) {\n      throw new Error(`cave_unknown_transform:${route.transform_id}`);\n    }\n    const targets = lowered.ir.segments.filter((segment) =>\n      segment.kind === route.segment_kind &&\n      (route.segment_id === undefined || segment.id === route.segment_id));\n    if (targets.length === 0) {\n      if (route.segment_kind === \"history\" || route.segment_kind === \"tool_result\") {\n        continue;\n      }\n      throw new Error(`cave_plan_route_unmatched:${route.segment_id ?? route.segment_kind}`);\n    }\n    evaluated.push(route.transform_id);\n    let routeApplied = false;\n    for (const segment of targets) {\n      const original = lowered.bodies.get(segment.bodyHandle);\n      if (!original) throw new Error(`cave_context_body_missing:${segment.id}`);\n      if (segment.safety !== \"S4\") throw new Error(`cave_transform_safety_mismatch:${segment.id}`);\n      const startedAt = performance.now();\n      // beforeTokens/afterTokens are byte-derived (bytes/4) throughout so a\n      // delta is always within one basis. beforeTokens counts the ORIGINAL\n      // bytes; afterTokens, for an applied transform, counts the FULL provider\n      // body actually sent — wrapper included. segment.tokenCount\n      // is already estimateTokens(original) = bytes/4.\n      const beforeTokens = segment.tokenCount;\n      if (segment.opaque) {\n        trace.push({\n          segmentKind: segment.kind,\n          transformID: route.transform_id,\n          safetyClass: segment.safety,\n          beforeTokens,\n          afterTokens: beforeTokens,\n          tokensBasis: \"byte_derived\",\n          recoveryKind: segment.recovery,\n          recoveryUsed: false,\n          latencyMs: Math.round(performance.now() - startedAt),","sourceCodeStart":2629,"sourceCodeEnd":2665,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/agent/src/runtime.ts#L2629-L2665","documentation":"Thrown when a compaction route targets a segment whose safety classification is not 'S4'. Only S4 (lowest-sensitivity, transform-safe) segments may be rewritten by engine transforms; touching S1–S3 segments is refused to protect sensitive content. The segment id is included in the message.","triggerScenarios":"A plan route matches a segment with segment.safety !== \"S4\" (e.g. instructions or a user-classified context segment) and the runtime attempts to apply the transform to it.","commonSituations":"Broad segment_kind routes that sweep in higher-safety segments; segments mislabeled S4-eligible during lowering; plans reused across agents where the same kind has different safety labels.","solutions":["Narrow the plan route with an explicit segment_id that points at an S4 segment.","Check the safety classification assigned during lowering and correct it if it is wrongly restricted.","Remove routes that target non-S4 kinds; route only history/tool_result or S4 context.","If the segment genuinely is safe, update its safety level in the definition/lowering to S4."],"exampleFix":"// before\nsegment_routes: [{ segment_kind: \"context\", transform_id: \"...\" }] // matches S2 segment\n// after\nsegment_routes: [{ segment_kind: \"context\", segment_id: \"docs-s4\", transform_id: \"...\" }]","handlingStrategy":"validation","validationCode":"for (const route of plan.segment_routes) {\n  const targets = lowered.ir.segments.filter(s => s.kind === route.segment_kind && (route.segment_id === undefined || s.id === route.segment_id));\n  const unsafe = targets.filter(s => s.safety !== \"S4\");\n  if (unsafe.length) console.warn(`route would touch non-S4 segments: ${unsafe.map(s => s.id).join(\",\")}`);\n}","typeGuard":"function isTransformSafe(seg: { safety: string }): boolean { return seg.safety === \"S4\"; }","tryCatchPattern":"try {\n  await executePlan(plan, lowered);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith(\"cave_transform_safety_mismatch:\")) {\n    const id = err.message.split(\":\")[1];\n    // retarget the route to an S4 segment or fix the safety label\n  } else throw err;\n}","preventionTips":["Constrain plan routes with explicit segment_id when targeting context segments.","Review safety classifications whenever new context sources are added.","Never widen safety levels to silence this error without a data-sensitivity review.","Filter route targets to safety === \"S4\" inside custom plan generators."],"tags":["safety","transform","segment","agent-runtime"],"backgroundTag":"permission-denied","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"}