FAILURE MAP
← Case archive

FA-65681 / Ecological population dynamics / Open access

Stochastic growth rate and quasi-extinction: quasi-extinction comparison · case 01

Populations exactly at the threshold are counted as quasi-extinct.

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

ROOT CAUSE

The threshold comparison includes equality.

VERIFIED REPAIR

Restore the quasi-extinction comparison rule: `n < threshold`.

Unsuccessful approach: Rounding abundance to whole animals hides fractional dips below the threshold.

Case contract

Geometric mean growth exp(mean ln lambda) determines trend (declining <1, stable ==1, growing >1); arithmetic mean reported alongside; trajectory multiplies N by each lambda; quasi-extinction time is the first 1-based year with N < threshold or None; return [geo, arith, trajectory, hit, trend]; None for empty, non-positive lambdas or N0<=0.

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(lambdas, n0, threshold):
    if not lambdas or min(lambdas) <= 0 or n0 <= 0:
        return None
    logs = [math.log(x) for x in lambdas]
    geo = math.exp(sum(logs) / len(logs))
    arith = sum(lambdas) / len(lambdas)
    n = float(n0)
    traj = []
    hit = None
    for t, lam in enumerate(lambdas, start=1):
        n *= lam
        traj.append(round(n, 4))
        if hit is None and n <= threshold:
            hit = t
    trend = 'declining' if geo < 1 else ('stable' if geo == 1 else 'growing')
    return [round(geo, 6), round(arith, 6), traj, hit, trend]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('control: boom and bust',
   ([1.5, 0.5, 1.5, 0.5], 100, 20),
   [0.866025, 1.0, [150.0, 75.0, 112.5, 56.25], None, 'declining']),
  ('regression: exact halving to threshold',
   ([0.5, 1.0, 2.0], 100, 50),
   [1.0, 1.166667, [50.0, 50.0, 100.0], None, 'stable']),
  ('control: balanced doubling halving', ([2.0, 0.5], 100, 10), [1.0, 1.25, [200.0, 100.0], None, 'stable']),
  ('control: steady growth',
   ([1.1, 1.2, 1.05], 50, 10),
   [1.114947, 1.116667, [55.0, 66.0, 69.3], None, 'growing']),
  ('control: constant', ([1.0, 1.0, 1.0], 30, 5), [1.0, 1.0, [30.0, 30.0, 30.0], None, 'stable']),
  ('control: dip and recovery',
   ([0.4, 0.8, 3.0, 2.0], 100, 50),
   [1.177132, 1.55, [40.0, 32.0, 96.0, 192.0], 1, 'growing']),
  ('regression: fractional dip', ([0.496, 1.2], 100, 50), [0.771492, 0.848, [49.6, 59.52], 1, 'declining'])],
 [('regression: exact halving to threshold',
   ([0.5, 1.0, 2.0], 100, 50),
   [1.0, 1.166667, [50.0, 50.0, 100.0], None, 'stable']),
  ('control: steady growth',
   ([1.1, 1.2, 1.05], 50, 10),
   [1.114947, 1.116667, [55.0, 66.0, 69.3], None, 'growing']),
  ('control: constant', ([1.0, 1.0, 1.0], 30, 5), [1.0, 1.0, [30.0, 30.0, 30.0], None, 'stable']),
  ('control: dip and recovery',
   ([0.4, 0.8, 3.0, 2.0], 100, 50),
   [1.177132, 1.55, [40.0, 32.0, 96.0, 192.0], 1, 'growing']),
  ('control: invalid zero lambda', ([1.0, 0.0], 10, 1), None),
  ('control: first year crash',
   ([0.1, 1.5, 1.5], 100, 20),
   [0.60822, 1.033333, [10.0, 15.0, 22.5], 1, 'declining']),
  ('regression: fractional dip', ([0.496, 1.2], 100, 50), [0.771492, 0.848, [49.6, 59.52], 1, 'declining'])],
 [('control: boom and bust',
   ([1.5, 0.5, 1.5, 0.5], 100, 20),
   [0.866025, 1.0, [150.0, 75.0, 112.5, 56.25], None, 'declining']),
  ('regression: exact halving to threshold',
   ([0.5, 1.0, 2.0], 100, 50),
   [1.0, 1.166667, [50.0, 50.0, 100.0], None, 'stable']),
  ('control: invalid zero lambda', ([1.0, 0.0], 10, 1), None),
  ('control: first year crash',
   ([0.1, 1.5, 1.5], 100, 20),
   [0.60822, 1.033333, [10.0, 15.0, 22.5], 1, 'declining']),
  ('control: high variance decline',
   ([3.0, 0.3, 3.0, 0.3], 100, 5),
   [0.948683, 1.65, [300.0, 90.0, 270.0, 81.0], None, 'declining']),
  ('regression: fractional dip', ([0.496, 1.2], 100, 50), [0.771492, 0.848, [49.6, 59.52], 1, 'declining']),
  ('control: slow decline',
   ([0.95, 1.02, 0.9, 1.05, 0.93], 80, 60),
   [0.968384, 0.97, [76.0, 77.52, 69.768, 73.2564, 68.1285], None, 'declining'])],
 [('control: boom and bust',
   ([1.5, 0.5, 1.5, 0.5], 100, 20),
   [0.866025, 1.0, [150.0, 75.0, 112.5, 56.25], None, 'declining']),
  ('regression: exact halving to threshold',
   ([0.5, 1.0, 2.0], 100, 50),
   [1.0, 1.166667, [50.0, 50.0, 100.0], None, 'stable']),
  ('control: balanced doubling halving', ([2.0, 0.5], 100, 10), [1.0, 1.25, [200.0, 100.0], None, 'stable']),
  ('control: steady growth',
   ([1.1, 1.2, 1.05], 50, 10),
   [1.114947, 1.116667, [55.0, 66.0, 69.3], None, 'growing']),
  ('control: constant', ([1.0, 1.0, 1.0], 30, 5), [1.0, 1.0, [30.0, 30.0, 30.0], None, 'stable']),
  ('regression: fractional dip', ([0.496, 1.2], 100, 50), [0.771492, 0.848, [49.6, 59.52], 1, 'declining']),
  ('control: slow decline',
   ([0.95, 1.02, 0.9, 1.05, 0.93], 80, 60),
   [0.968384, 0.97, [76.0, 77.52, 69.768, 73.2564, 68.1285], None, 'declining'])],
 [('regression: exact halving to threshold',
   ([0.5, 1.0, 2.0], 100, 50),
   [1.0, 1.166667, [50.0, 50.0, 100.0], None, 'stable']),
  ('control: balanced doubling halving', ([2.0, 0.5], 100, 10), [1.0, 1.25, [200.0, 100.0], None, 'stable']),
  ('control: steady growth',
   ([1.1, 1.2, 1.05], 50, 10),
   [1.114947, 1.116667, [55.0, 66.0, 69.3], None, 'growing']),
  ('control: constant', ([1.0, 1.0, 1.0], 30, 5), [1.0, 1.0, [30.0, 30.0, 30.0], None, 'stable']),
  ('control: dip and recovery',
   ([0.4, 0.8, 3.0, 2.0], 100, 50),
   [1.177132, 1.55, [40.0, 32.0, 96.0, 192.0], 1, 'growing']),
  ('control: invalid zero lambda', ([1.0, 0.0], 10, 1), None),
  ('regression: fractional dip', ([0.496, 1.2], 100, 50), [0.771492, 0.848, [49.6, 59.52], 1, 'declining'])]]
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: boom and bust[0.866025, 1.0, [150.0, 75.0, 112.5, 56.25], None, 'declining'][0.866025, 1.0, [150.0, 75.0, 112.5, 56.25], None, 'declining']Passed
regression: exact halving to threshold[1.0, 1.166667, [50.0, 50.0, 100.0], 1, 'stable'][1.0, 1.166667, [50.0, 50.0, 100.0], None, 'stable']Failed
control: balanced doubling halving[1.0, 1.25, [200.0, 100.0], None, 'stable'][1.0, 1.25, [200.0, 100.0], None, 'stable']Passed
control: steady growth[1.114947, 1.116667, [55.0, 66.0, 69.3], None, 'growing'][1.114947, 1.116667, [55.0, 66.0, 69.3], None, 'growing']Passed
control: constant[1.0, 1.0, [30.0, 30.0, 30.0], None, 'stable'][1.0, 1.0, [30.0, 30.0, 30.0], None, 'stable']Passed
control: dip and recovery[1.177132, 1.55, [40.0, 32.0, 96.0, 192.0], 1, 'growing'][1.177132, 1.55, [40.0, 32.0, 96.0, 192.0], 1, 'growing']Passed
regression: fractional dip[0.771492, 0.848, [49.6, 59.52], 1, 'declining'][0.771492, 0.848, [49.6, 59.52], 1, 'declining']Passed

SHA-256 / bd56a69902acc7c93bbc2005efcbe72a11a209b04f8f1dedfa91eeb07d0ccdcb

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(lambdas, n0, threshold):
    if not lambdas or min(lambdas) <= 0 or n0 <= 0:
        return None
    logs = [math.log(x) for x in lambdas]
    geo = math.exp(sum(logs) / len(logs))
    arith = sum(lambdas) / len(lambdas)
    n = float(n0)
    traj = []
    hit = None
    for t, lam in enumerate(lambdas, start=1):
        n *= lam
        traj.append(round(n, 4))
        if hit is None and round(n) < threshold:
            hit = t
    trend = 'declining' if geo < 1 else ('stable' if geo == 1 else 'growing')
    return [round(geo, 6), round(arith, 6), traj, hit, trend]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('control: boom and bust',
   ([1.5, 0.5, 1.5, 0.5], 100, 20),
   [0.866025, 1.0, [150.0, 75.0, 112.5, 56.25], None, 'declining']),
  ('regression: exact halving to threshold',
   ([0.5, 1.0, 2.0], 100, 50),
   [1.0, 1.166667, [50.0, 50.0, 100.0], None, 'stable']),
  ('control: balanced doubling halving', ([2.0, 0.5], 100, 10), [1.0, 1.25, [200.0, 100.0], None, 'stable']),
  ('control: steady growth',
   ([1.1, 1.2, 1.05], 50, 10),
   [1.114947, 1.116667, [55.0, 66.0, 69.3], None, 'growing']),
  ('control: constant', ([1.0, 1.0, 1.0], 30, 5), [1.0, 1.0, [30.0, 30.0, 30.0], None, 'stable']),
  ('control: dip and recovery',
   ([0.4, 0.8, 3.0, 2.0], 100, 50),
   [1.177132, 1.55, [40.0, 32.0, 96.0, 192.0], 1, 'growing']),
  ('regression: fractional dip', ([0.496, 1.2], 100, 50), [0.771492, 0.848, [49.6, 59.52], 1, 'declining'])],
 [('regression: exact halving to threshold',
   ([0.5, 1.0, 2.0], 100, 50),
   [1.0, 1.166667, [50.0, 50.0, 100.0], None, 'stable']),
  ('control: steady growth',
   ([1.1, 1.2, 1.05], 50, 10),
   [1.114947, 1.116667, [55.0, 66.0, 69.3], None, 'growing']),
  ('control: constant', ([1.0, 1.0, 1.0], 30, 5), [1.0, 1.0, [30.0, 30.0, 30.0], None, 'stable']),
  ('control: dip and recovery',
   ([0.4, 0.8, 3.0, 2.0], 100, 50),
   [1.177132, 1.55, [40.0, 32.0, 96.0, 192.0], 1, 'growing']),
  ('control: invalid zero lambda', ([1.0, 0.0], 10, 1), None),
  ('control: first year crash',
   ([0.1, 1.5, 1.5], 100, 20),
   [0.60822, 1.033333, [10.0, 15.0, 22.5], 1, 'declining']),
  ('regression: fractional dip', ([0.496, 1.2], 100, 50), [0.771492, 0.848, [49.6, 59.52], 1, 'declining'])],
 [('control: boom and bust',
   ([1.5, 0.5, 1.5, 0.5], 100, 20),
   [0.866025, 1.0, [150.0, 75.0, 112.5, 56.25], None, 'declining']),
  ('regression: exact halving to threshold',
   ([0.5, 1.0, 2.0], 100, 50),
   [1.0, 1.166667, [50.0, 50.0, 100.0], None, 'stable']),
  ('control: invalid zero lambda', ([1.0, 0.0], 10, 1), None),
  ('control: first year crash',
   ([0.1, 1.5, 1.5], 100, 20),
   [0.60822, 1.033333, [10.0, 15.0, 22.5], 1, 'declining']),
  ('control: high variance decline',
   ([3.0, 0.3, 3.0, 0.3], 100, 5),
   [0.948683, 1.65, [300.0, 90.0, 270.0, 81.0], None, 'declining']),
  ('regression: fractional dip', ([0.496, 1.2], 100, 50), [0.771492, 0.848, [49.6, 59.52], 1, 'declining']),
  ('control: slow decline',
   ([0.95, 1.02, 0.9, 1.05, 0.93], 80, 60),
   [0.968384, 0.97, [76.0, 77.52, 69.768, 73.2564, 68.1285], None, 'declining'])],
 [('control: boom and bust',
   ([1.5, 0.5, 1.5, 0.5], 100, 20),
   [0.866025, 1.0, [150.0, 75.0, 112.5, 56.25], None, 'declining']),
  ('regression: exact halving to threshold',
   ([0.5, 1.0, 2.0], 100, 50),
   [1.0, 1.166667, [50.0, 50.0, 100.0], None, 'stable']),
  ('control: balanced doubling halving', ([2.0, 0.5], 100, 10), [1.0, 1.25, [200.0, 100.0], None, 'stable']),
  ('control: steady growth',
   ([1.1, 1.2, 1.05], 50, 10),
   [1.114947, 1.116667, [55.0, 66.0, 69.3], None, 'growing']),
  ('control: constant', ([1.0, 1.0, 1.0], 30, 5), [1.0, 1.0, [30.0, 30.0, 30.0], None, 'stable']),
  ('regression: fractional dip', ([0.496, 1.2], 100, 50), [0.771492, 0.848, [49.6, 59.52], 1, 'declining']),
  ('control: slow decline',
   ([0.95, 1.02, 0.9, 1.05, 0.93], 80, 60),
   [0.968384, 0.97, [76.0, 77.52, 69.768, 73.2564, 68.1285], None, 'declining'])],
 [('regression: exact halving to threshold',
   ([0.5, 1.0, 2.0], 100, 50),
   [1.0, 1.166667, [50.0, 50.0, 100.0], None, 'stable']),
  ('control: balanced doubling halving', ([2.0, 0.5], 100, 10), [1.0, 1.25, [200.0, 100.0], None, 'stable']),
  ('control: steady growth',
   ([1.1, 1.2, 1.05], 50, 10),
   [1.114947, 1.116667, [55.0, 66.0, 69.3], None, 'growing']),
  ('control: constant', ([1.0, 1.0, 1.0], 30, 5), [1.0, 1.0, [30.0, 30.0, 30.0], None, 'stable']),
  ('control: dip and recovery',
   ([0.4, 0.8, 3.0, 2.0], 100, 50),
   [1.177132, 1.55, [40.0, 32.0, 96.0, 192.0], 1, 'growing']),
  ('control: invalid zero lambda', ([1.0, 0.0], 10, 1), None),
  ('regression: fractional dip', ([0.496, 1.2], 100, 50), [0.771492, 0.848, [49.6, 59.52], 1, 'declining'])]]
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: boom and bust[0.866025, 1.0, [150.0, 75.0, 112.5, 56.25], None, 'declining'][0.866025, 1.0, [150.0, 75.0, 112.5, 56.25], None, 'declining']Passed
regression: exact halving to threshold[1.0, 1.166667, [50.0, 50.0, 100.0], None, 'stable'][1.0, 1.166667, [50.0, 50.0, 100.0], None, 'stable']Passed
control: balanced doubling halving[1.0, 1.25, [200.0, 100.0], None, 'stable'][1.0, 1.25, [200.0, 100.0], None, 'stable']Passed
control: steady growth[1.114947, 1.116667, [55.0, 66.0, 69.3], None, 'growing'][1.114947, 1.116667, [55.0, 66.0, 69.3], None, 'growing']Passed
control: constant[1.0, 1.0, [30.0, 30.0, 30.0], None, 'stable'][1.0, 1.0, [30.0, 30.0, 30.0], None, 'stable']Passed
control: dip and recovery[1.177132, 1.55, [40.0, 32.0, 96.0, 192.0], 1, 'growing'][1.177132, 1.55, [40.0, 32.0, 96.0, 192.0], 1, 'growing']Passed
regression: fractional dip[0.771492, 0.848, [49.6, 59.52], None, 'declining'][0.771492, 0.848, [49.6, 59.52], 1, 'declining']Failed

SHA-256 / 4dff83e4118c546cd4b2a4323b2bf070384781b509ad17f855c58411fcf21276

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(lambdas, n0, threshold):
    if not lambdas or min(lambdas) <= 0 or n0 <= 0:
        return None
    logs = [math.log(x) for x in lambdas]
    geo = math.exp(sum(logs) / len(logs))
    arith = sum(lambdas) / len(lambdas)
    n = float(n0)
    traj = []
    hit = None
    for t, lam in enumerate(lambdas, start=1):
        n *= lam
        traj.append(round(n, 4))
        if hit is None and n < threshold:
            hit = t
    trend = 'declining' if geo < 1 else ('stable' if geo == 1 else 'growing')
    return [round(geo, 6), round(arith, 6), traj, hit, trend]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('control: boom and bust',
   ([1.5, 0.5, 1.5, 0.5], 100, 20),
   [0.866025, 1.0, [150.0, 75.0, 112.5, 56.25], None, 'declining']),
  ('regression: exact halving to threshold',
   ([0.5, 1.0, 2.0], 100, 50),
   [1.0, 1.166667, [50.0, 50.0, 100.0], None, 'stable']),
  ('control: balanced doubling halving', ([2.0, 0.5], 100, 10), [1.0, 1.25, [200.0, 100.0], None, 'stable']),
  ('control: steady growth',
   ([1.1, 1.2, 1.05], 50, 10),
   [1.114947, 1.116667, [55.0, 66.0, 69.3], None, 'growing']),
  ('control: constant', ([1.0, 1.0, 1.0], 30, 5), [1.0, 1.0, [30.0, 30.0, 30.0], None, 'stable']),
  ('control: dip and recovery',
   ([0.4, 0.8, 3.0, 2.0], 100, 50),
   [1.177132, 1.55, [40.0, 32.0, 96.0, 192.0], 1, 'growing']),
  ('regression: fractional dip', ([0.496, 1.2], 100, 50), [0.771492, 0.848, [49.6, 59.52], 1, 'declining'])],
 [('regression: exact halving to threshold',
   ([0.5, 1.0, 2.0], 100, 50),
   [1.0, 1.166667, [50.0, 50.0, 100.0], None, 'stable']),
  ('control: steady growth',
   ([1.1, 1.2, 1.05], 50, 10),
   [1.114947, 1.116667, [55.0, 66.0, 69.3], None, 'growing']),
  ('control: constant', ([1.0, 1.0, 1.0], 30, 5), [1.0, 1.0, [30.0, 30.0, 30.0], None, 'stable']),
  ('control: dip and recovery',
   ([0.4, 0.8, 3.0, 2.0], 100, 50),
   [1.177132, 1.55, [40.0, 32.0, 96.0, 192.0], 1, 'growing']),
  ('control: invalid zero lambda', ([1.0, 0.0], 10, 1), None),
  ('control: first year crash',
   ([0.1, 1.5, 1.5], 100, 20),
   [0.60822, 1.033333, [10.0, 15.0, 22.5], 1, 'declining']),
  ('regression: fractional dip', ([0.496, 1.2], 100, 50), [0.771492, 0.848, [49.6, 59.52], 1, 'declining'])],
 [('control: boom and bust',
   ([1.5, 0.5, 1.5, 0.5], 100, 20),
   [0.866025, 1.0, [150.0, 75.0, 112.5, 56.25], None, 'declining']),
  ('regression: exact halving to threshold',
   ([0.5, 1.0, 2.0], 100, 50),
   [1.0, 1.166667, [50.0, 50.0, 100.0], None, 'stable']),
  ('control: invalid zero lambda', ([1.0, 0.0], 10, 1), None),
  ('control: first year crash',
   ([0.1, 1.5, 1.5], 100, 20),
   [0.60822, 1.033333, [10.0, 15.0, 22.5], 1, 'declining']),
  ('control: high variance decline',
   ([3.0, 0.3, 3.0, 0.3], 100, 5),
   [0.948683, 1.65, [300.0, 90.0, 270.0, 81.0], None, 'declining']),
  ('regression: fractional dip', ([0.496, 1.2], 100, 50), [0.771492, 0.848, [49.6, 59.52], 1, 'declining']),
  ('control: slow decline',
   ([0.95, 1.02, 0.9, 1.05, 0.93], 80, 60),
   [0.968384, 0.97, [76.0, 77.52, 69.768, 73.2564, 68.1285], None, 'declining'])],
 [('control: boom and bust',
   ([1.5, 0.5, 1.5, 0.5], 100, 20),
   [0.866025, 1.0, [150.0, 75.0, 112.5, 56.25], None, 'declining']),
  ('regression: exact halving to threshold',
   ([0.5, 1.0, 2.0], 100, 50),
   [1.0, 1.166667, [50.0, 50.0, 100.0], None, 'stable']),
  ('control: balanced doubling halving', ([2.0, 0.5], 100, 10), [1.0, 1.25, [200.0, 100.0], None, 'stable']),
  ('control: steady growth',
   ([1.1, 1.2, 1.05], 50, 10),
   [1.114947, 1.116667, [55.0, 66.0, 69.3], None, 'growing']),
  ('control: constant', ([1.0, 1.0, 1.0], 30, 5), [1.0, 1.0, [30.0, 30.0, 30.0], None, 'stable']),
  ('regression: fractional dip', ([0.496, 1.2], 100, 50), [0.771492, 0.848, [49.6, 59.52], 1, 'declining']),
  ('control: slow decline',
   ([0.95, 1.02, 0.9, 1.05, 0.93], 80, 60),
   [0.968384, 0.97, [76.0, 77.52, 69.768, 73.2564, 68.1285], None, 'declining'])],
 [('regression: exact halving to threshold',
   ([0.5, 1.0, 2.0], 100, 50),
   [1.0, 1.166667, [50.0, 50.0, 100.0], None, 'stable']),
  ('control: balanced doubling halving', ([2.0, 0.5], 100, 10), [1.0, 1.25, [200.0, 100.0], None, 'stable']),
  ('control: steady growth',
   ([1.1, 1.2, 1.05], 50, 10),
   [1.114947, 1.116667, [55.0, 66.0, 69.3], None, 'growing']),
  ('control: constant', ([1.0, 1.0, 1.0], 30, 5), [1.0, 1.0, [30.0, 30.0, 30.0], None, 'stable']),
  ('control: dip and recovery',
   ([0.4, 0.8, 3.0, 2.0], 100, 50),
   [1.177132, 1.55, [40.0, 32.0, 96.0, 192.0], 1, 'growing']),
  ('control: invalid zero lambda', ([1.0, 0.0], 10, 1), None),
  ('regression: fractional dip', ([0.496, 1.2], 100, 50), [0.771492, 0.848, [49.6, 59.52], 1, 'declining'])]]
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: boom and bust[0.866025, 1.0, [150.0, 75.0, 112.5, 56.25], None, 'declining'][0.866025, 1.0, [150.0, 75.0, 112.5, 56.25], None, 'declining']Passed
regression: exact halving to threshold[1.0, 1.166667, [50.0, 50.0, 100.0], None, 'stable'][1.0, 1.166667, [50.0, 50.0, 100.0], None, 'stable']Passed
control: balanced doubling halving[1.0, 1.25, [200.0, 100.0], None, 'stable'][1.0, 1.25, [200.0, 100.0], None, 'stable']Passed
control: steady growth[1.114947, 1.116667, [55.0, 66.0, 69.3], None, 'growing'][1.114947, 1.116667, [55.0, 66.0, 69.3], None, 'growing']Passed
control: constant[1.0, 1.0, [30.0, 30.0, 30.0], None, 'stable'][1.0, 1.0, [30.0, 30.0, 30.0], None, 'stable']Passed
control: dip and recovery[1.177132, 1.55, [40.0, 32.0, 96.0, 192.0], 1, 'growing'][1.177132, 1.55, [40.0, 32.0, 96.0, 192.0], 1, 'growing']Passed
regression: fractional dip[0.771492, 0.848, [49.6, 59.52], 1, 'declining'][0.771492, 0.848, [49.6, 59.52], 1, 'declining']Passed

SHA-256 / 17756f051464e225f5a86d0d2b9703584c07f5cd8fdab5339fe6234e2c4ecf3e

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

Case digest / c812b1854b13d30d029f1352d1d52c4e953524bd1ebe708a2b99eb84713bf386