FA-64996 / Epidemic compartment models / Open access
SIS endemic equilibrium convergence: day cap · case 01
Non-converging runs take one more step than allowed.
ROOT CAUSE
The day-cap comparison is inclusive.
VERIFIED REPAIR
Restore the day cap rule: `day < max_days`.
Unsuccessful approach: Stopping at max_days-1 takes one step too few.
Case contract
SIS with susceptibles pop-I; endemic target pop*(1-1/R0) if R0=beta/gamma>1 else 0; iterate daily Euler I += beta*I*(pop-I)/pop - gamma*I until |I-target| <= tol*pop or max_days steps; return [target rounded 4, days taken, I rounded 4] or None for non-positive beta, gamma or pop.
Why this case matters
Compartmental epidemic calculations drive outbreak forecasts, vaccine targets and hospital planning; a single wrong flow, rate conversion or boundary silently changes every downstream number.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(beta, gamma, pop, i0, tol, max_days):
if beta <= 0 or gamma <= 0 or pop <= 0:
return None
r0 = beta / gamma
target = pop * (1 - 1 / r0) if r0 > 1 else 0.0
i = float(i0)
day = 0
while abs(i - target) > tol * pop and day <= max_days:
i += beta * i * (pop - i) / pop - gamma * i
day += 1
return [round(target, 4), day, round(i, 4)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('control: gonorrhoea-like endemic', (0.3, 0.1, 1000, 10, 0.01, 200), [666.6667, 42, 657.0888]),
('control: subcritical dies out', (0.1, 0.2, 500, 50, 0.01, 200), [0.0, 21, 4.9755]),
('control: start above equilibrium', (0.4, 0.2, 1000, 900, 0.005, 100), [500.0, 17, 504.3274]),
('control: already at equilibrium', (0.4, 0.2, 1000, 500, 0.01, 50), [500.0, 0, 500.0]),
('regression: tight tolerance capped', (0.25, 0.2, 2000, 1, 0.0001, 30), [400.0, 30, 4.288]),
('regression: zero day cap', (0.3, 0.1, 100, 1, 0.01, 0), [66.6667, 0, 1.0]),
('control: invalid gamma', (0.3, 0.0, 100, 1, 0.01, 10), None)],
[('control: gonorrhoea-like endemic', (0.3, 0.1, 1000, 10, 0.01, 200), [666.6667, 42, 657.0888]),
('control: already at equilibrium', (0.4, 0.2, 1000, 500, 0.01, 50), [500.0, 0, 500.0]),
('regression: tight tolerance capped', (0.25, 0.2, 2000, 1, 0.0001, 30), [400.0, 30, 4.288]),
('regression: zero day cap', (0.3, 0.1, 100, 1, 0.01, 0), [66.6667, 0, 1.0]),
('control: invalid gamma', (0.3, 0.0, 100, 1, 0.01, 10), None),
('control: fast dynamics', (0.9, 0.3, 300, 3, 0.02, 100), [200.0, 14, 197.4596]),
('regression: near threshold', (0.21, 0.2, 10000, 100, 0.001, 60), [476.1905, 60, 155.2383])],
[('control: gonorrhoea-like endemic', (0.3, 0.1, 1000, 10, 0.01, 200), [666.6667, 42, 657.0888]),
('control: subcritical dies out', (0.1, 0.2, 500, 50, 0.01, 200), [0.0, 21, 4.9755]),
('control: start above equilibrium', (0.4, 0.2, 1000, 900, 0.005, 100), [500.0, 17, 504.3274]),
('regression: tight tolerance capped', (0.25, 0.2, 2000, 1, 0.0001, 30), [400.0, 30, 4.288]),
('control: invalid gamma', (0.3, 0.0, 100, 1, 0.01, 10), None),
('control: fast dynamics', (0.9, 0.3, 300, 3, 0.02, 100), [200.0, 14, 197.4596]),
('regression: near threshold', (0.21, 0.2, 10000, 100, 0.001, 60), [476.1905, 60, 155.2383])],
[('control: gonorrhoea-like endemic', (0.3, 0.1, 1000, 10, 0.01, 200), [666.6667, 42, 657.0888]),
('control: subcritical dies out', (0.1, 0.2, 500, 50, 0.01, 200), [0.0, 21, 4.9755]),
('control: start above equilibrium', (0.4, 0.2, 1000, 900, 0.005, 100), [500.0, 17, 504.3274]),
('control: already at equilibrium', (0.4, 0.2, 1000, 500, 0.01, 50), [500.0, 0, 500.0]),
('regression: tight tolerance capped', (0.25, 0.2, 2000, 1, 0.0001, 30), [400.0, 30, 4.288]),
('regression: zero day cap', (0.3, 0.1, 100, 1, 0.01, 0), [66.6667, 0, 1.0]),
('control: invalid gamma', (0.3, 0.0, 100, 1, 0.01, 10), None)],
[('control: gonorrhoea-like endemic', (0.3, 0.1, 1000, 10, 0.01, 200), [666.6667, 42, 657.0888]),
('control: already at equilibrium', (0.4, 0.2, 1000, 500, 0.01, 50), [500.0, 0, 500.0]),
('regression: tight tolerance capped', (0.25, 0.2, 2000, 1, 0.0001, 30), [400.0, 30, 4.288]),
('regression: zero day cap', (0.3, 0.1, 100, 1, 0.01, 0), [66.6667, 0, 1.0]),
('control: invalid gamma', (0.3, 0.0, 100, 1, 0.01, 10), None),
('control: fast dynamics', (0.9, 0.3, 300, 3, 0.02, 100), [200.0, 14, 197.4596]),
('regression: near threshold', (0.21, 0.2, 10000, 100, 0.001, 60), [476.1905, 60, 155.2383])]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| control: gonorrhoea-like endemic | [666.6667, 42, 657.0888] | [666.6667, 42, 657.0888] | Passed |
| control: subcritical dies out | [0.0, 21, 4.9755] | [0.0, 21, 4.9755] | Passed |
| control: start above equilibrium | [500.0, 17, 504.3274] | [500.0, 17, 504.3274] | Passed |
| control: already at equilibrium | [500.0, 0, 500.0] | [500.0, 0, 500.0] | Passed |
| regression: tight tolerance capped | [400.0, 31, 4.5001] | [400.0, 30, 4.288] | Failed |
| regression: zero day cap | [66.6667, 1, 1.197] | [66.6667, 0, 1.0] | Failed |
| control: invalid gamma | None | None | Passed |
SHA-256 / 4ffda6daa5875141457e56cda13364eae407d52fc2f3fab1b5e11ca3a4ffaf7c
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(beta, gamma, pop, i0, tol, max_days):
if beta <= 0 or gamma <= 0 or pop <= 0:
return None
r0 = beta / gamma
target = pop * (1 - 1 / r0) if r0 > 1 else 0.0
i = float(i0)
day = 0
while abs(i - target) > tol * pop and day < max_days - 1:
i += beta * i * (pop - i) / pop - gamma * i
day += 1
return [round(target, 4), day, round(i, 4)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('control: gonorrhoea-like endemic', (0.3, 0.1, 1000, 10, 0.01, 200), [666.6667, 42, 657.0888]),
('control: subcritical dies out', (0.1, 0.2, 500, 50, 0.01, 200), [0.0, 21, 4.9755]),
('control: start above equilibrium', (0.4, 0.2, 1000, 900, 0.005, 100), [500.0, 17, 504.3274]),
('control: already at equilibrium', (0.4, 0.2, 1000, 500, 0.01, 50), [500.0, 0, 500.0]),
('regression: tight tolerance capped', (0.25, 0.2, 2000, 1, 0.0001, 30), [400.0, 30, 4.288]),
('regression: zero day cap', (0.3, 0.1, 100, 1, 0.01, 0), [66.6667, 0, 1.0]),
('control: invalid gamma', (0.3, 0.0, 100, 1, 0.01, 10), None)],
[('control: gonorrhoea-like endemic', (0.3, 0.1, 1000, 10, 0.01, 200), [666.6667, 42, 657.0888]),
('control: already at equilibrium', (0.4, 0.2, 1000, 500, 0.01, 50), [500.0, 0, 500.0]),
('regression: tight tolerance capped', (0.25, 0.2, 2000, 1, 0.0001, 30), [400.0, 30, 4.288]),
('regression: zero day cap', (0.3, 0.1, 100, 1, 0.01, 0), [66.6667, 0, 1.0]),
('control: invalid gamma', (0.3, 0.0, 100, 1, 0.01, 10), None),
('control: fast dynamics', (0.9, 0.3, 300, 3, 0.02, 100), [200.0, 14, 197.4596]),
('regression: near threshold', (0.21, 0.2, 10000, 100, 0.001, 60), [476.1905, 60, 155.2383])],
[('control: gonorrhoea-like endemic', (0.3, 0.1, 1000, 10, 0.01, 200), [666.6667, 42, 657.0888]),
('control: subcritical dies out', (0.1, 0.2, 500, 50, 0.01, 200), [0.0, 21, 4.9755]),
('control: start above equilibrium', (0.4, 0.2, 1000, 900, 0.005, 100), [500.0, 17, 504.3274]),
('regression: tight tolerance capped', (0.25, 0.2, 2000, 1, 0.0001, 30), [400.0, 30, 4.288]),
('control: invalid gamma', (0.3, 0.0, 100, 1, 0.01, 10), None),
('control: fast dynamics', (0.9, 0.3, 300, 3, 0.02, 100), [200.0, 14, 197.4596]),
('regression: near threshold', (0.21, 0.2, 10000, 100, 0.001, 60), [476.1905, 60, 155.2383])],
[('control: gonorrhoea-like endemic', (0.3, 0.1, 1000, 10, 0.01, 200), [666.6667, 42, 657.0888]),
('control: subcritical dies out', (0.1, 0.2, 500, 50, 0.01, 200), [0.0, 21, 4.9755]),
('control: start above equilibrium', (0.4, 0.2, 1000, 900, 0.005, 100), [500.0, 17, 504.3274]),
('control: already at equilibrium', (0.4, 0.2, 1000, 500, 0.01, 50), [500.0, 0, 500.0]),
('regression: tight tolerance capped', (0.25, 0.2, 2000, 1, 0.0001, 30), [400.0, 30, 4.288]),
('regression: zero day cap', (0.3, 0.1, 100, 1, 0.01, 0), [66.6667, 0, 1.0]),
('control: invalid gamma', (0.3, 0.0, 100, 1, 0.01, 10), None)],
[('control: gonorrhoea-like endemic', (0.3, 0.1, 1000, 10, 0.01, 200), [666.6667, 42, 657.0888]),
('control: already at equilibrium', (0.4, 0.2, 1000, 500, 0.01, 50), [500.0, 0, 500.0]),
('regression: tight tolerance capped', (0.25, 0.2, 2000, 1, 0.0001, 30), [400.0, 30, 4.288]),
('regression: zero day cap', (0.3, 0.1, 100, 1, 0.01, 0), [66.6667, 0, 1.0]),
('control: invalid gamma', (0.3, 0.0, 100, 1, 0.01, 10), None),
('control: fast dynamics', (0.9, 0.3, 300, 3, 0.02, 100), [200.0, 14, 197.4596]),
('regression: near threshold', (0.21, 0.2, 10000, 100, 0.001, 60), [476.1905, 60, 155.2383])]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| control: gonorrhoea-like endemic | [666.6667, 42, 657.0888] | [666.6667, 42, 657.0888] | Passed |
| control: subcritical dies out | [0.0, 21, 4.9755] | [0.0, 21, 4.9755] | Passed |
| control: start above equilibrium | [500.0, 17, 504.3274] | [500.0, 17, 504.3274] | Passed |
| control: already at equilibrium | [500.0, 0, 500.0] | [500.0, 0, 500.0] | Passed |
| regression: tight tolerance capped | [400.0, 29, 4.0858] | [400.0, 30, 4.288] | Failed |
| regression: zero day cap | [66.6667, 0, 1.0] | [66.6667, 0, 1.0] | Passed |
| control: invalid gamma | None | None | Passed |
SHA-256 / a846fbde8f298a1e05fc014366218c4e4b933d63cb9258b437da72977f6adb8e
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
import math
N = 1
observations = []
def solve(beta, gamma, pop, i0, tol, max_days):
if beta <= 0 or gamma <= 0 or pop <= 0:
return None
r0 = beta / gamma
target = pop * (1 - 1 / r0) if r0 > 1 else 0.0
i = float(i0)
day = 0
while abs(i - target) > tol * pop and day < max_days:
i += beta * i * (pop - i) / pop - gamma * i
day += 1
return [round(target, 4), day, round(i, 4)]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('control: gonorrhoea-like endemic', (0.3, 0.1, 1000, 10, 0.01, 200), [666.6667, 42, 657.0888]),
('control: subcritical dies out', (0.1, 0.2, 500, 50, 0.01, 200), [0.0, 21, 4.9755]),
('control: start above equilibrium', (0.4, 0.2, 1000, 900, 0.005, 100), [500.0, 17, 504.3274]),
('control: already at equilibrium', (0.4, 0.2, 1000, 500, 0.01, 50), [500.0, 0, 500.0]),
('regression: tight tolerance capped', (0.25, 0.2, 2000, 1, 0.0001, 30), [400.0, 30, 4.288]),
('regression: zero day cap', (0.3, 0.1, 100, 1, 0.01, 0), [66.6667, 0, 1.0]),
('control: invalid gamma', (0.3, 0.0, 100, 1, 0.01, 10), None)],
[('control: gonorrhoea-like endemic', (0.3, 0.1, 1000, 10, 0.01, 200), [666.6667, 42, 657.0888]),
('control: already at equilibrium', (0.4, 0.2, 1000, 500, 0.01, 50), [500.0, 0, 500.0]),
('regression: tight tolerance capped', (0.25, 0.2, 2000, 1, 0.0001, 30), [400.0, 30, 4.288]),
('regression: zero day cap', (0.3, 0.1, 100, 1, 0.01, 0), [66.6667, 0, 1.0]),
('control: invalid gamma', (0.3, 0.0, 100, 1, 0.01, 10), None),
('control: fast dynamics', (0.9, 0.3, 300, 3, 0.02, 100), [200.0, 14, 197.4596]),
('regression: near threshold', (0.21, 0.2, 10000, 100, 0.001, 60), [476.1905, 60, 155.2383])],
[('control: gonorrhoea-like endemic', (0.3, 0.1, 1000, 10, 0.01, 200), [666.6667, 42, 657.0888]),
('control: subcritical dies out', (0.1, 0.2, 500, 50, 0.01, 200), [0.0, 21, 4.9755]),
('control: start above equilibrium', (0.4, 0.2, 1000, 900, 0.005, 100), [500.0, 17, 504.3274]),
('regression: tight tolerance capped', (0.25, 0.2, 2000, 1, 0.0001, 30), [400.0, 30, 4.288]),
('control: invalid gamma', (0.3, 0.0, 100, 1, 0.01, 10), None),
('control: fast dynamics', (0.9, 0.3, 300, 3, 0.02, 100), [200.0, 14, 197.4596]),
('regression: near threshold', (0.21, 0.2, 10000, 100, 0.001, 60), [476.1905, 60, 155.2383])],
[('control: gonorrhoea-like endemic', (0.3, 0.1, 1000, 10, 0.01, 200), [666.6667, 42, 657.0888]),
('control: subcritical dies out', (0.1, 0.2, 500, 50, 0.01, 200), [0.0, 21, 4.9755]),
('control: start above equilibrium', (0.4, 0.2, 1000, 900, 0.005, 100), [500.0, 17, 504.3274]),
('control: already at equilibrium', (0.4, 0.2, 1000, 500, 0.01, 50), [500.0, 0, 500.0]),
('regression: tight tolerance capped', (0.25, 0.2, 2000, 1, 0.0001, 30), [400.0, 30, 4.288]),
('regression: zero day cap', (0.3, 0.1, 100, 1, 0.01, 0), [66.6667, 0, 1.0]),
('control: invalid gamma', (0.3, 0.0, 100, 1, 0.01, 10), None)],
[('control: gonorrhoea-like endemic', (0.3, 0.1, 1000, 10, 0.01, 200), [666.6667, 42, 657.0888]),
('control: already at equilibrium', (0.4, 0.2, 1000, 500, 0.01, 50), [500.0, 0, 500.0]),
('regression: tight tolerance capped', (0.25, 0.2, 2000, 1, 0.0001, 30), [400.0, 30, 4.288]),
('regression: zero day cap', (0.3, 0.1, 100, 1, 0.01, 0), [66.6667, 0, 1.0]),
('control: invalid gamma', (0.3, 0.0, 100, 1, 0.01, 10), None),
('control: fast dynamics', (0.9, 0.3, 300, 3, 0.02, 100), [200.0, 14, 197.4596]),
('regression: near threshold', (0.21, 0.2, 10000, 100, 0.001, 60), [476.1905, 60, 155.2383])]]
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 fixture | Actual | Expected | Outcome |
|---|---|---|---|
| control: gonorrhoea-like endemic | [666.6667, 42, 657.0888] | [666.6667, 42, 657.0888] | Passed |
| control: subcritical dies out | [0.0, 21, 4.9755] | [0.0, 21, 4.9755] | Passed |
| control: start above equilibrium | [500.0, 17, 504.3274] | [500.0, 17, 504.3274] | Passed |
| control: already at equilibrium | [500.0, 0, 500.0] | [500.0, 0, 500.0] | Passed |
| regression: tight tolerance capped | [400.0, 30, 4.288] | [400.0, 30, 4.288] | Passed |
| regression: zero day cap | [66.6667, 0, 1.0] | [66.6667, 0, 1.0] | Passed |
| control: invalid gamma | None | None | Passed |
SHA-256 / 5ddfe75fecaa97576aa3fb2a8b1b72c66e9a50c7d0557c0b3c8437d64a656cbf
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:30.001286+00:00.
Case digest / 1ad50235df716102489d6a537069351adfc5bc0541d49fc1c1a8bb23410e4eab