{
  "title": "Hold segment weights fixed when a blended retention rate moves",
  "synthetic": true,
  "inputs": {
    "rateA": 0.3,
    "rateB": 0.1,
    "mixBefore": 0.2,
    "mixAfter": 0.8
  },
  "outputs": [
    {
      "label": "Before blended retention %",
      "actual": 14.000000000000002,
      "expected": 14,
      "passed": true
    },
    {
      "label": "After blended retention %",
      "actual": 26,
      "expected": 26,
      "passed": true
    },
    {
      "label": "Composition-only difference points",
      "actual": 12.000000000000002,
      "expected": 12,
      "passed": true
    }
  ],
  "constraints": [
    "v.rateA<=1",
    "v.rateB<=1",
    "v.mixBefore<=1",
    "v.mixAfter<=1"
  ],
  "formulas": [
    {
      "label": "Before blended retention %",
      "javascript": "100*(v.rateA*v.mixBefore+v.rateB*(1-v.mixBefore))"
    },
    {
      "label": "After blended retention %",
      "javascript": "100*(v.rateA*v.mixAfter+v.rateB*(1-v.mixAfter))"
    },
    {
      "label": "Composition-only difference points",
      "javascript": "100*(v.rateA-v.rateB)*(v.mixAfter-v.mixBefore)"
    }
  ],
  "limits": "Two segments rarely capture every confounder. This is a standardisation illustration, not a causal adjustment or a claim that real segments would retain fixed performance after a large budget change."
}
