JuliusBrussee/caveman · error · Error

support variant count disagrees with its variant ids

Error message

${where} support variant count disagrees with its variant ids

What it means

support_variant_count is a redundant count that must equal the length of the motif's variant_ids array. The validator throws when they disagree, keeping every motif's structural counts re-derivable from its listed variants.

Solutions

  1. Set support_variant_count to variant_ids.length.
  2. Re-run the report generator so counts and id lists are recomputed together.
  3. If the variant list is wrong, re-derive which variants support the motif and fix the list.

Example fix

// before
{ "support_variant_count": 2, "variant_ids": ["v1", "v2", "v3"] }
// after
{ "support_variant_count": 3, "variant_ids": ["v1", "v2", "v3"] }
Defensive patterns

Strategy: validation

Validate before calling

for (const m of report.motifs) if (m.support_variant_count !== m.variant_ids.length) throw new Error(`motif ${m.id}: support_variant_count != variant_ids.length`);

Type guard

const motifCountsConsistent = (motif) => motif.support_variant_count === motif.variant_ids.length;

Try / catch

try { validateContinuousImprovement(report); } catch (e) { if (String(e.message).includes('support variant count disagrees')) { console.error('Set support_variant_count = variant_ids.length'); } else throw e; }

Prevention

When it happens

Trigger: A motif entry where motif.support_variant_count !== motif.variant_ids.length, e.g. after adding/removing variant ids without updating the count.

Common situations: Appending a variant id during fixture updates; filtering variants from a motif after regeneration; hand-editing one field and forgetting the other.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/b9b40658891720ee. Report an issue: GitHub.

Appendix: source

Thrown at packages/shared/contracts/scripts/validate-continuous-improvement.mjs:111

    const expectedBGivenA = relationship.shared_unit_count / relationship.theme_a_unit_count;
    const expectedAGivenB = relationship.shared_unit_count / relationship.theme_b_unit_count;
    if (Math.abs(relationship.probability_b_given_a - expectedBGivenA) > 1e-9) {
      throw new Error(`${where} probability_b_given_a ${relationship.probability_b_given_a} != ${expectedBGivenA}`);
    }
    if (Math.abs(relationship.probability_a_given_b - expectedAGivenB) > 1e-9) {
      throw new Error(`${where} probability_a_given_b ${relationship.probability_a_given_b} != ${expectedAGivenB}`);
    }
  }
  relationshipCount += report.relationships.length;

  // A motif is a structural count over variants this report carries, so every
  // part of it must be re-derivable from those variants.
  const variantsByID = new Map(report.workflow_variants.map((variant) => [variant.id, variant]));
  const familyIDs = new Set(report.task_families.map((family) => family.id));
  for (const motif of report.motifs) {
    const where = `report fixture ${reportPaths[index]}: motif ${motif.id}`;
    if (!familyIDs.has(motif.task_family_id)) throw new Error(`${where} references a task family that is not in this report`);
    if (motif.support_variant_count !== motif.variant_ids.length) throw new Error(`${where} support variant count disagrees with its variant ids`);
    let runs = 0;
    let weighted = 0;
    for (const variantID of motif.variant_ids) {
      const variant = variantsByID.get(variantID);
      if (!variant) throw new Error(`${where} references workflow variant ${variantID} that is not in this report`);
      if (variant.task_family_id !== motif.task_family_id) throw new Error(`${where} supporting variant ${variantID} belongs to another task family`);
      if (!contiguouslyContains(variant.signature, motif.operations)) {
        throw new Error(`${where} operations are not a contiguous subsequence of variant ${variantID}'s signature`);
      }
      runs += variant.eligible_runs;
      weighted += (motif.operations.length / variant.signature.length) * variant.eligible_runs;
    }
    if (motif.support_run_count !== runs) throw new Error(`${where} support run count ${motif.support_run_count} != ${runs}`);
    const expectedShare = runs > 0 ? weighted / runs : 0;
    if (Math.abs(motif.structural_cost_share - expectedShare) > 1e-6) {
      throw new Error(`${where} structural_cost_share ${motif.structural_cost_share} != ${expectedShare}`);
    }
  }

View on GitHub (pinned to 3ee70a1026)