FAILURE MAP
← Case archive

FA-65381 / Ecological population dynamics / Open access

Beverton-Holt recruitment convergence: density denominator · case 01

The stock settles well below the stated carrying capacity.

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

ROOT CAUSE

The half-saturation constant is taken as K instead of K/(r0-1).

VERIFIED REPAIR

Restore the density denominator rule: `(1 + (r0 - 1) * n / k)`.

Unsuccessful approach: Using r0*N/K moves the equilibrium to K*(r0-1)/r0.

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 = 0 if abs(n - eq) <= band else None
    for year in range(1, years + 1):
        n = r0 * n / (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 = [[('regression: 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]),
  ('regression: 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]),
  ('regression: replacement r0 one', (200, 1.0, 1000, 4), [[200.0, 200.0, 200.0, 200.0], 0.0, None]),
  ('regression: 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: invalid r0', (100, 0.0, 1000, 5), None)],
 [('regression: start within band', (995, 2.0, 1000, 3), [[997.4937, 998.7453, 999.3723], 1000.0, 0]),
  ('regression: replacement r0 one', (200, 1.0, 1000, 4), [[200.0, 200.0, 200.0, 200.0], 0.0, None]),
  ('regression: 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]),
  ('regression: 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),
  ('regression: never reaches band',
   (1, 1.2, 10000, 5),
   [[1.2, 1.4399, 1.7279, 2.0734, 2.4879], 10000.0, None]),
  ('regression: one year from band',
   (985, 2.0, 1000, 4),
   [[992.4433, 996.2073, 998.1001, 999.0491], 1000.0, 1])],
 [('regression: 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]),
  ('regression: 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: 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),
  ('regression: never reaches band',
   (1, 1.2, 10000, 5),
   [[1.2, 1.4399, 1.7279, 2.0734, 2.4879], 10000.0, None]),
  ('regression: one year from band',
   (985, 2.0, 1000, 4),
   [[992.4433, 996.2073, 998.1001, 999.0491], 1000.0, 1]),
  ('regression: small capacity',
   (2, 4.0, 20, 6),
   [[6.1538, 12.8, 17.5342, 19.3208, 19.8258, 19.9562], 20.0, 5])],
 [('regression: 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]),
  ('regression: 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: invalid r0', (100, 0.0, 1000, 5), None),
  ('regression: one year from band',
   (985, 2.0, 1000, 4),
   [[992.4433, 996.2073, 998.1001, 999.0491], 1000.0, 1]),
  ('regression: small capacity',
   (2, 4.0, 20, 6),
   [[6.1538, 12.8, 17.5342, 19.3208, 19.8258, 19.9562], 20.0, 5])],
 [('regression: 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]),
  ('regression: replacement r0 one', (200, 1.0, 1000, 4), [[200.0, 200.0, 200.0, 200.0], 0.0, None]),
  ('regression: 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]),
  ('regression: 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
regression: herring recruitment[[142.8571, 375.0, 818.1818, 1350.0, 1723.4043, 1898.4375, 1964.9596, 1988.1818, 1996.045, 1998.6799], 1000.0, None][[136.3636, 321.4286, 586.9565, 810.0, 927.4809, 974.5989, 991.3871, 997.1125, 999.0356, 999.6783], 1000.0, 7]Failed
regression: slow approach[[14.7059, 21.4286, 30.8219, 43.5484, 60.089, 80.4636, 103.9646, 129.1027, 153.9129, 176.5291, 195.7002, 210.9747], 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]Failed
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
regression: replacement r0 one[[166.6667, 142.8571, 125.0, 111.1111], 0.0, None][[200.0, 200.0, 200.0, 200.0], 0.0, None]Failed
regression: declining r0 half[[142.8571, 62.5, 29.4118, 14.2857, 7.0423, 3.4965, 1.7422, 0.8696], 0.0, 5][[250.0, 142.8571, 76.9231, 40.0, 20.4082, 10.3093, 5.1813, 2.5974], 0.0, 7]Failed
control: invalid r0NoneNonePassed

SHA-256 / f6d3307b9fa3c2c023514081b944ced687e68a0c2566484153aac8383ec442b6

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 = 0 if abs(n - eq) <= band else None
    for year in range(1, years + 1):
        n = r0 * n / (1 + r0 * 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 = [[('regression: 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]),
  ('regression: 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]),
  ('regression: replacement r0 one', (200, 1.0, 1000, 4), [[200.0, 200.0, 200.0, 200.0], 0.0, None]),
  ('regression: 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: invalid r0', (100, 0.0, 1000, 5), None)],
 [('regression: start within band', (995, 2.0, 1000, 3), [[997.4937, 998.7453, 999.3723], 1000.0, 0]),
  ('regression: replacement r0 one', (200, 1.0, 1000, 4), [[200.0, 200.0, 200.0, 200.0], 0.0, None]),
  ('regression: 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]),
  ('regression: 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),
  ('regression: never reaches band',
   (1, 1.2, 10000, 5),
   [[1.2, 1.4399, 1.7279, 2.0734, 2.4879], 10000.0, None]),
  ('regression: one year from band',
   (985, 2.0, 1000, 4),
   [[992.4433, 996.2073, 998.1001, 999.0491], 1000.0, 1])],
 [('regression: 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]),
  ('regression: 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: 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),
  ('regression: never reaches band',
   (1, 1.2, 10000, 5),
   [[1.2, 1.4399, 1.7279, 2.0734, 2.4879], 10000.0, None]),
  ('regression: one year from band',
   (985, 2.0, 1000, 4),
   [[992.4433, 996.2073, 998.1001, 999.0491], 1000.0, 1]),
  ('regression: small capacity',
   (2, 4.0, 20, 6),
   [[6.1538, 12.8, 17.5342, 19.3208, 19.8258, 19.9562], 20.0, 5])],
 [('regression: 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]),
  ('regression: 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: invalid r0', (100, 0.0, 1000, 5), None),
  ('regression: one year from band',
   (985, 2.0, 1000, 4),
   [[992.4433, 996.2073, 998.1001, 999.0491], 1000.0, 1]),
  ('regression: small capacity',
   (2, 4.0, 20, 6),
   [[6.1538, 12.8, 17.5342, 19.3208, 19.8258, 19.9562], 20.0, 5])],
 [('regression: 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]),
  ('regression: replacement r0 one', (200, 1.0, 1000, 4), [[200.0, 200.0, 200.0, 200.0], 0.0, None]),
  ('regression: 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]),
  ('regression: 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
regression: herring recruitment[[130.4348, 281.25, 457.6271, 578.5714, 634.4648, 655.5755, 662.9282, 665.4158, 666.2492, 666.5275], 1000.0, None][[136.3636, 321.4286, 586.9565, 810.0, 927.4809, 974.5989, 991.3871, 997.1125, 999.0356, 999.6783], 1000.0, 7]Failed
regression: slow approach[[14.5631, 20.9302, 29.5405, 40.7035, 54.4111, 70.1636, 86.9444, 103.4369, 118.4111, 131.0598, 141.1087, 148.7101], 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]Failed
regression: start at capacity[[666.6667, 571.4286, 533.3333, 516.129], 1000.0, 0][[1000.0, 1000.0, 1000.0, 1000.0], 1000.0, 0]Failed
regression: start within band[[665.5518, 571.0187, 533.1547], 1000.0, 0][[997.4937, 998.7453, 999.3723], 1000.0, 0]Failed
regression: replacement r0 one[[166.6667, 142.8571, 125.0, 111.1111], 0.0, None][[200.0, 200.0, 200.0, 200.0], 0.0, None]Failed
regression: declining r0 half[[166.6667, 76.9231, 37.037, 18.1818, 9.009, 4.4843, 2.2371, 1.1173], 0.0, 5][[250.0, 142.8571, 76.9231, 40.0, 20.4082, 10.3093, 5.1813, 2.5974], 0.0, 7]Failed
control: invalid r0NoneNonePassed

SHA-256 / 93e452af5adaf024329a95f012383f9aa14a37c4f23bd8992579d0467f9bbf45

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 = [[('regression: 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]),
  ('regression: 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]),
  ('regression: replacement r0 one', (200, 1.0, 1000, 4), [[200.0, 200.0, 200.0, 200.0], 0.0, None]),
  ('regression: 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: invalid r0', (100, 0.0, 1000, 5), None)],
 [('regression: start within band', (995, 2.0, 1000, 3), [[997.4937, 998.7453, 999.3723], 1000.0, 0]),
  ('regression: replacement r0 one', (200, 1.0, 1000, 4), [[200.0, 200.0, 200.0, 200.0], 0.0, None]),
  ('regression: 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]),
  ('regression: 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),
  ('regression: never reaches band',
   (1, 1.2, 10000, 5),
   [[1.2, 1.4399, 1.7279, 2.0734, 2.4879], 10000.0, None]),
  ('regression: one year from band',
   (985, 2.0, 1000, 4),
   [[992.4433, 996.2073, 998.1001, 999.0491], 1000.0, 1])],
 [('regression: 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]),
  ('regression: 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: 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),
  ('regression: never reaches band',
   (1, 1.2, 10000, 5),
   [[1.2, 1.4399, 1.7279, 2.0734, 2.4879], 10000.0, None]),
  ('regression: one year from band',
   (985, 2.0, 1000, 4),
   [[992.4433, 996.2073, 998.1001, 999.0491], 1000.0, 1]),
  ('regression: small capacity',
   (2, 4.0, 20, 6),
   [[6.1538, 12.8, 17.5342, 19.3208, 19.8258, 19.9562], 20.0, 5])],
 [('regression: 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]),
  ('regression: 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: invalid r0', (100, 0.0, 1000, 5), None),
  ('regression: one year from band',
   (985, 2.0, 1000, 4),
   [[992.4433, 996.2073, 998.1001, 999.0491], 1000.0, 1]),
  ('regression: small capacity',
   (2, 4.0, 20, 6),
   [[6.1538, 12.8, 17.5342, 19.3208, 19.8258, 19.9562], 20.0, 5])],
 [('regression: 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]),
  ('regression: replacement r0 one', (200, 1.0, 1000, 4), [[200.0, 200.0, 200.0, 200.0], 0.0, None]),
  ('regression: 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]),
  ('regression: 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
regression: 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
regression: 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
regression: 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
regression: 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: invalid r0NoneNonePassed

SHA-256 / 7f5c8ecbbfdd4b3b3c5ed7e233fc2a862b48961d0c94c01a4f144df99aa495ec

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

Case digest / 2ebc0c240e46af04fe5cd6fffe5efea087eb0386452cab34e7629dcf91755814