FAILURE MAP
← Case archive

FA-65701 / Ecological population dynamics / Open access

Two-patch source-sink dispersal with ceilings: ceiling ordering · case 01

Excess recruits above the ceiling disperse into the other patch.

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

ROOT CAUSE

The ceiling is never applied.

VERIFIED REPAIR

Restore the ceiling ordering rule: `grown = [min(n[j] * lambdas[j], caps[j]) for j in range(2)]`.

Unsuccessful approach: Applying ceilings after dispersal lets surplus from a full patch rescue the sink.

Case contract

Each year each patch grows by its lambda and is capped at its own ceiling, then fraction disperse of each post-growth patch moves to the other simultaneously; return yearly [N1, N2] rounded 4.

Why this case matters

Population projections set harvest quotas, conservation status and pest-control timing; a wrong update order, boundary or rate conversion silently changes management advice.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(n0s, lambdas, caps, disperse, years):
    n = [float(x) for x in n0s]
    traj = []
    for _ in range(years):
        grown = [n[j] * lambdas[j] for j in range(2)]
        out = [grown[j] * disperse for j in range(2)]
        n = [grown[0] - out[0] + out[1], grown[1] - out[1] + out[0]]
        traj.append([round(x, 4) for x in n])
    return traj
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: meadow source woodland sink',
   ([100, 20], [1.5, 0.7], [200, 200], 0.2, 5),
   [[122.8, 41.2], [153.128, 59.912], [168.3877, 73.5507], [170.2971, 81.1884], [171.3664, 85.4655]]),
  ('regression: ceiling binding in source',
   ([180, 10], [1.4, 0.8], [200, 50], 0.1, 4),
   [[180.8, 27.2], [182.176, 39.584], [183.1667, 48.5005], [183.88, 54.9203]]),
  ('control: no dispersal',
   ([50, 50], [1.2, 0.9], [100, 100], 0.0, 3),
   [[60.0, 45.0], [72.0, 40.5], [86.4, 36.45]]),
  ('control: full exchange',
   ([60, 0], [1.1, 0.5], [100, 100], 1.0, 3),
   [[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]]),
  ('control: both sinks',
   ([100, 100], [0.8, 0.6], [150, 150], 0.3, 4),
   [[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]]),
  ('regression: sink ceiling binding',
   ([10, 120], [1.3, 1.2], [300, 100], 0.25, 4),
   [[34.75, 78.25], [57.3563, 81.7188], [80.438, 92.1877], [103.427, 101.1423]]),
  ('regression: unequal ceilings',
   ([90, 40], [2.0, 1.5], [120, 60], 0.05, 5),
   [[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]])],
 [('regression: meadow source woodland sink',
   ([100, 20], [1.5, 0.7], [200, 200], 0.2, 5),
   [[122.8, 41.2], [153.128, 59.912], [168.3877, 73.5507], [170.2971, 81.1884], [171.3664, 85.4655]]),
  ('regression: ceiling binding in source',
   ([180, 10], [1.4, 0.8], [200, 50], 0.1, 4),
   [[180.8, 27.2], [182.176, 39.584], [183.1667, 48.5005], [183.88, 54.9203]]),
  ('control: no dispersal',
   ([50, 50], [1.2, 0.9], [100, 100], 0.0, 3),
   [[60.0, 45.0], [72.0, 40.5], [86.4, 36.45]]),
  ('control: full exchange',
   ([60, 0], [1.1, 0.5], [100, 100], 1.0, 3),
   [[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]]),
  ('control: both sinks',
   ([100, 100], [0.8, 0.6], [150, 150], 0.3, 4),
   [[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]]),
  ('regression: sink ceiling binding',
   ([10, 120], [1.3, 1.2], [300, 100], 0.25, 4),
   [[34.75, 78.25], [57.3563, 81.7188], [80.438, 92.1877], [103.427, 101.1423]]),
  ('regression: unequal ceilings',
   ([90, 40], [2.0, 1.5], [120, 60], 0.05, 5),
   [[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]])],
 [('regression: meadow source woodland sink',
   ([100, 20], [1.5, 0.7], [200, 200], 0.2, 5),
   [[122.8, 41.2], [153.128, 59.912], [168.3877, 73.5507], [170.2971, 81.1884], [171.3664, 85.4655]]),
  ('regression: ceiling binding in source',
   ([180, 10], [1.4, 0.8], [200, 50], 0.1, 4),
   [[180.8, 27.2], [182.176, 39.584], [183.1667, 48.5005], [183.88, 54.9203]]),
  ('control: no dispersal',
   ([50, 50], [1.2, 0.9], [100, 100], 0.0, 3),
   [[60.0, 45.0], [72.0, 40.5], [86.4, 36.45]]),
  ('control: full exchange',
   ([60, 0], [1.1, 0.5], [100, 100], 1.0, 3),
   [[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]]),
  ('control: both sinks',
   ([100, 100], [0.8, 0.6], [150, 150], 0.3, 4),
   [[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]]),
  ('regression: sink ceiling binding',
   ([10, 120], [1.3, 1.2], [300, 100], 0.25, 4),
   [[34.75, 78.25], [57.3563, 81.7188], [80.438, 92.1877], [103.427, 101.1423]]),
  ('regression: unequal ceilings',
   ([90, 40], [2.0, 1.5], [120, 60], 0.05, 5),
   [[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]])],
 [('regression: meadow source woodland sink',
   ([100, 20], [1.5, 0.7], [200, 200], 0.2, 5),
   [[122.8, 41.2], [153.128, 59.912], [168.3877, 73.5507], [170.2971, 81.1884], [171.3664, 85.4655]]),
  ('regression: ceiling binding in source',
   ([180, 10], [1.4, 0.8], [200, 50], 0.1, 4),
   [[180.8, 27.2], [182.176, 39.584], [183.1667, 48.5005], [183.88, 54.9203]]),
  ('control: no dispersal',
   ([50, 50], [1.2, 0.9], [100, 100], 0.0, 3),
   [[60.0, 45.0], [72.0, 40.5], [86.4, 36.45]]),
  ('control: full exchange',
   ([60, 0], [1.1, 0.5], [100, 100], 1.0, 3),
   [[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]]),
  ('control: both sinks',
   ([100, 100], [0.8, 0.6], [150, 150], 0.3, 4),
   [[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]]),
  ('regression: sink ceiling binding',
   ([10, 120], [1.3, 1.2], [300, 100], 0.25, 4),
   [[34.75, 78.25], [57.3563, 81.7188], [80.438, 92.1877], [103.427, 101.1423]]),
  ('regression: unequal ceilings',
   ([90, 40], [2.0, 1.5], [120, 60], 0.05, 5),
   [[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]])],
 [('regression: meadow source woodland sink',
   ([100, 20], [1.5, 0.7], [200, 200], 0.2, 5),
   [[122.8, 41.2], [153.128, 59.912], [168.3877, 73.5507], [170.2971, 81.1884], [171.3664, 85.4655]]),
  ('regression: ceiling binding in source',
   ([180, 10], [1.4, 0.8], [200, 50], 0.1, 4),
   [[180.8, 27.2], [182.176, 39.584], [183.1667, 48.5005], [183.88, 54.9203]]),
  ('control: no dispersal',
   ([50, 50], [1.2, 0.9], [100, 100], 0.0, 3),
   [[60.0, 45.0], [72.0, 40.5], [86.4, 36.45]]),
  ('control: full exchange',
   ([60, 0], [1.1, 0.5], [100, 100], 1.0, 3),
   [[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]]),
  ('control: both sinks',
   ([100, 100], [0.8, 0.6], [150, 150], 0.3, 4),
   [[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]]),
  ('regression: sink ceiling binding',
   ([10, 120], [1.3, 1.2], [300, 100], 0.25, 4),
   [[34.75, 78.25], [57.3563, 81.7188], [80.438, 92.1877], [103.427, 101.1423]]),
  ('regression: unequal ceilings',
   ([90, 40], [2.0, 1.5], [120, 60], 0.05, 5),
   [[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]])]]
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: meadow source woodland sink[[122.8, 41.2], [153.128, 59.912], [192.1413, 79.4891], [241.698, 102.1563], [304.3395, 129.7169]][[122.8, 41.2], [153.128, 59.912], [168.3877, 73.5507], [170.2971, 81.1884], [171.3664, 85.4655]]Failed
regression: ceiling binding in source[[227.6, 32.4], [289.368, 55.192], [369.019, 80.2498], [471.384, 109.4425]][[180.8, 27.2], [182.176, 39.584], [183.1667, 48.5005], [183.88, 54.9203]]Failed
control: no dispersal[[60.0, 45.0], [72.0, 40.5], [86.4, 36.45]][[60.0, 45.0], [72.0, 40.5], [86.4, 36.45]]Passed
control: full exchange[[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]][[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]]Passed
control: both sinks[[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]][[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]]Passed
regression: sink ceiling binding[[45.75, 111.25], [77.9813, 114.9938], [110.5298, 128.8383], [146.4181, 151.8767]][[34.75, 78.25], [57.3563, 81.7188], [80.438, 92.1877], [103.427, 101.1423]]Failed
regression: unequal ceilings[[174.0, 66.0], [335.55, 111.45], [645.9038, 192.3713], [1241.645, 338.7194], [2384.5294, 606.8397]][[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]]Failed

SHA-256 / 01165a77cdbcf7b37b223799629b479cefb84d1a82c684adebf7de266908129d

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(n0s, lambdas, caps, disperse, years):
    n = [float(x) for x in n0s]
    traj = []
    for _ in range(years):
        grown = [n[j] * lambdas[j] for j in range(2)]
        out = [grown[j] * disperse for j in range(2)]
        n = [min(grown[0] - out[0] + out[1], caps[0]), min(grown[1] - out[1] + out[0], caps[1])]
        traj.append([round(x, 4) for x in n])
    return traj
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: meadow source woodland sink',
   ([100, 20], [1.5, 0.7], [200, 200], 0.2, 5),
   [[122.8, 41.2], [153.128, 59.912], [168.3877, 73.5507], [170.2971, 81.1884], [171.3664, 85.4655]]),
  ('regression: ceiling binding in source',
   ([180, 10], [1.4, 0.8], [200, 50], 0.1, 4),
   [[180.8, 27.2], [182.176, 39.584], [183.1667, 48.5005], [183.88, 54.9203]]),
  ('control: no dispersal',
   ([50, 50], [1.2, 0.9], [100, 100], 0.0, 3),
   [[60.0, 45.0], [72.0, 40.5], [86.4, 36.45]]),
  ('control: full exchange',
   ([60, 0], [1.1, 0.5], [100, 100], 1.0, 3),
   [[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]]),
  ('control: both sinks',
   ([100, 100], [0.8, 0.6], [150, 150], 0.3, 4),
   [[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]]),
  ('regression: sink ceiling binding',
   ([10, 120], [1.3, 1.2], [300, 100], 0.25, 4),
   [[34.75, 78.25], [57.3563, 81.7188], [80.438, 92.1877], [103.427, 101.1423]]),
  ('regression: unequal ceilings',
   ([90, 40], [2.0, 1.5], [120, 60], 0.05, 5),
   [[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]])],
 [('regression: meadow source woodland sink',
   ([100, 20], [1.5, 0.7], [200, 200], 0.2, 5),
   [[122.8, 41.2], [153.128, 59.912], [168.3877, 73.5507], [170.2971, 81.1884], [171.3664, 85.4655]]),
  ('regression: ceiling binding in source',
   ([180, 10], [1.4, 0.8], [200, 50], 0.1, 4),
   [[180.8, 27.2], [182.176, 39.584], [183.1667, 48.5005], [183.88, 54.9203]]),
  ('control: no dispersal',
   ([50, 50], [1.2, 0.9], [100, 100], 0.0, 3),
   [[60.0, 45.0], [72.0, 40.5], [86.4, 36.45]]),
  ('control: full exchange',
   ([60, 0], [1.1, 0.5], [100, 100], 1.0, 3),
   [[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]]),
  ('control: both sinks',
   ([100, 100], [0.8, 0.6], [150, 150], 0.3, 4),
   [[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]]),
  ('regression: sink ceiling binding',
   ([10, 120], [1.3, 1.2], [300, 100], 0.25, 4),
   [[34.75, 78.25], [57.3563, 81.7188], [80.438, 92.1877], [103.427, 101.1423]]),
  ('regression: unequal ceilings',
   ([90, 40], [2.0, 1.5], [120, 60], 0.05, 5),
   [[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]])],
 [('regression: meadow source woodland sink',
   ([100, 20], [1.5, 0.7], [200, 200], 0.2, 5),
   [[122.8, 41.2], [153.128, 59.912], [168.3877, 73.5507], [170.2971, 81.1884], [171.3664, 85.4655]]),
  ('regression: ceiling binding in source',
   ([180, 10], [1.4, 0.8], [200, 50], 0.1, 4),
   [[180.8, 27.2], [182.176, 39.584], [183.1667, 48.5005], [183.88, 54.9203]]),
  ('control: no dispersal',
   ([50, 50], [1.2, 0.9], [100, 100], 0.0, 3),
   [[60.0, 45.0], [72.0, 40.5], [86.4, 36.45]]),
  ('control: full exchange',
   ([60, 0], [1.1, 0.5], [100, 100], 1.0, 3),
   [[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]]),
  ('control: both sinks',
   ([100, 100], [0.8, 0.6], [150, 150], 0.3, 4),
   [[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]]),
  ('regression: sink ceiling binding',
   ([10, 120], [1.3, 1.2], [300, 100], 0.25, 4),
   [[34.75, 78.25], [57.3563, 81.7188], [80.438, 92.1877], [103.427, 101.1423]]),
  ('regression: unequal ceilings',
   ([90, 40], [2.0, 1.5], [120, 60], 0.05, 5),
   [[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]])],
 [('regression: meadow source woodland sink',
   ([100, 20], [1.5, 0.7], [200, 200], 0.2, 5),
   [[122.8, 41.2], [153.128, 59.912], [168.3877, 73.5507], [170.2971, 81.1884], [171.3664, 85.4655]]),
  ('regression: ceiling binding in source',
   ([180, 10], [1.4, 0.8], [200, 50], 0.1, 4),
   [[180.8, 27.2], [182.176, 39.584], [183.1667, 48.5005], [183.88, 54.9203]]),
  ('control: no dispersal',
   ([50, 50], [1.2, 0.9], [100, 100], 0.0, 3),
   [[60.0, 45.0], [72.0, 40.5], [86.4, 36.45]]),
  ('control: full exchange',
   ([60, 0], [1.1, 0.5], [100, 100], 1.0, 3),
   [[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]]),
  ('control: both sinks',
   ([100, 100], [0.8, 0.6], [150, 150], 0.3, 4),
   [[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]]),
  ('regression: sink ceiling binding',
   ([10, 120], [1.3, 1.2], [300, 100], 0.25, 4),
   [[34.75, 78.25], [57.3563, 81.7188], [80.438, 92.1877], [103.427, 101.1423]]),
  ('regression: unequal ceilings',
   ([90, 40], [2.0, 1.5], [120, 60], 0.05, 5),
   [[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]])],
 [('regression: meadow source woodland sink',
   ([100, 20], [1.5, 0.7], [200, 200], 0.2, 5),
   [[122.8, 41.2], [153.128, 59.912], [168.3877, 73.5507], [170.2971, 81.1884], [171.3664, 85.4655]]),
  ('regression: ceiling binding in source',
   ([180, 10], [1.4, 0.8], [200, 50], 0.1, 4),
   [[180.8, 27.2], [182.176, 39.584], [183.1667, 48.5005], [183.88, 54.9203]]),
  ('control: no dispersal',
   ([50, 50], [1.2, 0.9], [100, 100], 0.0, 3),
   [[60.0, 45.0], [72.0, 40.5], [86.4, 36.45]]),
  ('control: full exchange',
   ([60, 0], [1.1, 0.5], [100, 100], 1.0, 3),
   [[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]]),
  ('control: both sinks',
   ([100, 100], [0.8, 0.6], [150, 150], 0.3, 4),
   [[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]]),
  ('regression: sink ceiling binding',
   ([10, 120], [1.3, 1.2], [300, 100], 0.25, 4),
   [[34.75, 78.25], [57.3563, 81.7188], [80.438, 92.1877], [103.427, 101.1423]]),
  ('regression: unequal ceilings',
   ([90, 40], [2.0, 1.5], [120, 60], 0.05, 5),
   [[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]])]]
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: meadow source woodland sink[[122.8, 41.2], [153.128, 59.912], [192.1413, 79.4891], [200, 102.1563], [200, 117.2075]][[122.8, 41.2], [153.128, 59.912], [168.3877, 73.5507], [170.2971, 81.1884], [171.3664, 85.4655]]Failed
regression: ceiling binding in source[[200, 32.4], [200, 50], [200, 50], [200, 50]][[180.8, 27.2], [182.176, 39.584], [183.1667, 48.5005], [183.88, 54.9203]]Failed
control: no dispersal[[60.0, 45.0], [72.0, 40.5], [86.4, 36.45]][[60.0, 45.0], [72.0, 40.5], [86.4, 36.45]]Passed
control: full exchange[[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]][[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]]Passed
control: both sinks[[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]][[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]]Passed
regression: sink ceiling binding[[45.75, 100], [74.6063, 100], [102.7411, 100], [130.1726, 100]][[34.75, 78.25], [57.3563, 81.7188], [80.438, 92.1877], [103.427, 101.1423]]Failed
regression: unequal ceilings[[120, 60], [120, 60], [120, 60], [120, 60], [120, 60]][[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]]Failed

SHA-256 / ec9f18e7f95e6bbf33b9dbcad9905a767ab1db714f80a91d682ec6e5e3fd5375

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(n0s, lambdas, caps, disperse, years):
    n = [float(x) for x in n0s]
    traj = []
    for _ in range(years):
        grown = [min(n[j] * lambdas[j], caps[j]) for j in range(2)]
        out = [grown[j] * disperse for j in range(2)]
        n = [grown[0] - out[0] + out[1], grown[1] - out[1] + out[0]]
        traj.append([round(x, 4) for x in n])
    return traj
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: meadow source woodland sink',
   ([100, 20], [1.5, 0.7], [200, 200], 0.2, 5),
   [[122.8, 41.2], [153.128, 59.912], [168.3877, 73.5507], [170.2971, 81.1884], [171.3664, 85.4655]]),
  ('regression: ceiling binding in source',
   ([180, 10], [1.4, 0.8], [200, 50], 0.1, 4),
   [[180.8, 27.2], [182.176, 39.584], [183.1667, 48.5005], [183.88, 54.9203]]),
  ('control: no dispersal',
   ([50, 50], [1.2, 0.9], [100, 100], 0.0, 3),
   [[60.0, 45.0], [72.0, 40.5], [86.4, 36.45]]),
  ('control: full exchange',
   ([60, 0], [1.1, 0.5], [100, 100], 1.0, 3),
   [[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]]),
  ('control: both sinks',
   ([100, 100], [0.8, 0.6], [150, 150], 0.3, 4),
   [[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]]),
  ('regression: sink ceiling binding',
   ([10, 120], [1.3, 1.2], [300, 100], 0.25, 4),
   [[34.75, 78.25], [57.3563, 81.7188], [80.438, 92.1877], [103.427, 101.1423]]),
  ('regression: unequal ceilings',
   ([90, 40], [2.0, 1.5], [120, 60], 0.05, 5),
   [[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]])],
 [('regression: meadow source woodland sink',
   ([100, 20], [1.5, 0.7], [200, 200], 0.2, 5),
   [[122.8, 41.2], [153.128, 59.912], [168.3877, 73.5507], [170.2971, 81.1884], [171.3664, 85.4655]]),
  ('regression: ceiling binding in source',
   ([180, 10], [1.4, 0.8], [200, 50], 0.1, 4),
   [[180.8, 27.2], [182.176, 39.584], [183.1667, 48.5005], [183.88, 54.9203]]),
  ('control: no dispersal',
   ([50, 50], [1.2, 0.9], [100, 100], 0.0, 3),
   [[60.0, 45.0], [72.0, 40.5], [86.4, 36.45]]),
  ('control: full exchange',
   ([60, 0], [1.1, 0.5], [100, 100], 1.0, 3),
   [[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]]),
  ('control: both sinks',
   ([100, 100], [0.8, 0.6], [150, 150], 0.3, 4),
   [[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]]),
  ('regression: sink ceiling binding',
   ([10, 120], [1.3, 1.2], [300, 100], 0.25, 4),
   [[34.75, 78.25], [57.3563, 81.7188], [80.438, 92.1877], [103.427, 101.1423]]),
  ('regression: unequal ceilings',
   ([90, 40], [2.0, 1.5], [120, 60], 0.05, 5),
   [[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]])],
 [('regression: meadow source woodland sink',
   ([100, 20], [1.5, 0.7], [200, 200], 0.2, 5),
   [[122.8, 41.2], [153.128, 59.912], [168.3877, 73.5507], [170.2971, 81.1884], [171.3664, 85.4655]]),
  ('regression: ceiling binding in source',
   ([180, 10], [1.4, 0.8], [200, 50], 0.1, 4),
   [[180.8, 27.2], [182.176, 39.584], [183.1667, 48.5005], [183.88, 54.9203]]),
  ('control: no dispersal',
   ([50, 50], [1.2, 0.9], [100, 100], 0.0, 3),
   [[60.0, 45.0], [72.0, 40.5], [86.4, 36.45]]),
  ('control: full exchange',
   ([60, 0], [1.1, 0.5], [100, 100], 1.0, 3),
   [[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]]),
  ('control: both sinks',
   ([100, 100], [0.8, 0.6], [150, 150], 0.3, 4),
   [[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]]),
  ('regression: sink ceiling binding',
   ([10, 120], [1.3, 1.2], [300, 100], 0.25, 4),
   [[34.75, 78.25], [57.3563, 81.7188], [80.438, 92.1877], [103.427, 101.1423]]),
  ('regression: unequal ceilings',
   ([90, 40], [2.0, 1.5], [120, 60], 0.05, 5),
   [[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]])],
 [('regression: meadow source woodland sink',
   ([100, 20], [1.5, 0.7], [200, 200], 0.2, 5),
   [[122.8, 41.2], [153.128, 59.912], [168.3877, 73.5507], [170.2971, 81.1884], [171.3664, 85.4655]]),
  ('regression: ceiling binding in source',
   ([180, 10], [1.4, 0.8], [200, 50], 0.1, 4),
   [[180.8, 27.2], [182.176, 39.584], [183.1667, 48.5005], [183.88, 54.9203]]),
  ('control: no dispersal',
   ([50, 50], [1.2, 0.9], [100, 100], 0.0, 3),
   [[60.0, 45.0], [72.0, 40.5], [86.4, 36.45]]),
  ('control: full exchange',
   ([60, 0], [1.1, 0.5], [100, 100], 1.0, 3),
   [[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]]),
  ('control: both sinks',
   ([100, 100], [0.8, 0.6], [150, 150], 0.3, 4),
   [[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]]),
  ('regression: sink ceiling binding',
   ([10, 120], [1.3, 1.2], [300, 100], 0.25, 4),
   [[34.75, 78.25], [57.3563, 81.7188], [80.438, 92.1877], [103.427, 101.1423]]),
  ('regression: unequal ceilings',
   ([90, 40], [2.0, 1.5], [120, 60], 0.05, 5),
   [[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]])],
 [('regression: meadow source woodland sink',
   ([100, 20], [1.5, 0.7], [200, 200], 0.2, 5),
   [[122.8, 41.2], [153.128, 59.912], [168.3877, 73.5507], [170.2971, 81.1884], [171.3664, 85.4655]]),
  ('regression: ceiling binding in source',
   ([180, 10], [1.4, 0.8], [200, 50], 0.1, 4),
   [[180.8, 27.2], [182.176, 39.584], [183.1667, 48.5005], [183.88, 54.9203]]),
  ('control: no dispersal',
   ([50, 50], [1.2, 0.9], [100, 100], 0.0, 3),
   [[60.0, 45.0], [72.0, 40.5], [86.4, 36.45]]),
  ('control: full exchange',
   ([60, 0], [1.1, 0.5], [100, 100], 1.0, 3),
   [[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]]),
  ('control: both sinks',
   ([100, 100], [0.8, 0.6], [150, 150], 0.3, 4),
   [[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]]),
  ('regression: sink ceiling binding',
   ([10, 120], [1.3, 1.2], [300, 100], 0.25, 4),
   [[34.75, 78.25], [57.3563, 81.7188], [80.438, 92.1877], [103.427, 101.1423]]),
  ('regression: unequal ceilings',
   ([90, 40], [2.0, 1.5], [120, 60], 0.05, 5),
   [[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]])]]
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: meadow source woodland sink[[122.8, 41.2], [153.128, 59.912], [168.3877, 73.5507], [170.2971, 81.1884], [171.3664, 85.4655]][[122.8, 41.2], [153.128, 59.912], [168.3877, 73.5507], [170.2971, 81.1884], [171.3664, 85.4655]]Passed
regression: ceiling binding in source[[180.8, 27.2], [182.176, 39.584], [183.1667, 48.5005], [183.88, 54.9203]][[180.8, 27.2], [182.176, 39.584], [183.1667, 48.5005], [183.88, 54.9203]]Passed
control: no dispersal[[60.0, 45.0], [72.0, 40.5], [86.4, 36.45]][[60.0, 45.0], [72.0, 40.5], [86.4, 36.45]]Passed
control: full exchange[[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]][[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]]Passed
control: both sinks[[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]][[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]]Passed
regression: sink ceiling binding[[34.75, 78.25], [57.3563, 81.7188], [80.438, 92.1877], [103.427, 101.1423]][[34.75, 78.25], [57.3563, 81.7188], [80.438, 92.1877], [103.427, 101.1423]]Passed
regression: unequal ceilings[[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]][[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]]Passed

SHA-256 / 4163838221b080713a4d61cd6e0290b37763a26b8d93731342954e2552564adc

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:36.579881+00:00.

Case digest / e24d2eb54e3a016debd606aa0db32d9d58e84d0e7c00adbe9dc694cf1afd1377