{"record":{"id":"9f3b56acf6548921","repo":"JuliusBrussee/caveman","slug":"where-structural-cost-share-motif-structural","errorCode":null,"errorMessage":"${where} structural_cost_share ${motif.structural_cost_share} != ${expectedShare}","messagePattern":"(.+?) structural_cost_share (.+?) != (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/shared/contracts/scripts/validate-continuous-improvement.mjs","lineNumber":127,"sourceCode":"    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);\n    if (roles.join(\",\") !== \"baseline,alternative\") throw new Error(`${where} cohort arms are not baseline then alternative`);\n    const armVariants = new Map();\n    let comparedUnits = 0;","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/766dce6b1394ebb56a3090748d5a0240a5aefb36/packages/shared/contracts/scripts/validate-continuous-improvement.mjs#L109-L145","documentation":"The validator recomputes a motif's structural_cost_share as the eligible-run-weighted average of motif.operations.length / variant.signature.length over every supporting variant (tolerance 1e-6) and throws when the stored value drifts beyond it (validate-continuous-improvement.mjs:126-128). This keeps the share an evidence figure the reader can re-derive rather than an assertion. The typical cause is a rounded or stale stored value, not a disagreement about the formula.","triggerScenarios":"The fixture stores structural_cost_share rounded to 4 decimals while the weighted average needs full double precision; a variant's signature length or eligible_runs changed after the share was computed; motif.operations gained or lost an operation without recomputing. Note the check runs only after support_run_count already matched (error 600), so the inputs to the average are consistent.","commonSituations":"Serializing floats through a formatter that truncates digits (toFixed(4), JSON writers that round); hand-computing the share in a spreadsheet and pasting a rounded number; a generator emitting shares from an earlier pass over the variants.","solutions":["Recompute the share in full double precision: expectedShare = Σ(operations.length / signature.length × eligible_runs) / Σ(eligible_runs), and store it unrounded.","Check the inputs to the average — each ratio uses that variant's current signature length and the motif's current operations list.","When the recomputed runs total is 0, the expected share is exactly 0 — store 0, not a leftover ratio.","Re-run the validator."],"exampleFix":"// before — ops length 3; wf-a signature 6 (24 runs), wf-b signature 9 (31 runs)\n{ \"structural_cost_share\": 0.5 }\n// after — (3/6*24 + 3/9*31) / 55 = 0.40606060606060607\n{ \"structural_cost_share\": 0.40606060606060607 }","handlingStrategy":"validation","validationCode":"const shareDrift = (report) => {\n  const byID = new Map(report.workflow_variants.map((v) => [v.id, v]));\n  return report.motifs.filter((m) => {\n    let runs = 0, weighted = 0;\n    for (const id of m.variant_ids) {\n      const v = byID.get(id);\n      runs += v.eligible_runs;\n      weighted += (m.operations.length / v.signature.length) * v.eligible_runs;\n    }\n    return Math.abs(m.structural_cost_share - (runs > 0 ? weighted / runs : 0)) > 1e-6;\n  });\n};","typeGuard":null,"tryCatchPattern":"try {\n  execFileSync(process.execPath, [VALIDATOR, reportPath, spansPath]);\n} catch (err) {\n  if (/structural_cost_share/.test(err.message)) {\n    failCI(`rounded or stale share — recompute in full precision: ${err.message}`);\n  } else throw err;\n}","preventionTips":["Never round derived floats when writing fixtures — store the full double the formula produces.","Keep the 1e-6 tolerance in mind: anything past six decimal digits of drift fails.","Fix support_run_count drift (error 600) first; the share is computed from the same inputs."],"tags":["fixtures","cross-validation","motif","floating-point","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"}