{"record":{"id":"681906fa727565ef","repo":"JuliusBrussee/caveman","slug":"where-support-run-count-motif-support-run-cou","errorCode":null,"errorMessage":"${where} support run count ${motif.support_run_count} != ${runs}","messagePattern":"(.+?) support run count (.+?) != (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/shared/contracts/scripts/validate-continuous-improvement.mjs","lineNumber":124,"sourceCode":"  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]));\n  for (const item of report.cases) {\n    const where = `report fixture ${reportPaths[index]}: case ${item.id}`;\n    const family = familiesByID.get(item.cohort.task_family_id);\n    if (!family) throw new Error(`${where} cohort references a task family that is not in this report`);\n    const familyUnits = new Set(family.analysis_unit_ids);\n    if (item.cohort.family_unit_count !== familyUnits.size) throw new Error(`${where} cohort family unit count disagrees with the task family`);\n    const roles = item.cohort.arms.map((arm) => arm.role);","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/766dce6b1394ebb56a3090748d5a0240a5aefb36/packages/shared/contracts/scripts/validate-continuous-improvement.mjs#L106-L142","documentation":"Thrown by the continuous-improvement report conformance validator (packages/shared/contracts/scripts/validate-continuous-improvement.mjs:124) when a motif's declared support_run_count does not equal the sum of eligible_runs over the workflow variants listed in that motif's variant_ids. A motif is a structural count over the report's own variants, so every number it carries must be re-derivable from them; the validator recomputes the sum and rejects the fixture on any mismatch. The message prints both the stored value and the recomputed sum so the drift is immediately visible.","triggerScenarios":"A report fixture passes the ajv schema check but motif.variant_ids names variants whose eligible_runs sum to something other than motif.support_run_count — e.g. one variant's eligible_runs was edited from 24 to 31 without touching the motif, or a variant id was added to or removed from variant_ids without re-summing. Produced by running: node packages/shared/contracts/scripts/validate-continuous-improvement.mjs <report.json> <spans.json>.","commonSituations":"Hand-editing generated fixtures to tweak numbers; a report generator that computes support_run_count from a snapshot taken before eligible_runs was finalized; rebasing fixtures after a schema or generator change; copying a motif block from another fixture that has different variant ids.","solutions":["Recompute support_run_count as the exact sum of eligible_runs over every variant id in motif.variant_ids and write that value into the fixture.","If the recomputed sum looks wrong, verify variant_ids lists exactly the supporting variants (each must contain the motif operations as a contiguous subsequence of its signature) — a stale entry silently changes the sum.","If a generator produced the fixture, fix it to derive the count at emit time (after eligible_runs is final) and add a unit test that recomputes it.","Re-run the validator: node packages/shared/contracts/scripts/validate-continuous-improvement.mjs <reportPath> <spansPath>"],"exampleFix":"// before — variant_ids: [wf-a (eligible_runs 24), wf-b (eligible_runs 31)]\n{\n  \"id\": \"motif-retry-loop\",\n  \"variant_ids\": [\"wf-a\", \"wf-b\"],\n  \"support_run_count\": 40\n}\n// after — 24 + 31 = 55\n{\n  \"id\": \"motif-retry-loop\",\n  \"variant_ids\": [\"wf-a\", \"wf-b\"],\n  \"support_run_count\": 55\n}","handlingStrategy":"validation","validationCode":"const motifRunDrift = (report) => {\n  const byID = new Map(report.workflow_variants.map((v) => [v.id, v]));\n  return report.motifs.filter((m) =>\n    m.support_run_count !== m.variant_ids.reduce((n, id) => n + (byID.get(id)?.eligible_runs ?? 0), 0));\n};","typeGuard":null,"tryCatchPattern":"try {\n  execFileSync(process.execPath, [VALIDATOR, reportPath, spansPath]);\n} catch (err) {\n  if (/support run count/.test(err.message)) {\n    // err.message carries fixture path, motif id, stored and expected sums\n    failCI(`derived count drift — regenerate fixture: ${err.message}`);\n  } else throw err;\n}","preventionTips":["Never hand-edit derived counts in fixtures; regenerate them with the report generator.","Run a pre-flight lint that recomputes motif sums before the conformance validator runs in CI.","Treat any edit to eligible_runs or variant_ids as invalidating every motif that references the variant."],"tags":["fixtures","cross-validation","motif","arithmetic","derived-field"],"backgroundTag":"derived-field-mismatch","analyzedSha":"766dce6b1394ebb56a3090748d5a0240a5aefb36","analyzedAt":"2026-08-18T03:14:35.516Z","contentChangedAt":"2026-08-18T03:14:35.516Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}