FAILURE MAP
← Case archive

FA-65696 / Ecological population dynamics / Open access

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

The sink patch is allowed to fill to the source ceiling.

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

ROOT CAUSE

Every patch uses the first patch's ceiling.

VERIFIED REPAIR

Restore the patch-specific ceiling rule: `min(n[j] * lambdas[j], caps[j])`.

Unsuccessful approach: Capping at the combined ceiling never binds a single patch.

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 = [min(n[j] * lambdas[j], caps[0]) 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[[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[[117.0, 63.0], [118.725, 95.775], [120.0, 120.0], [120.0, 120.0], [120.0, 120.0]][[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]]Failed

SHA-256 / 5f0ab2dde2e8132d424af39e229b8c4b6eadad640f4e14da428d2740a63d12c1

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 = [min(n[j] * lambdas[j], sum(caps)) 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[[225.8, 32.2], [227.576, 48.184], [228.8547, 59.6925], [229.7754, 67.9786]][[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], [175.95, 103.05], [178.7287, 155.8462], [180.0, 180.0], [180.0, 180.0]][[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]]Failed

SHA-256 / a53ccf4b16778275117fde2873a7ee8ea8d43e01e5d8d58839f6ce3c0d5e174c

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

Case digest / af178c0f78d503b47dd1dbe0d879d793c12dd2c2c7eee9e0218040652bb794ff