JuliusBrussee/caveman · error · Error

${where} causal slice omits its own manifestation node

Error message

${where} causal slice omits its own manifestation node

What it means

When a manifestation node is pinned (manifestation_node_id !== ""), it must itself appear in node_chain — a slice that omits the very node it says the failure manifests on is incoherent (validate-continuous-improvement.mjs:185-187). The empty-string sentinel disables the check.

Source

Thrown at packages/shared/contracts/scripts/validate-continuous-improvement.mjs:186

      if (count > 3) throw new Error(`${where} arm ${arm} carries ${count} representative traces, more than three`);
    }

    const slice = item.causal_slice;
    const sliceVariant = variantsByID.get(slice.variant_id);
    if (!sliceVariant) throw new Error(`${where} causal slice references a workflow variant that is not in this report`);
    if (sliceVariant.id !== armVariants.get("baseline").id) throw new Error(`${where} causal slice is not taken from the baseline arm's variant`);
    const sliceNodes = new Set(sliceVariant.nodes.map((node) => node.id));
    if (slice.manifestation_node_id !== "" && !sliceNodes.has(slice.manifestation_node_id)) {
      throw new Error(`${where} manifestation node ${slice.manifestation_node_id} is not a node of variant ${sliceVariant.id}`);
    }
    if (item.diagnosis.manifestation.node_id !== slice.manifestation_node_id) {
      throw new Error(`${where} diagnosis manifestation node disagrees with its causal slice`);
    }
    for (const nodeID of slice.node_chain) {
      if (!sliceNodes.has(nodeID)) throw new Error(`${where} causal slice node ${nodeID} is not a node of variant ${sliceVariant.id}`);
    }
    if (slice.manifestation_node_id !== "" && !slice.node_chain.includes(slice.manifestation_node_id)) {
      throw new Error(`${where} causal slice omits its own manifestation node`);
    }
    const provenDependency = (edge) => edge.strength === "hard" && (edge.type === "data" || edge.type === "control") && edge.evidence_refs.length > 0;
    const variantEdges = new Map(sliceVariant.edges.map((edge) => [`${edge.from}${edge.to}${edge.type}`, edge]));
    for (const edge of slice.hard_edges) {
      if (!provenDependency(edge)) throw new Error(`${where} hard chain carries an unproven edge ${edge.from}->${edge.to}`);
      if (!sliceNodes.has(edge.from) || !sliceNodes.has(edge.to)) throw new Error(`${where} hard chain edge ${edge.from}->${edge.to} names a node outside variant ${sliceVariant.id}`);
      if (!slice.node_chain.includes(edge.from) || !slice.node_chain.includes(edge.to)) {
        throw new Error(`${where} hard chain edge ${edge.from}->${edge.to} is outside the slice's node chain`);
      }
      const source = variantEdges.get(`${edge.from}${edge.to}${edge.type}`);
      if (!source || source.strength !== "hard") throw new Error(`${where} hard chain edge ${edge.from}->${edge.to} is not a hard edge of variant ${sliceVariant.id}`);
    }
    for (const edge of slice.unproven_adjacencies) {
      // The whole point of the separate list: nothing in it may read as proven.
      if (provenDependency(edge)) throw new Error(`${where} unproven adjacency ${edge.from}->${edge.to} is in fact a proven hard dependency`);
      if (slice.hard_edges.some((hard) => hard.from === edge.from && hard.to === edge.to && hard.type === edge.type)) {
        throw new Error(`${where} adjacency ${edge.from}->${edge.to} appears in both the hard chain and the unproven list`);
      }

View on GitHub (pinned to 766dce6b13)

Solutions

  1. Append (or insert at the right position) the manifestation node into node_chain.
  2. Better: rebuild the chain backwards from the manifestation node so it ends there by construction.
  3. Re-run the validator.

Example fix

// before
"manifestation_node_id": "node/exec",
"node_chain": ["node/parse"]
// after
"manifestation_node_id": "node/exec",
"node_chain": ["node/parse", "node/exec"]
Defensive patterns

Strategy: validation

Validate before calling

const slicesMissingManifestation = (report) =>
  report.cases.filter((c) =>
    c.causal_slice.manifestation_node_id !== '' &&
    !c.causal_slice.node_chain.includes(c.causal_slice.manifestation_node_id)
  ).map((c) => c.id);

Try / catch

try {
  execFileSync(process.execPath, [VALIDATOR, reportPath, spansPath]);
} catch (err) {
  if (/omits its own manifestation/.test(err.message)) {
    failCI(`node_chain must include the manifestation node: ${err.message}`);
  } else throw err;
}

Prevention

When it happens

Trigger: The backward slice was truncated one hop early; the chain was reordered or deduplicated and dropped the manifestation node; the chain was built toward a different endpoint than the manifestation claim.

Common situations: Hand-trimming chains for brevity; generators that stop the backward walk at a budget before reaching the manifestation node; editing manifestation_node_id without extending the chain.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@766dce6b13 (2026-08-18). Data as JSON: /api/errors/3031b9eaa39d39a3. Report an issue: GitHub.