FAILURE MAP
← Case archive

FA-65711 / Ecological population dynamics / Open access

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

Dispersal numbers ignore this year's reproduction.

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

ROOT CAUSE

Emigration is computed from the pre-growth population.

VERIFIED REPAIR

Restore the dispersal base rule: `out = [grown[j] * disperse`.

Unsuccessful approach: Emigration proportional to the ceiling ignores actual abundance.

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[j]) for j in range(2)]
        out = [n[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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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[[134.0, 30.0], [179.2, 41.8], [172.52, 56.74], [176.844, 62.874], [177.206, 66.8058]][[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[[183.0, 25.0], [184.2, 35.8], [185.16, 43.48], [185.832, 48.952]][[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
regression: full exchange[[6.0, 60.0], [60.6, -24.0], [-17.94, 72.6]][[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]]Failed
regression: both sinks[[80.0, 60.0], [58.0, 42.0], [41.6, 30.0], [29.8, 21.48]][[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]]Failed
regression: sink ceiling binding[[40.5, 72.5], [60.65, 79.0], [83.4325, 90.2125], [110.1573, 98.305]][[34.75, 78.25], [57.3563, 81.7188], [80.438, 92.1877], [103.427, 101.1423]]Failed
regression: unequal ceilings[[117.5, 62.5], [117.25, 62.75], [117.275, 62.725], [117.2725, 62.7275], [117.2728, 62.7272]][[117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0], [117.0, 63.0]]Failed

SHA-256 / e11d1dfa743e53cf6ca9de9abf7b91711ac7a44172849c63b5a2c1af1e366fb5

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], caps[j]) for j in range(2)]
        out = [caps[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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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[[150.0, 14.0], [200.0, 9.8], [200.0, 6.86], [200.0, 4.802], [200.0, 3.3614]][[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[[185.0, 23.0], [185.0, 33.4], [185.0, 41.72], [185.0, 48.376]][[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
regression: full exchange[[66.0, 0.0], [72.6, 0.0], [79.86, 0.0]][[0.0, 66.0], [33.0, 0.0], [0.0, 36.3]]Failed
regression: both sinks[[80.0, 60.0], [64.0, 36.0], [51.2, 21.6], [40.96, 12.96]][[74.0, 66.0], [53.32, 45.48], [38.0456, 31.8984], [27.0472, 22.5283]]Failed
regression: sink ceiling binding[[-37.0, 150.0], [-98.1, 150.0], [-177.53, 150.0], [-280.789, 150.0]][[34.75, 78.25], [57.3563, 81.7188], [80.438, 92.1877], [103.427, 101.1423]]Failed
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 / dafa552bc5937b2062f5c75e25138a252d2ebb8c3676029e2555541eb6b07cc9

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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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]]),
  ('regression: 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
regression: 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
regression: 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 / 20af016fbef8f8e5bddedad7ba05623f3842a2b921716977f7f68d125d613c3b

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

Case digest / 7c1f9dab41a4c8aaa4470f28a7b866fdda43fbb913342efb5210351d7bccfe67