FAILURE MAP
← Case archive

FA-65401 / Ecological population dynamics / Open access

Beverton-Holt recruitment convergence: initial state check · case 01

A stock that starts at equilibrium is reported as converging in year 1.

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

ROOT CAUSE

Year 0 is never tested against the band.

VERIFIED REPAIR

Restore the initial state check rule: `hit = 0 if abs(n - eq) <= band else None`.

Unsuccessful approach: Labelling an initially converged stock as year 1 shifts the answer.

Case contract

N[t+1] = r0*N/(1+(r0-1)*N/K); equilibrium K if r0>1 else 0; band = 0.01*K; hit = first year (0 = start) with |N-eq|<=band, else None; return [trajectory rounded 4, equilibrium, hit]; None for invalid inputs.

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(n0, r0, k, years):
    if k <= 0 or r0 <= 0 or n0 < 0:
        return None
    eq = float(k) if r0 > 1 else 0.0
    band = 0.01 * k
    n = float(n0)
    traj = []
    hit = None
    for year in range(1, years + 1):
        n = r0 * n / (1 + (r0 - 1) * n / k)
        traj.append(round(n, 4))
        if hit is None and abs(n - eq) <= band:
            hit = year
    return [traj, eq, hit]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('control: herring recruitment',
   (50, 3.0, 1000, 10),
   [[136.3636, 321.4286, 586.9565, 810.0, 927.4809, 974.5989, 991.3871, 997.1125, 999.0356, 999.6783],
    1000.0,
    7]),
  ('control: slow approach',
   (10, 1.5, 500, 12),
   [[14.8515,
     21.9512,
     32.2196,
     46.8208,
     67.09,
     94.3079,
     129.2706,
     171.709,
     219.8186,
     270.309,
     319.1849,
     362.9343],
    500.0,
    None]),
  ('regression: start at capacity', (1000, 2.0, 1000, 4), [[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 0]),
  ('regression: start within band', (995, 2.0, 1000, 3), [[997.4937, 998.7453, 999.3723], 1000.0, 0]),
  ('control: replacement r0 one', (200, 1.0, 1000, 4), [[200.0, 200.0, 200.0, 200.0], 0.0, None]),
  ('control: declining r0 half',
   (400, 0.5, 1000, 8),
   [[250.0, 142.8571, 76.9231, 40.0, 20.4082, 10.3093, 5.1813, 2.5974], 0.0, 7]),
  ('control: above capacity',
   (3000, 2.5, 1000, 6),
   [[1363.6364, 1119.403, 1044.5682, 1017.363, 1006.8736, 1002.7381], 1000.0, 5])],
 [('regression: start at capacity', (1000, 2.0, 1000, 4), [[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 0]),
  ('regression: start within band', (995, 2.0, 1000, 3), [[997.4937, 998.7453, 999.3723], 1000.0, 0]),
  ('control: replacement r0 one', (200, 1.0, 1000, 4), [[200.0, 200.0, 200.0, 200.0], 0.0, None]),
  ('control: declining r0 half',
   (400, 0.5, 1000, 8),
   [[250.0, 142.8571, 76.9231, 40.0, 20.4082, 10.3093, 5.1813, 2.5974], 0.0, 7]),
  ('control: above capacity',
   (3000, 2.5, 1000, 6),
   [[1363.6364, 1119.403, 1044.5682, 1017.363, 1006.8736, 1002.7381], 1000.0, 5]),
  ('control: invalid r0', (100, 0.0, 1000, 5), None),
  ('control: never reaches band',
   (1, 1.2, 10000, 5),
   [[1.2, 1.4399, 1.7279, 2.0734, 2.4879], 10000.0, None])],
 [('regression: start at capacity', (1000, 2.0, 1000, 4), [[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 0]),
  ('regression: start within band', (995, 2.0, 1000, 3), [[997.4937, 998.7453, 999.3723], 1000.0, 0]),
  ('control: above capacity',
   (3000, 2.5, 1000, 6),
   [[1363.6364, 1119.403, 1044.5682, 1017.363, 1006.8736, 1002.7381], 1000.0, 5]),
  ('control: invalid r0', (100, 0.0, 1000, 5), None),
  ('control: never reaches band', (1, 1.2, 10000, 5), [[1.2, 1.4399, 1.7279, 2.0734, 2.4879], 10000.0, None]),
  ('control: one year from band', (985, 2.0, 1000, 4), [[992.4433, 996.2073, 998.1001, 999.0491], 1000.0, 1]),
  ('control: small capacity',
   (2, 4.0, 20, 6),
   [[6.1538, 12.8, 17.5342, 19.3208, 19.8258, 19.9562], 20.0, 5])],
 [('control: herring recruitment',
   (50, 3.0, 1000, 10),
   [[136.3636, 321.4286, 586.9565, 810.0, 927.4809, 974.5989, 991.3871, 997.1125, 999.0356, 999.6783],
    1000.0,
    7]),
  ('control: slow approach',
   (10, 1.5, 500, 12),
   [[14.8515,
     21.9512,
     32.2196,
     46.8208,
     67.09,
     94.3079,
     129.2706,
     171.709,
     219.8186,
     270.309,
     319.1849,
     362.9343],
    500.0,
    None]),
  ('regression: start at capacity', (1000, 2.0, 1000, 4), [[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 0]),
  ('regression: start within band', (995, 2.0, 1000, 3), [[997.4937, 998.7453, 999.3723], 1000.0, 0]),
  ('control: replacement r0 one', (200, 1.0, 1000, 4), [[200.0, 200.0, 200.0, 200.0], 0.0, None]),
  ('control: one year from band', (985, 2.0, 1000, 4), [[992.4433, 996.2073, 998.1001, 999.0491], 1000.0, 1]),
  ('control: small capacity',
   (2, 4.0, 20, 6),
   [[6.1538, 12.8, 17.5342, 19.3208, 19.8258, 19.9562], 20.0, 5])],
 [('control: slow approach',
   (10, 1.5, 500, 12),
   [[14.8515,
     21.9512,
     32.2196,
     46.8208,
     67.09,
     94.3079,
     129.2706,
     171.709,
     219.8186,
     270.309,
     319.1849,
     362.9343],
    500.0,
    None]),
  ('regression: start at capacity', (1000, 2.0, 1000, 4), [[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 0]),
  ('regression: start within band', (995, 2.0, 1000, 3), [[997.4937, 998.7453, 999.3723], 1000.0, 0]),
  ('control: replacement r0 one', (200, 1.0, 1000, 4), [[200.0, 200.0, 200.0, 200.0], 0.0, None]),
  ('control: declining r0 half',
   (400, 0.5, 1000, 8),
   [[250.0, 142.8571, 76.9231, 40.0, 20.4082, 10.3093, 5.1813, 2.5974], 0.0, 7]),
  ('control: above capacity',
   (3000, 2.5, 1000, 6),
   [[1363.6364, 1119.403, 1044.5682, 1017.363, 1006.8736, 1002.7381], 1000.0, 5]),
  ('control: invalid r0', (100, 0.0, 1000, 5), None)]]
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
control: herring recruitment[[136.3636, 321.4286, 586.9565, 810.0, 927.4809, 974.5989, 991.3871, 997.1125, 999.0356, 999.6783], 1000.0, 7][[136.3636, 321.4286, 586.9565, 810.0, 927.4809, 974.5989, 991.3871, 997.1125, 999.0356, 999.6783], 1000.0, 7]Passed
control: slow approach[[14.8515, 21.9512, 32.2196, 46.8208, 67.09, 94.3079, 129.2706, 171.709, 219.8186, 270.309, 319.1849, 362.9343], 500.0, None][[14.8515, 21.9512, 32.2196, 46.8208, 67.09, 94.3079, 129.2706, 171.709, 219.8186, 270.309, 319.1849, 362.9343], 500.0, None]Passed
regression: start at capacity[[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 1][[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 0]Failed
regression: start within band[[997.4937, 998.7453, 999.3723], 1000.0, 1][[997.4937, 998.7453, 999.3723], 1000.0, 0]Failed
control: replacement r0 one[[200.0, 200.0, 200.0, 200.0], 0.0, None][[200.0, 200.0, 200.0, 200.0], 0.0, None]Passed
control: declining r0 half[[250.0, 142.8571, 76.9231, 40.0, 20.4082, 10.3093, 5.1813, 2.5974], 0.0, 7][[250.0, 142.8571, 76.9231, 40.0, 20.4082, 10.3093, 5.1813, 2.5974], 0.0, 7]Passed
control: above capacity[[1363.6364, 1119.403, 1044.5682, 1017.363, 1006.8736, 1002.7381], 1000.0, 5][[1363.6364, 1119.403, 1044.5682, 1017.363, 1006.8736, 1002.7381], 1000.0, 5]Passed

SHA-256 / c6cc26fa8170ccaeb54e5618a02b6ad29eabe808851448033de672814f0ea4c1

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(n0, r0, k, years):
    if k <= 0 or r0 <= 0 or n0 < 0:
        return None
    eq = float(k) if r0 > 1 else 0.0
    band = 0.01 * k
    n = float(n0)
    traj = []
    hit = 1 if abs(n - eq) <= band else None
    for year in range(1, years + 1):
        n = r0 * n / (1 + (r0 - 1) * n / k)
        traj.append(round(n, 4))
        if hit is None and abs(n - eq) <= band:
            hit = year
    return [traj, eq, hit]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('control: herring recruitment',
   (50, 3.0, 1000, 10),
   [[136.3636, 321.4286, 586.9565, 810.0, 927.4809, 974.5989, 991.3871, 997.1125, 999.0356, 999.6783],
    1000.0,
    7]),
  ('control: slow approach',
   (10, 1.5, 500, 12),
   [[14.8515,
     21.9512,
     32.2196,
     46.8208,
     67.09,
     94.3079,
     129.2706,
     171.709,
     219.8186,
     270.309,
     319.1849,
     362.9343],
    500.0,
    None]),
  ('regression: start at capacity', (1000, 2.0, 1000, 4), [[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 0]),
  ('regression: start within band', (995, 2.0, 1000, 3), [[997.4937, 998.7453, 999.3723], 1000.0, 0]),
  ('control: replacement r0 one', (200, 1.0, 1000, 4), [[200.0, 200.0, 200.0, 200.0], 0.0, None]),
  ('control: declining r0 half',
   (400, 0.5, 1000, 8),
   [[250.0, 142.8571, 76.9231, 40.0, 20.4082, 10.3093, 5.1813, 2.5974], 0.0, 7]),
  ('control: above capacity',
   (3000, 2.5, 1000, 6),
   [[1363.6364, 1119.403, 1044.5682, 1017.363, 1006.8736, 1002.7381], 1000.0, 5])],
 [('regression: start at capacity', (1000, 2.0, 1000, 4), [[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 0]),
  ('regression: start within band', (995, 2.0, 1000, 3), [[997.4937, 998.7453, 999.3723], 1000.0, 0]),
  ('control: replacement r0 one', (200, 1.0, 1000, 4), [[200.0, 200.0, 200.0, 200.0], 0.0, None]),
  ('control: declining r0 half',
   (400, 0.5, 1000, 8),
   [[250.0, 142.8571, 76.9231, 40.0, 20.4082, 10.3093, 5.1813, 2.5974], 0.0, 7]),
  ('control: above capacity',
   (3000, 2.5, 1000, 6),
   [[1363.6364, 1119.403, 1044.5682, 1017.363, 1006.8736, 1002.7381], 1000.0, 5]),
  ('control: invalid r0', (100, 0.0, 1000, 5), None),
  ('control: never reaches band',
   (1, 1.2, 10000, 5),
   [[1.2, 1.4399, 1.7279, 2.0734, 2.4879], 10000.0, None])],
 [('regression: start at capacity', (1000, 2.0, 1000, 4), [[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 0]),
  ('regression: start within band', (995, 2.0, 1000, 3), [[997.4937, 998.7453, 999.3723], 1000.0, 0]),
  ('control: above capacity',
   (3000, 2.5, 1000, 6),
   [[1363.6364, 1119.403, 1044.5682, 1017.363, 1006.8736, 1002.7381], 1000.0, 5]),
  ('control: invalid r0', (100, 0.0, 1000, 5), None),
  ('control: never reaches band', (1, 1.2, 10000, 5), [[1.2, 1.4399, 1.7279, 2.0734, 2.4879], 10000.0, None]),
  ('control: one year from band', (985, 2.0, 1000, 4), [[992.4433, 996.2073, 998.1001, 999.0491], 1000.0, 1]),
  ('control: small capacity',
   (2, 4.0, 20, 6),
   [[6.1538, 12.8, 17.5342, 19.3208, 19.8258, 19.9562], 20.0, 5])],
 [('control: herring recruitment',
   (50, 3.0, 1000, 10),
   [[136.3636, 321.4286, 586.9565, 810.0, 927.4809, 974.5989, 991.3871, 997.1125, 999.0356, 999.6783],
    1000.0,
    7]),
  ('control: slow approach',
   (10, 1.5, 500, 12),
   [[14.8515,
     21.9512,
     32.2196,
     46.8208,
     67.09,
     94.3079,
     129.2706,
     171.709,
     219.8186,
     270.309,
     319.1849,
     362.9343],
    500.0,
    None]),
  ('regression: start at capacity', (1000, 2.0, 1000, 4), [[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 0]),
  ('regression: start within band', (995, 2.0, 1000, 3), [[997.4937, 998.7453, 999.3723], 1000.0, 0]),
  ('control: replacement r0 one', (200, 1.0, 1000, 4), [[200.0, 200.0, 200.0, 200.0], 0.0, None]),
  ('control: one year from band', (985, 2.0, 1000, 4), [[992.4433, 996.2073, 998.1001, 999.0491], 1000.0, 1]),
  ('control: small capacity',
   (2, 4.0, 20, 6),
   [[6.1538, 12.8, 17.5342, 19.3208, 19.8258, 19.9562], 20.0, 5])],
 [('control: slow approach',
   (10, 1.5, 500, 12),
   [[14.8515,
     21.9512,
     32.2196,
     46.8208,
     67.09,
     94.3079,
     129.2706,
     171.709,
     219.8186,
     270.309,
     319.1849,
     362.9343],
    500.0,
    None]),
  ('regression: start at capacity', (1000, 2.0, 1000, 4), [[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 0]),
  ('regression: start within band', (995, 2.0, 1000, 3), [[997.4937, 998.7453, 999.3723], 1000.0, 0]),
  ('control: replacement r0 one', (200, 1.0, 1000, 4), [[200.0, 200.0, 200.0, 200.0], 0.0, None]),
  ('control: declining r0 half',
   (400, 0.5, 1000, 8),
   [[250.0, 142.8571, 76.9231, 40.0, 20.4082, 10.3093, 5.1813, 2.5974], 0.0, 7]),
  ('control: above capacity',
   (3000, 2.5, 1000, 6),
   [[1363.6364, 1119.403, 1044.5682, 1017.363, 1006.8736, 1002.7381], 1000.0, 5]),
  ('control: invalid r0', (100, 0.0, 1000, 5), None)]]
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
control: herring recruitment[[136.3636, 321.4286, 586.9565, 810.0, 927.4809, 974.5989, 991.3871, 997.1125, 999.0356, 999.6783], 1000.0, 7][[136.3636, 321.4286, 586.9565, 810.0, 927.4809, 974.5989, 991.3871, 997.1125, 999.0356, 999.6783], 1000.0, 7]Passed
control: slow approach[[14.8515, 21.9512, 32.2196, 46.8208, 67.09, 94.3079, 129.2706, 171.709, 219.8186, 270.309, 319.1849, 362.9343], 500.0, None][[14.8515, 21.9512, 32.2196, 46.8208, 67.09, 94.3079, 129.2706, 171.709, 219.8186, 270.309, 319.1849, 362.9343], 500.0, None]Passed
regression: start at capacity[[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 1][[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 0]Failed
regression: start within band[[997.4937, 998.7453, 999.3723], 1000.0, 1][[997.4937, 998.7453, 999.3723], 1000.0, 0]Failed
control: replacement r0 one[[200.0, 200.0, 200.0, 200.0], 0.0, None][[200.0, 200.0, 200.0, 200.0], 0.0, None]Passed
control: declining r0 half[[250.0, 142.8571, 76.9231, 40.0, 20.4082, 10.3093, 5.1813, 2.5974], 0.0, 7][[250.0, 142.8571, 76.9231, 40.0, 20.4082, 10.3093, 5.1813, 2.5974], 0.0, 7]Passed
control: above capacity[[1363.6364, 1119.403, 1044.5682, 1017.363, 1006.8736, 1002.7381], 1000.0, 5][[1363.6364, 1119.403, 1044.5682, 1017.363, 1006.8736, 1002.7381], 1000.0, 5]Passed

SHA-256 / cc08bd8f014a5e5999a19b442ae89ef1122653c30d438ec0d68d0eb43cbd5f87

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(n0, r0, k, years):
    if k <= 0 or r0 <= 0 or n0 < 0:
        return None
    eq = float(k) if r0 > 1 else 0.0
    band = 0.01 * k
    n = float(n0)
    traj = []
    hit = 0 if abs(n - eq) <= band else None
    for year in range(1, years + 1):
        n = r0 * n / (1 + (r0 - 1) * n / k)
        traj.append(round(n, 4))
        if hit is None and abs(n - eq) <= band:
            hit = year
    return [traj, eq, hit]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('control: herring recruitment',
   (50, 3.0, 1000, 10),
   [[136.3636, 321.4286, 586.9565, 810.0, 927.4809, 974.5989, 991.3871, 997.1125, 999.0356, 999.6783],
    1000.0,
    7]),
  ('control: slow approach',
   (10, 1.5, 500, 12),
   [[14.8515,
     21.9512,
     32.2196,
     46.8208,
     67.09,
     94.3079,
     129.2706,
     171.709,
     219.8186,
     270.309,
     319.1849,
     362.9343],
    500.0,
    None]),
  ('regression: start at capacity', (1000, 2.0, 1000, 4), [[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 0]),
  ('regression: start within band', (995, 2.0, 1000, 3), [[997.4937, 998.7453, 999.3723], 1000.0, 0]),
  ('control: replacement r0 one', (200, 1.0, 1000, 4), [[200.0, 200.0, 200.0, 200.0], 0.0, None]),
  ('control: declining r0 half',
   (400, 0.5, 1000, 8),
   [[250.0, 142.8571, 76.9231, 40.0, 20.4082, 10.3093, 5.1813, 2.5974], 0.0, 7]),
  ('control: above capacity',
   (3000, 2.5, 1000, 6),
   [[1363.6364, 1119.403, 1044.5682, 1017.363, 1006.8736, 1002.7381], 1000.0, 5])],
 [('regression: start at capacity', (1000, 2.0, 1000, 4), [[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 0]),
  ('regression: start within band', (995, 2.0, 1000, 3), [[997.4937, 998.7453, 999.3723], 1000.0, 0]),
  ('control: replacement r0 one', (200, 1.0, 1000, 4), [[200.0, 200.0, 200.0, 200.0], 0.0, None]),
  ('control: declining r0 half',
   (400, 0.5, 1000, 8),
   [[250.0, 142.8571, 76.9231, 40.0, 20.4082, 10.3093, 5.1813, 2.5974], 0.0, 7]),
  ('control: above capacity',
   (3000, 2.5, 1000, 6),
   [[1363.6364, 1119.403, 1044.5682, 1017.363, 1006.8736, 1002.7381], 1000.0, 5]),
  ('control: invalid r0', (100, 0.0, 1000, 5), None),
  ('control: never reaches band',
   (1, 1.2, 10000, 5),
   [[1.2, 1.4399, 1.7279, 2.0734, 2.4879], 10000.0, None])],
 [('regression: start at capacity', (1000, 2.0, 1000, 4), [[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 0]),
  ('regression: start within band', (995, 2.0, 1000, 3), [[997.4937, 998.7453, 999.3723], 1000.0, 0]),
  ('control: above capacity',
   (3000, 2.5, 1000, 6),
   [[1363.6364, 1119.403, 1044.5682, 1017.363, 1006.8736, 1002.7381], 1000.0, 5]),
  ('control: invalid r0', (100, 0.0, 1000, 5), None),
  ('control: never reaches band', (1, 1.2, 10000, 5), [[1.2, 1.4399, 1.7279, 2.0734, 2.4879], 10000.0, None]),
  ('control: one year from band', (985, 2.0, 1000, 4), [[992.4433, 996.2073, 998.1001, 999.0491], 1000.0, 1]),
  ('control: small capacity',
   (2, 4.0, 20, 6),
   [[6.1538, 12.8, 17.5342, 19.3208, 19.8258, 19.9562], 20.0, 5])],
 [('control: herring recruitment',
   (50, 3.0, 1000, 10),
   [[136.3636, 321.4286, 586.9565, 810.0, 927.4809, 974.5989, 991.3871, 997.1125, 999.0356, 999.6783],
    1000.0,
    7]),
  ('control: slow approach',
   (10, 1.5, 500, 12),
   [[14.8515,
     21.9512,
     32.2196,
     46.8208,
     67.09,
     94.3079,
     129.2706,
     171.709,
     219.8186,
     270.309,
     319.1849,
     362.9343],
    500.0,
    None]),
  ('regression: start at capacity', (1000, 2.0, 1000, 4), [[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 0]),
  ('regression: start within band', (995, 2.0, 1000, 3), [[997.4937, 998.7453, 999.3723], 1000.0, 0]),
  ('control: replacement r0 one', (200, 1.0, 1000, 4), [[200.0, 200.0, 200.0, 200.0], 0.0, None]),
  ('control: one year from band', (985, 2.0, 1000, 4), [[992.4433, 996.2073, 998.1001, 999.0491], 1000.0, 1]),
  ('control: small capacity',
   (2, 4.0, 20, 6),
   [[6.1538, 12.8, 17.5342, 19.3208, 19.8258, 19.9562], 20.0, 5])],
 [('control: slow approach',
   (10, 1.5, 500, 12),
   [[14.8515,
     21.9512,
     32.2196,
     46.8208,
     67.09,
     94.3079,
     129.2706,
     171.709,
     219.8186,
     270.309,
     319.1849,
     362.9343],
    500.0,
    None]),
  ('regression: start at capacity', (1000, 2.0, 1000, 4), [[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 0]),
  ('regression: start within band', (995, 2.0, 1000, 3), [[997.4937, 998.7453, 999.3723], 1000.0, 0]),
  ('control: replacement r0 one', (200, 1.0, 1000, 4), [[200.0, 200.0, 200.0, 200.0], 0.0, None]),
  ('control: declining r0 half',
   (400, 0.5, 1000, 8),
   [[250.0, 142.8571, 76.9231, 40.0, 20.4082, 10.3093, 5.1813, 2.5974], 0.0, 7]),
  ('control: above capacity',
   (3000, 2.5, 1000, 6),
   [[1363.6364, 1119.403, 1044.5682, 1017.363, 1006.8736, 1002.7381], 1000.0, 5]),
  ('control: invalid r0', (100, 0.0, 1000, 5), None)]]
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
control: herring recruitment[[136.3636, 321.4286, 586.9565, 810.0, 927.4809, 974.5989, 991.3871, 997.1125, 999.0356, 999.6783], 1000.0, 7][[136.3636, 321.4286, 586.9565, 810.0, 927.4809, 974.5989, 991.3871, 997.1125, 999.0356, 999.6783], 1000.0, 7]Passed
control: slow approach[[14.8515, 21.9512, 32.2196, 46.8208, 67.09, 94.3079, 129.2706, 171.709, 219.8186, 270.309, 319.1849, 362.9343], 500.0, None][[14.8515, 21.9512, 32.2196, 46.8208, 67.09, 94.3079, 129.2706, 171.709, 219.8186, 270.309, 319.1849, 362.9343], 500.0, None]Passed
regression: start at capacity[[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 0][[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 0]Passed
regression: start within band[[997.4937, 998.7453, 999.3723], 1000.0, 0][[997.4937, 998.7453, 999.3723], 1000.0, 0]Passed
control: replacement r0 one[[200.0, 200.0, 200.0, 200.0], 0.0, None][[200.0, 200.0, 200.0, 200.0], 0.0, None]Passed
control: declining r0 half[[250.0, 142.8571, 76.9231, 40.0, 20.4082, 10.3093, 5.1813, 2.5974], 0.0, 7][[250.0, 142.8571, 76.9231, 40.0, 20.4082, 10.3093, 5.1813, 2.5974], 0.0, 7]Passed
control: above capacity[[1363.6364, 1119.403, 1044.5682, 1017.363, 1006.8736, 1002.7381], 1000.0, 5][[1363.6364, 1119.403, 1044.5682, 1017.363, 1006.8736, 1002.7381], 1000.0, 5]Passed

SHA-256 / 16503051cfebdbaeefdf5711ebac9cbb0e30f92e50eaa0c35208a0deac3fda08

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

Case digest / 7a6040899f36b3d8ff5690a0e49715d31553c3b153a8cf2a64297960d3415d37