{"record":{"id":"53c324cd0d3320d9","repo":"JuliusBrussee/caveman","slug":"where-references-a-task-family-that-is-not-in-this-report","errorCode":null,"errorMessage":"${where} references a task family that is not in this report","messagePattern":"(.+?) references a task family that is not in this report","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/shared/contracts/scripts/validate-continuous-improvement.mjs","lineNumber":110,"sourceCode":"    }\n    const expectedBGivenA = relationship.shared_unit_count / relationship.theme_a_unit_count;\n    const expectedAGivenB = relationship.shared_unit_count / relationship.theme_b_unit_count;\n    if (Math.abs(relationship.probability_b_given_a - expectedBGivenA) > 1e-9) {\n      throw new Error(`${where} probability_b_given_a ${relationship.probability_b_given_a} != ${expectedBGivenA}`);\n    }\n    if (Math.abs(relationship.probability_a_given_b - expectedAGivenB) > 1e-9) {\n      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    }","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/shared/contracts/scripts/validate-continuous-improvement.mjs#L92-L128","documentation":"Every motif must reference a task family that exists in the same report fixture. The validator builds a set of task_families ids and throws when a motif's task_family_id is absent, enforcing referential integrity inside each report.","triggerScenarios":"A report's motifs[] entry has task_family_id that does not match any id in that report's task_families[] (typo, renamed family, or motif copied from another report).","commonSituations":"Renaming a task family id in fixtures without updating motifs; duplicating a motif across report fixtures with different family ids; typos in hand-authored fixtures.","solutions":["Correct the motif's task_family_id to match an existing task_families[].id in the same report.","If the family was renamed, update all motifs referencing the old id.","Add the missing task family entry to task_families if it legitimately should exist."],"exampleFix":"// before\n{ \"motifs\": [{ \"id\": \"m1\", \"task_family_id\": \"family-old\" }] }\n// after\n{ \"motifs\": [{ \"id\": \"m1\", \"task_family_id\": \"family-renamed\" }] }","handlingStrategy":"validation","validationCode":"const familyIDs = new Set(report.task_families.map(f => f.id));\nfor (const m of report.motifs) if (!familyIDs.has(m.task_family_id)) throw new Error(`motif ${m.id}: unknown task_family_id ${m.task_family_id}`);","typeGuard":"const motifFamilyExists = (motif, report) => report.task_families.some(f => f.id === motif.task_family_id);","tryCatchPattern":"try { validateContinuousImprovement(report); } catch (e) { if (String(e.message).includes('references a task family')) { console.error('Update motif.task_family_id to a family present in this report'); } else throw e; }","preventionTips":["Generate motifs from the same report's task_families, never copy across reports","Grep fixtures for renamed family ids after refactors","Enforce referential integrity in the fixture generator itself"],"tags":["fixture","reference-integrity","validation"],"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"}