FAILURE MAP
← Case archive

FA-65301 / Epidemic compartment models / Open access

Two-patch SIR with daily migration: local mixing denominator · case 01

Force of infection uses stale census sizes as migration reshapes the patches.

Verified by executionVariant 1 · 7 checks per implementationDownload source bundle ↓JSON ↗

ROOT CAUSE

The mixing denominator is the initial census size rather than the current patch size.

VERIFIED REPAIR

Restore the local mixing denominator rule: `i[k] / n[k] if n[k] > 0`.

Unsuccessful approach: Pooling both patches in the denominator dilutes local transmission.

Case contract

Each day: local frequency-dependent SIR in each patch using the current patch size, then every compartment exchanges fraction travel of each patch simultaneously; return [S pair, I pair, R pair] rounded 3.

Why this case matters

Compartmental epidemic calculations drive outbreak forecasts, vaccine targets and hospital planning; a single wrong flow, rate conversion or boundary silently changes every downstream number.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(beta, gamma, pops, i0s, travel, days):
    s = [float(pops[k] - i0s[k]) for k in range(2)]
    i = [float(x) for x in i0s]
    r = [0.0, 0.0]
    for _ in range(days):
        n = [s[k] + i[k] + r[k] for k in range(2)]
        inf = [beta * s[k] * i[k] / pops[k] if n[k] > 0 else 0.0 for k in range(2)]
        rec = [gamma * i[k] for k in range(2)]
        for k in range(2):
            s[k] -= inf[k]
            i[k] += inf[k] - rec[k]
            r[k] += rec[k]
        for comp in (s, i, r):
            a, b = comp[0] * travel, comp[1] * travel
            comp[0] += b - a
            comp[1] += a - b
    return [[round(x, 3) for x in s], [round(x, 3) for x in i], [round(x, 3) for x in r]]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: city and town',
   (0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
   [[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
  ('regression: isolated patches',
   (0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
   [[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
  ('regression: high mobility',
   (0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
   [[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
  ('regression: both seeded',
   (0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
   [[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
  ('control: boundary zero days',
   (0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
   [[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
  ('regression: equal patches',
   (0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
   [[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
  ('regression: tiny second patch',
   (0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
   [[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
 [('regression: city and town',
   (0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
   [[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
  ('regression: isolated patches',
   (0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
   [[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
  ('regression: high mobility',
   (0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
   [[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
  ('regression: both seeded',
   (0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
   [[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
  ('control: boundary zero days',
   (0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
   [[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
  ('regression: equal patches',
   (0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
   [[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
  ('regression: tiny second patch',
   (0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
   [[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
 [('regression: city and town',
   (0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
   [[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
  ('regression: isolated patches',
   (0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
   [[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
  ('regression: high mobility',
   (0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
   [[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
  ('regression: both seeded',
   (0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
   [[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
  ('control: boundary zero days',
   (0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
   [[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
  ('regression: equal patches',
   (0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
   [[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
  ('regression: tiny second patch',
   (0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
   [[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
 [('regression: city and town',
   (0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
   [[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
  ('regression: isolated patches',
   (0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
   [[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
  ('regression: high mobility',
   (0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
   [[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
  ('regression: both seeded',
   (0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
   [[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
  ('control: boundary zero days',
   (0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
   [[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
  ('regression: equal patches',
   (0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
   [[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
  ('regression: tiny second patch',
   (0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
   [[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
 [('regression: city and town',
   (0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
   [[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
  ('regression: isolated patches',
   (0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
   [[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
  ('regression: high mobility',
   (0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
   [[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
  ('regression: both seeded',
   (0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
   [[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
  ('control: boundary zero days',
   (0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
   [[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
  ('regression: equal patches',
   (0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
   [[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
  ('regression: tiny second patch',
   (0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
   [[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])]]
for label, args, expected in fixtures[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: city and town[[632.516, 277.348], [60.019, 136.977], [46.937, 46.203]][[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]Failed
regression: isolated patches[[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]][[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]Passed
regression: high mobility[[527.582, 544.189], [51.089, 37.902], [20.101, 19.138]][[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]Failed
regression: both seeded[[564.251, 513.365], [33.436, 53.757], [16.057, 19.134]][[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]Failed
control: boundary zero days[[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]][[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]Passed
regression: equal patches[[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]][[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]Passed
regression: tiny second patch[[1303.081, 328.726], [193.226, -127.086], [203.914, 148.139]][[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]]Failed

SHA-256 / 9845fcf3533d0a17605d130d949fc97346395e5b2419ed7ec4a5cf664d472bd8

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(beta, gamma, pops, i0s, travel, days):
    s = [float(pops[k] - i0s[k]) for k in range(2)]
    i = [float(x) for x in i0s]
    r = [0.0, 0.0]
    for _ in range(days):
        n = [s[k] + i[k] + r[k] for k in range(2)]
        inf = [beta * s[k] * i[k] / (n[0] + n[1]) if n[k] > 0 else 0.0 for k in range(2)]
        rec = [gamma * i[k] for k in range(2)]
        for k in range(2):
            s[k] -= inf[k]
            i[k] += inf[k] - rec[k]
            r[k] += rec[k]
        for comp in (s, i, r):
            a, b = comp[0] * travel, comp[1] * travel
            comp[0] += b - a
            comp[1] += a - b
    return [[round(x, 3) for x in s], [round(x, 3) for x in i], [round(x, 3) for x in r]]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: city and town',
   (0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
   [[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
  ('regression: isolated patches',
   (0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
   [[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
  ('regression: high mobility',
   (0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
   [[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
  ('regression: both seeded',
   (0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
   [[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
  ('control: boundary zero days',
   (0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
   [[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
  ('regression: equal patches',
   (0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
   [[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
  ('regression: tiny second patch',
   (0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
   [[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
 [('regression: city and town',
   (0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
   [[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
  ('regression: isolated patches',
   (0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
   [[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
  ('regression: high mobility',
   (0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
   [[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
  ('regression: both seeded',
   (0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
   [[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
  ('control: boundary zero days',
   (0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
   [[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
  ('regression: equal patches',
   (0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
   [[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
  ('regression: tiny second patch',
   (0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
   [[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
 [('regression: city and town',
   (0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
   [[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
  ('regression: isolated patches',
   (0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
   [[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
  ('regression: high mobility',
   (0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
   [[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
  ('regression: both seeded',
   (0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
   [[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
  ('control: boundary zero days',
   (0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
   [[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
  ('regression: equal patches',
   (0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
   [[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
  ('regression: tiny second patch',
   (0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
   [[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
 [('regression: city and town',
   (0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
   [[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
  ('regression: isolated patches',
   (0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
   [[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
  ('regression: high mobility',
   (0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
   [[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
  ('regression: both seeded',
   (0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
   [[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
  ('control: boundary zero days',
   (0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
   [[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
  ('regression: equal patches',
   (0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
   [[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
  ('regression: tiny second patch',
   (0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
   [[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
 [('regression: city and town',
   (0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
   [[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
  ('regression: isolated patches',
   (0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
   [[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
  ('regression: high mobility',
   (0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
   [[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
  ('regression: both seeded',
   (0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
   [[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
  ('control: boundary zero days',
   (0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
   [[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
  ('regression: equal patches',
   (0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
   [[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
  ('regression: tiny second patch',
   (0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
   [[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])]]
for label, args, expected in fixtures[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: city and town[[685.738, 442.177], [25.06, 7.088], [28.673, 11.264]][[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]Failed
regression: isolated patches[[487.211, 500.0], [4.867, 0.0], [7.922, 0.0]][[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]Failed
regression: high mobility[[583.322, 585.599], [6.841, 6.934], [8.608, 8.696]][[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]Failed
regression: both seeded[[599.894, 573.207], [7.374, 6.823], [6.476, 6.226]][[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]Failed
control: boundary zero days[[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]][[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]Passed
regression: equal patches[[389.905, 391.349], [5.376, 4.61], [4.72, 4.041]][[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]Failed
regression: tiny second patch[[1355.465, 320.18], [167.906, 9.405], [176.85, 20.195]][[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]]Failed

SHA-256 / 125a2b1904361d582ca96946177e0caac272303cec58cf3e0d0c60b06baae693

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(beta, gamma, pops, i0s, travel, days):
    s = [float(pops[k] - i0s[k]) for k in range(2)]
    i = [float(x) for x in i0s]
    r = [0.0, 0.0]
    for _ in range(days):
        n = [s[k] + i[k] + r[k] for k in range(2)]
        inf = [beta * s[k] * i[k] / n[k] if n[k] > 0 else 0.0 for k in range(2)]
        rec = [gamma * i[k] for k in range(2)]
        for k in range(2):
            s[k] -= inf[k]
            i[k] += inf[k] - rec[k]
            r[k] += rec[k]
        for comp in (s, i, r):
            a, b = comp[0] * travel, comp[1] * travel
            comp[0] += b - a
            comp[1] += a - b
    return [[round(x, 3) for x in s], [round(x, 3) for x in i], [round(x, 3) for x in r]]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: city and town',
   (0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
   [[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
  ('regression: isolated patches',
   (0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
   [[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
  ('regression: high mobility',
   (0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
   [[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
  ('regression: both seeded',
   (0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
   [[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
  ('control: boundary zero days',
   (0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
   [[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
  ('regression: equal patches',
   (0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
   [[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
  ('regression: tiny second patch',
   (0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
   [[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
 [('regression: city and town',
   (0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
   [[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
  ('regression: isolated patches',
   (0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
   [[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
  ('regression: high mobility',
   (0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
   [[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
  ('regression: both seeded',
   (0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
   [[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
  ('control: boundary zero days',
   (0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
   [[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
  ('regression: equal patches',
   (0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
   [[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
  ('regression: tiny second patch',
   (0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
   [[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
 [('regression: city and town',
   (0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
   [[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
  ('regression: isolated patches',
   (0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
   [[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
  ('regression: high mobility',
   (0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
   [[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
  ('regression: both seeded',
   (0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
   [[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
  ('control: boundary zero days',
   (0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
   [[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
  ('regression: equal patches',
   (0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
   [[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
  ('regression: tiny second patch',
   (0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
   [[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
 [('regression: city and town',
   (0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
   [[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
  ('regression: isolated patches',
   (0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
   [[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
  ('regression: high mobility',
   (0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
   [[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
  ('regression: both seeded',
   (0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
   [[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
  ('control: boundary zero days',
   (0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
   [[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
  ('regression: equal patches',
   (0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
   [[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
  ('regression: tiny second patch',
   (0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
   [[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])],
 [('regression: city and town',
   (0.5, 0.2, [1000, 200], [10, 0], 0.05, 10),
   [[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]),
  ('regression: isolated patches',
   (0.4, 0.2, [500, 500], [5, 0], 0.0, 8),
   [[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]),
  ('regression: high mobility',
   (0.6, 0.25, [300, 900], [0, 9], 0.3, 6),
   [[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]),
  ('regression: both seeded',
   (0.3, 0.1, [800, 400], [4, 4], 0.1, 12),
   [[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]),
  ('control: boundary zero days',
   (0.5, 0.2, [100, 100], [1, 1], 0.1, 0),
   [[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]),
  ('regression: equal patches',
   (0.5, 0.2, [400, 400], [8, 0], 0.2, 5),
   [[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]),
  ('regression: tiny second patch',
   (0.7, 0.3, [2000, 50], [20, 0], 0.02, 9),
   [[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]])]]
for label, args, expected in fixtures[N - 1]:
    check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
Boundary fixtureActualExpectedOutcome
regression: city and town[[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]][[611.99, 397.105], [74.874, 37.65], [52.607, 25.773]]Passed
regression: isolated patches[[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]][[464.204, 500.0], [19.812, 0.0], [15.984, 0.0]]Passed
regression: high mobility[[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]][[557.673, 559.801], [25.331, 25.533], [15.766, 15.895]]Passed
regression: both seeded[[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]][[565.74, 538.406], [32.741, 32.614], [15.262, 15.237]]Passed
control: boundary zero days[[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]][[99.0, 99.0], [1.0, 1.0], [0.0, 0.0]]Passed
regression: equal patches[[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]][[377.224, 380.426], [15.15, 13.039], [7.625, 6.535]]Passed
regression: tiny second patch[[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]][[1241.271, 264.206], [242.617, 45.744], [216.332, 39.829]]Passed

SHA-256 / 51a896a1cb28b1f0d3684691da7e86c9e86b63e9720f8c4963f702f1372f0643

Verification & scope

Deterministic bounded teaching model with a stipulated contract; not a validated scientific or public-health modelling library. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.

Observations recorded using Python 3.12.14 at 2026-09-29T14:47:32.653065+00:00.

Case digest / bd68dcc79b489e605f06e380a4c937c97cdaa290066b6d2def88cec42b6c8378