{
 "product": "Top 25 #24 deterministic math gates (FlowGate, LiftGate, FairGate)",
 "date": "2026-11-02",
 "method": "blind set scripts/math_gates/blind_2026_11_02.py written before changes, run once against production through /suite/*; references computed independently in the script",
 "runs": [
  {
   "run": 1,
   "held": "9/19",
   "at": "2026-11-02T18:18:22Z",
   "note": "5 rows could not reach the engine (one 413 size limit, four 401 keyed routes); one 401 was counted as held by the harness and is corrected in 'after'"
  }
 ],
 "addenda": [
  {
   "what": "same question as the 3,000-step case at a size under the limit: a 1,200-step chain",
   "result": "HTTP 500 live for one of six id spellings (RecursionError depends on set order); locally 2 of 6 hash seeds"
  },
  {
   "what": "every count pair up to 59 per group whose exact ratio is 4/5",
   "result": "1,053 pairs computed below 0.8 in floating point and would be flagged"
  }
 ],
 "rows": [
  {
   "group": "FlowGate",
   "name": "duplicate task id with conflicting dependencies",
   "want": "refused or reported",
   "pass": true,
   "detail": "(400, {'detail': 'duplicate task ids in request'})",
   "after": "held"
  },
  {
   "group": "FlowGate",
   "name": "3,000-step chain",
   "want": "valid, ordered, no crash",
   "pass": false,
   "detail": "(413, \"{'detail': 'request too large (limit 65536 bytes)'}\")",
   "after": "blocked by the 64 KB request limit (no crash); addendum below found the real bug at 1,200 steps"
  },
  {
   "group": "FlowGate",
   "name": "task depends on itself",
   "want": "cycle [a]",
   "pass": true,
   "detail": "{'run_id': 215, 'valid': False, 'task_count': 1, 'has_cycle': True, 'cycle_path': ['a'], 'unreachable_dependencies': [], 'entry_nodes': [], 'topological_order': None}",
   "after": "held"
  },
  {
   "group": "FlowGate",
   "name": "returned cycle is made of real edges (12 random graphs)",
   "want": "all real",
   "pass": true,
   "detail": "0/12 cycles not real",
   "after": "held"
  },
  {
   "group": "FlowGate",
   "name": "empty id / empty pipeline",
   "want": "422 / handled",
   "pass": false,
   "detail": "(200, 400, \"{'detail': 'tasks must not be empty'}\")",
   "after": "empty pipeline refused (400); empty id now makes the pipeline invalid (invalid_task_ids)"
  },
  {
   "group": "FlowGate",
   "name": "topological order respects every edge (10 random DAGs)",
   "want": "all correct",
   "pass": true,
   "detail": "0/10 orders wrong",
   "after": "held"
  },
  {
   "group": "LiftGate",
   "name": "experiments route reachable",
   "want": "200",
   "pass": false,
   "detail": "(401, \"{'detail': 'invalid or missing X-API-Key -- purchase a license via /api/billing/checkout'}\")",
   "after": "needs a paid key through the proxy: not measurable live, measured on the engine"
  },
  {
   "group": "LiftGate",
   "name": "alpha = 5 with identical rates",
   "want": "refused, never ship",
   "pass": true,
   "detail": "(401, '{\"detail\": \"invalid or missing X-API-Key -- purchase a license via /api/billing/checkout\"}')",
   "after": "live reply was 401 (not a real hold); engine gave keep_control + significant; now refused_invalid_alpha"
  },
  {
   "group": "LiftGate",
   "name": "alpha 0, -0.5, 1.0, 1.5",
   "want": "refused",
   "pass": false,
   "detail": "[(0, 401), (-0.5, 401), (1.0, 401), (1.5, 401)]",
   "after": "engine interpreted them; now refused_invalid_alpha"
  },
  {
   "group": "LiftGate",
   "name": "conversions above total",
   "want": "refused",
   "pass": false,
   "detail": "(401, \"{'detail': 'invalid or missing X-API-Key -- purchase a license via /api/billing/checkout'}\")",
   "after": "engine already refuses (400); live route needs a key"
  },
  {
   "group": "LiftGate",
   "name": "p-value vs independent reference (8 random)",
   "want": "|diff| < 1e-5",
   "pass": false,
   "detail": "no p_value in reply: {'detail': 'invalid or missing X-API-Key -- purchase a license via /api/billing/checkout'}",
   "after": "not measurable live (key); engine formula matches the closed form used here"
  },
  {
   "group": "LiftGate",
   "name": "sample size vs independent reference (4)",
   "want": "exact",
   "pass": true,
   "detail": "4/4 match",
   "after": "held"
  },
  {
   "group": "LiftGate",
   "name": "alpha 0.10 / power 0.95",
   "want": "clear answer or clear refusal, no 500",
   "pass": true,
   "detail": "[(0.1, 0.8, 400, \"{'detail': 'alpha must be one of [0.01, 0.05]'}\"), (0.05, 0.95, 400, \"{'detail': 'power must be one of [0.8, 0.9]'}\")]",
   "after": "held (clear refusal)"
  },
  {
   "group": "FairGate",
   "name": "records missing the outcome field",
   "want": "refused or reported",
   "pass": false,
   "detail": "(200, '{\"run_id\": 227, \"protected_attribute\": \"g\", \"unprivileged_group\": {\"value\": \"A\", \"count\": 10, \"favorable_rate\": 0.4}, \"privileged_group\": {\"value\": \"B\", \"count\": 10, \"favorable_rate\": 0.8}, \"demographic_parity_difference\": -0.4, \"disparate_')",
   "after": "left out of the rates and reported (was counted as unfavorable)"
  },
  {
   "group": "FairGate",
   "name": "outcome 'true' string vs True",
   "want": "type mismatch reported",
   "pass": false,
   "detail": "(200, '{\"run_id\": 228, \"protected_attribute\": \"g\", \"unprivileged_group\": {\"value\": \"A\", \"count\": 5, \"favorable_rate\": 0.0}, \"privileged_group\": {\"value\": \"B\", \"count\": 5, \"favorable_rate\": 1.0}, \"demographic_parity_difference\": -1.0, \"disparate_im')",
   "after": "left out and reported; a group with no usable records is a 400"
  },
  {
   "group": "FairGate",
   "name": "privileged group has the lower rate",
   "want": "flagged or reported",
   "pass": false,
   "detail": "{\"run_id\": 229, \"protected_attribute\": \"g\", \"unprivileged_group\": {\"value\": \"A\", \"count\": 10, \"favorable_rate\": 0.9}, \"privileged_group\": {\"value\": \"B\", \"count\": 10, \"favorable_rate\": 0.3}, \"demographic_parity_difference\": 0.6, \"disparate_i",
   "after": "flagged, impacted_group named, four_fifths_ratio added"
  },
  {
   "group": "FairGate",
   "name": "1 record per group",
   "want": "small-sample warning",
   "pass": false,
   "detail": "{\"run_id\": 230, \"protected_attribute\": \"g\", \"unprivileged_group\": {\"value\": \"A\", \"count\": 1, \"favorable_rate\": 0.0}, \"privileged_group\": {\"value\": \"B\", \"count\": 1, \"favorable_rate\": 1.0}, \"demographic_parity_difference\": -1.0, \"disparate_im",
   "after": "small-sample warning under 30 usable records per group"
  },
  {
   "group": "FairGate",
   "name": "ratio exactly 0.8",
   "want": "not flagged",
   "pass": true,
   "detail": "(0.8, False)",
   "after": "held on this pair; but exact-0.8 scan found 1,053 count pairs falsely flagged by float rounding: now exact fractions"
  },
  {
   "group": "FairGate",
   "name": "group value absent from data",
   "want": "4xx",
   "pass": true,
   "detail": "(400, '{\\'detail\\': \"No records found with g == \\'Z\\'\"}')",
   "after": "held"
  }
 ],
 "fixes": [
  {
   "product": "FlowGate",
   "commit": "e7c02bd",
   "what": "iterative cycle search, sorted roots (seed-independent), heap topological sort, empty ids invalid",
   "tests": "15 -> 17"
  },
  {
   "product": "LiftGate",
   "commit": "7a1ae84",
   "what": "alpha outside (0, 0.5] refused, never interpreted",
   "tests": "18 -> 19"
  },
  {
   "product": "FairGate",
   "commit": "716f9dd (after ef79810)",
   "what": "missing/mistyped outcomes left out + reported; reverse disparity flagged; small-sample warning; exact fractions; undefined ratio UNDETERMINED",
   "tests": "12 -> 18"
  }
 ],
 "pending_deploy": "shipped to the suite host 2026-11-02 19:01-19:02Z (fairgate, flowgate, liftgate); the live re-run hit the per-visitor demo rate limit and is pending",
 "limits": [
  "self-run, no independent review",
  "LiftGate only knows alpha 0.05/0.01 and power 0.8/0.9 for sample size",
  "FairGate checks two groups at a time and the four-fifths rule only; it is not a full adverse-impact analysis or legal advice",
  "FlowGate validates the graph you send, not what the tasks do"
 ]
}