{"record":{"id":"f24b86b815ef93d0","repo":"JuliusBrussee/caveman","slug":"where-supporting-variant-variantid-belongs-t","errorCode":null,"errorMessage":"${where} supporting variant ${variantID} belongs to another task family","messagePattern":"(.+?) supporting variant (.+?) belongs to another task family","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/shared/contracts/scripts/validate-continuous-improvement.mjs","lineNumber":117,"sourceCode":"      throw new Error(`${where} probability_a_given_b ${relationship.probability_a_given_b} != ${expectedAGivenB}`);\n    }\n  }\n  relationshipCount += report.relationships.length;\n\n  // A motif is a structural count over variants this report carries, so every\n  // part of it must be re-derivable from those variants.\n  const variantsByID = new Map(report.workflow_variants.map((variant) => [variant.id, variant]));\n  const familyIDs = new Set(report.task_families.map((family) => family.id));\n  for (const motif of report.motifs) {\n    const where = `report fixture ${reportPaths[index]}: motif ${motif.id}`;\n    if (!familyIDs.has(motif.task_family_id)) throw new Error(`${where} references a task family that is not in this report`);\n    if (motif.support_variant_count !== motif.variant_ids.length) throw new Error(`${where} support variant count disagrees with its variant ids`);\n    let runs = 0;\n    let weighted = 0;\n    for (const variantID of motif.variant_ids) {\n      const variant = variantsByID.get(variantID);\n      if (!variant) throw new Error(`${where} references workflow variant ${variantID} that is not in this report`);\n      if (variant.task_family_id !== motif.task_family_id) throw new Error(`${where} supporting variant ${variantID} belongs to another task family`);\n      if (!contiguouslyContains(variant.signature, motif.operations)) {\n        throw new Error(`${where} operations are not a contiguous subsequence of variant ${variantID}'s signature`);\n      }\n      runs += variant.eligible_runs;\n      weighted += (motif.operations.length / variant.signature.length) * variant.eligible_runs;\n    }\n    if (motif.support_run_count !== runs) throw new Error(`${where} support run count ${motif.support_run_count} != ${runs}`);\n    const expectedShare = runs > 0 ? weighted / runs : 0;\n    if (Math.abs(motif.structural_cost_share - expectedShare) > 1e-6) {\n      throw new Error(`${where} structural_cost_share ${motif.structural_cost_share} != ${expectedShare}`);\n    }\n  }\n  motifCount += report.motifs.length;\n\n  // The causal investigation of every case: the cohort's arms, the traces it\n  // selected from them, and the backward hard-dependency slice.\n  const unitsByID = new Map(report.analysis_units.map((unit) => [unit.id, unit]));\n  const familiesByID = new Map(report.task_families.map((family) => [family.id, family]));","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/766dce6b1394ebb56a3090748d5a0240a5aefb36/packages/shared/contracts/scripts/validate-continuous-improvement.mjs#L99-L135","documentation":"The contracts fixture validator requires every motif to be re-derivable from the report's own workflow_variants: each variant a motif lists as supporting evidence must belong to the same task_family_id as the motif itself. This throw means a motif claims support from a variant in another family — the cross-reference is inconsistent, so the report's counts are not recomputable from the data it carries.","triggerScenarios":"A hand-edited report fixture where variant_ids were copied from a motif of a different family; a motif-extraction pipeline bug assigning cross-family variants; family ids that differ by one character between the task_families and workflow_variants blocks.","commonSituations":"Authors assembling fixtures from several report drafts; a renamed family id not propagated into motifs; a generator that regenerates variants but reuses stale motif lists.","solutions":["Regenerate the report with the pipeline rather than editing by hand.","Fix the motif's variant_ids to reference only variants whose task_family_id equals the motif's (or correct the motif's task_family_id).","Check for typos/duplicates among family ids in report.task_families and report.workflow_variants.","Re-run validate-continuous-improvement.mjs and confirm the fixture passes."],"exampleFix":"// before\nmotif: { id: 'm1', task_family_id: 'family-a', variant_ids: ['v-a1', 'v-b2'] }\n// v-b2 belongs to family-b -> throws\n// after\nmotif: { id: 'm1', task_family_id: 'family-a', variant_ids: ['v-a1', 'v-a2'] }","handlingStrategy":"validation","validationCode":"// Pre-check the fixture cross-references the validator enforces.\nfunction motifFamiliesConsistent(report) {\n  const variantsByID = new Map(report.workflow_variants.map((v) => [v.id, v]));\n  return report.motifs.every((motif) =>\n    motif.variant_ids.every((id) => variantsByID.get(id)?.task_family_id === motif.task_family_id),\n  );\n}\n// if (!motifFamiliesConsistent(report)) fixFixtureBeforeCommitting(report);","typeGuard":"function isConsistentMotif(report, motif) {\n  const familyIDs = new Set(report.task_families.map((f) => f.id));\n  const variantsByID = new Map(report.workflow_variants.map((v) => [v.id, v]));\n  return familyIDs.has(motif.task_family_id) &&\n    motif.variant_ids.every((id) => variantsByID.get(id)?.task_family_id === motif.task_family_id);\n}","tryCatchPattern":"try {\n  execFileSync('node', ['validate-continuous-improvement.mjs', reportPath, spansPath]);\n} catch (e) {\n  if (/belongs to another task family/.test(String(e?.stderr ?? e?.message))) {\n    // Regenerate the report from the pipeline; do not hand-patch variant_ids —\n    // support_run_count and structural_cost_share must be recomputed with it.\n  }\n  throw e;\n}","preventionTips":["Generate report fixtures with the pipeline; never splice variant lists across motifs by hand.","When renaming a task_family id, grep the whole report for the old id before committing.","Run the validator in CI on every fixture change so inconsistencies fail the build, not review."],"tags":["validation","fixtures","data-integrity","contracts"],"backgroundTag":"fixture-validation-failed","analyzedSha":"766dce6b1394ebb56a3090748d5a0240a5aefb36","analyzedAt":"2026-08-18T03:14:35.516Z","contentChangedAt":"2026-08-18T03:14:35.516Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}