{"record":{"id":"7d4e3fcf26545559","repo":"JuliusBrussee/caveman","slug":"where-key-opportunity-key-is-not-a-workflow-variant-of-this","errorCode":null,"errorMessage":"${where} ${key} ${opportunity[key]} is not a workflow variant of this report","messagePattern":"(.+?) (.+?) (.+?) is not a workflow variant of this report","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/shared/contracts/scripts/validate-continuous-improvement.mjs","lineNumber":59,"sourceCode":"    }\n    if (isNew !== (theme.lineage.predecessor_ids.length === 0)) {\n      throw new Error(`report fixture ${reportPaths[index]}: theme ${theme.id} transition ${theme.lineage.transition} disagrees with its predecessor list`);\n    }\n    if (!isNew && !theme.lineage.predecessor_ids.includes(theme.registry_id)) {\n      throw new Error(`report fixture ${reportPaths[index]}: theme ${theme.id} inherited a registry id that is not one of its predecessors`);\n    }\n  }\n\n  // An opportunity names the exact pair of workflow variants it was emitted\n  // from, and a safety finding carries no borrowed dollar figure: copying the\n  // efficiency finding's alternative metrics and expected value would let the\n  // same money be counted twice under two detectors.\n  const variantIds = new Set(report.workflow_variants.map((variant) => variant.id));\n  for (const opportunity of report.opportunities) {\n    const where = `report fixture ${reportPaths[index]}: opportunity ${opportunity.id}`;\n    for (const key of [\"current_variant_id\", \"alternative_variant_id\"]) {\n      if (opportunity[key] && !variantIds.has(opportunity[key])) {\n        throw new Error(`${where} ${key} ${opportunity[key]} is not a workflow variant of this report`);\n      }\n    }\n    if (opportunity.detector_id === \"dominated-workflow\") {\n      if (!opportunity.current_variant_id || !opportunity.alternative_variant_id) {\n        throw new Error(`${where} compares two workflows without naming both variants`);\n      }\n    }\n    if (opportunity.type === \"safety\") {\n      if (opportunity.alternative_variant_id) throw new Error(`${where} is a safety finding with an alternative variant`);\n      if (opportunity.expected_value !== 0) throw new Error(`${where} is a safety finding carrying expected value ${opportunity.expected_value}`);\n      if (opportunity.alternative_metrics.cost_per_outcome_usd !== null || opportunity.alternative_metrics.eligible_runs !== 0) {\n        throw new Error(`${where} is a safety finding carrying another workflow's metrics`);\n      }\n    }\n  }\n\n  // A relationship is a count, so it must be recomputable from the counts it\n  // carries. Anything a reader cannot re-derive is a claim, not evidence.","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/shared/contracts/scripts/validate-continuous-improvement.mjs#L41-L77","documentation":"Every opportunity must reference workflow variants that actually exist in the same report: the validator builds a Set of report.workflow_variants ids and throws if an opportunity's current_variant_id or alternative_variant_id is set but not in that set. This is a referential-integrity check — an opportunity naming a variant from another report or a deleted variant is not evidence this report can back.","triggerScenarios":"Running the validator on a report where an opportunity has a non-empty current_variant_id or alternative_variant_id that does not match any report.workflow_variants[].id.","commonSituations":"Merging opportunities and variants from different report fixtures; renaming variant ids during regeneration so opportunities keep stale ids; deleting a dominated variant from workflow_variants while its opportunities remain.","solutions":["Open the named fixture and fix opportunity.current_variant_id / alternative_variant_id to ids present in report.workflow_variants.","Remove or regenerate opportunities that reference variants no longer carried by the report.","If the variant exists in another report, move the opportunity into that report rather than cross-referencing.","Re-run the validator to confirm variant references resolve."],"exampleFix":"// before\n{ \"id\": \"opp-1\", \"current_variant_id\": \"variant-a-old\" }\n// after\n{ \"id\": \"opp-1\", \"current_variant_id\": \"variant-a\" }","handlingStrategy":"validation","validationCode":"const variantIds = new Set(report.workflow_variants.map((v) => v.id));\nconst dangling = report.opportunities.filter((o) =>\n  [o.current_variant_id, o.alternative_variant_id].some((id) => id && !variantIds.has(id))\n);\nif (dangling.length) throw new Error(`opportunities reference unknown variants: ${dangling.map((o) => o.id)}`);","typeGuard":"const referencesKnownVariant = (opportunity, report) => { const ids = new Set(report.workflow_variants.map((v) => v.id)); return ids.has(opportunity.current_variant_id) && (!opportunity.alternative_variant_id || ids.has(opportunity.alternative_variant_id)); };","tryCatchPattern":"try {\n  await runValidator([reportPath, spansPath]);\n} catch (err) {\n  if (String(err.message).includes(\"is not a workflow variant of this report\")) {\n    console.error(\"Opportunity variant id is dangling — reconcile with report.workflow_variants.\");\n  }\n  throw err;\n}","preventionTips":["Generate opportunities and variants in one pass so ids cannot diverge.","Never merge reports partially; move whole opportunity records with their variants.","Grep fixtures for renamed variant ids after any id change."],"tags":["validation","fixtures","referential-integrity","opportunities"],"backgroundTag":"entity-not-found","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"}