FAILURE MAP
← Case archive

FA-64966 / Epidemic compartment models / Open access

SIRS waning-immunity simulation: waning source · case 01

People recovering today already lose immunity in the same step.

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

ROOT CAUSE

The waning flow includes the same-day recoveries rather than start-of-day R.

THE FAILURE

The waning flow includes the same-day recoveries rather than start-of-day R.

Unsuccessful approach: Frequency-scaling the waning flow by S/pop has no basis in a per-capita loss rate.

Case contract

Daily forward-Euler SIRS; waning flow is R/immunity_days back to S (immunity_days 0 means permanent immunity); cumulative incidence sums every S->I flow including reinfections; return [S, I, R, cumulative incidence] rounded to 3.

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, immunity_days, pop, i0, days):
    s, i, r = float(pop - i0), float(i0), 0.0
    cumulative = 0.0
    for _ in range(days):
        inf = beta * s * i / pop
        rec = gamma * i
        wane = (r + rec) / immunity_days if immunity_days > 0 else 0.0
        s += wane - inf
        i += inf - rec
        r += rec - wane
        cumulative += inf
    return [round(s, 3), round(i, 3), round(r, 3), round(cumulative, 3)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: seasonal coronavirus', (0.4, 0.2, 30, 1000, 5, 80), [543.377, 58.225, 398.398, 1339.789]),
  ('control: permanent immunity sentinel', (0.5, 0.2, 0, 500, 5, 40), [48.675, 7.802, 443.523, 446.325]),
  ('regression: short immunity endemic', (0.6, 0.25, 10, 800, 8, 100), [333.272, 133.331, 333.396, 3385.33]),
  ('control: boundary zero days', (0.4, 0.2, 30, 100, 5, 0), [95.0, 5.0, 0.0, 0.0]),
  ('regression: no transmission waning only', (0.0, 0.3, 5, 100, 50, 20), [98.35, 0.04, 1.61, 0.0]),
  ('regression: long immunity single wave',
   (0.5, 0.1, 365, 2000, 10, 120),
   [376.102, 3.345, 1620.554, 2084.424]),
  ('regression: one day immunity', (0.5, 0.3, 1, 300, 3, 30), [188.175, 86.35, 25.475, 420.744])],
 [('regression: seasonal coronavirus', (0.4, 0.2, 30, 1000, 5, 80), [543.377, 58.225, 398.398, 1339.789]),
  ('control: permanent immunity sentinel', (0.5, 0.2, 0, 500, 5, 40), [48.675, 7.802, 443.523, 446.325]),
  ('control: boundary zero days', (0.4, 0.2, 30, 100, 5, 0), [95.0, 5.0, 0.0, 0.0]),
  ('regression: no transmission waning only', (0.0, 0.3, 5, 100, 50, 20), [98.35, 0.04, 1.61, 0.0]),
  ('regression: long immunity single wave',
   (0.5, 0.1, 365, 2000, 10, 120),
   [376.102, 3.345, 1620.554, 2084.424]),
  ('regression: one day immunity', (0.5, 0.3, 1, 300, 3, 30), [188.175, 86.35, 25.475, 420.744]),
  ('regression: two week run', (0.9, 0.3, 20, 400, 4, 14), [58.25, 94.786, 246.964, 386.248])],
 [('regression: seasonal coronavirus', (0.4, 0.2, 30, 1000, 5, 80), [543.377, 58.225, 398.398, 1339.789]),
  ('control: permanent immunity sentinel', (0.5, 0.2, 0, 500, 5, 40), [48.675, 7.802, 443.523, 446.325]),
  ('regression: short immunity endemic', (0.6, 0.25, 10, 800, 8, 100), [333.272, 133.331, 333.396, 3385.33]),
  ('control: boundary zero days', (0.4, 0.2, 30, 100, 5, 0), [95.0, 5.0, 0.0, 0.0]),
  ('regression: no transmission waning only', (0.0, 0.3, 5, 100, 50, 20), [98.35, 0.04, 1.61, 0.0]),
  ('regression: one day immunity', (0.5, 0.3, 1, 300, 3, 30), [188.175, 86.35, 25.475, 420.744]),
  ('regression: two week run', (0.9, 0.3, 20, 400, 4, 14), [58.25, 94.786, 246.964, 386.248])],
 [('control: permanent immunity sentinel', (0.5, 0.2, 0, 500, 5, 40), [48.675, 7.802, 443.523, 446.325]),
  ('regression: short immunity endemic', (0.6, 0.25, 10, 800, 8, 100), [333.272, 133.331, 333.396, 3385.33]),
  ('control: boundary zero days', (0.4, 0.2, 30, 100, 5, 0), [95.0, 5.0, 0.0, 0.0]),
  ('regression: no transmission waning only', (0.0, 0.3, 5, 100, 50, 20), [98.35, 0.04, 1.61, 0.0]),
  ('regression: long immunity single wave',
   (0.5, 0.1, 365, 2000, 10, 120),
   [376.102, 3.345, 1620.554, 2084.424]),
  ('regression: one day immunity', (0.5, 0.3, 1, 300, 3, 30), [188.175, 86.35, 25.475, 420.744]),
  ('regression: two week run', (0.9, 0.3, 20, 400, 4, 14), [58.25, 94.786, 246.964, 386.248])],
 [('regression: seasonal coronavirus', (0.4, 0.2, 30, 1000, 5, 80), [543.377, 58.225, 398.398, 1339.789]),
  ('control: permanent immunity sentinel', (0.5, 0.2, 0, 500, 5, 40), [48.675, 7.802, 443.523, 446.325]),
  ('control: boundary zero days', (0.4, 0.2, 30, 100, 5, 0), [95.0, 5.0, 0.0, 0.0]),
  ('regression: no transmission waning only', (0.0, 0.3, 5, 100, 50, 20), [98.35, 0.04, 1.61, 0.0]),
  ('regression: long immunity single wave',
   (0.5, 0.1, 365, 2000, 10, 120),
   [376.102, 3.345, 1620.554, 2084.424]),
  ('regression: one day immunity', (0.5, 0.3, 1, 300, 3, 30), [188.175, 86.35, 25.475, 420.744]),
  ('regression: two week run', (0.9, 0.3, 20, 400, 4, 14), [58.25, 94.786, 246.964, 386.248])]]
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: seasonal coronavirus[541.47, 60.145, 398.384, 1377.12][543.377, 58.225, 398.398, 1339.789]Failed
control: permanent immunity sentinel[48.675, 7.802, 443.523, 446.325][48.675, 7.802, 443.523, 446.325]Passed
regression: short immunity endemic[333.288, 143.595, 323.117, 3630.408][333.272, 133.331, 333.396, 3385.33]Failed
control: boundary zero days[95.0, 5.0, 0.0, 0.0][95.0, 5.0, 0.0, 0.0]Passed
regression: no transmission waning only[98.672, 0.04, 1.288, 0.0][98.35, 0.04, 1.61, 0.0]Failed
regression: long immunity single wave[376.367, 3.401, 1620.232, 2089.589][376.102, 3.345, 1620.554, 2084.424]Failed
regression: one day immunity[191.879, 108.121, 0.0, 491.595][188.175, 86.35, 25.475, 420.744]Failed

SHA-256 / c365fbb29f4b39d09b5db285b8f4480950181595518c0b04cefc35b6d1b317e7

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, immunity_days, pop, i0, days):
    s, i, r = float(pop - i0), float(i0), 0.0
    cumulative = 0.0
    for _ in range(days):
        inf = beta * s * i / pop
        rec = gamma * i
        wane = r * s / pop / immunity_days if immunity_days > 0 else 0.0
        s += wane - inf
        i += inf - rec
        r += rec - wane
        cumulative += inf
    return [round(s, 3), round(i, 3), round(r, 3), round(cumulative, 3)]
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: seasonal coronavirus', (0.4, 0.2, 30, 1000, 5, 80), [543.377, 58.225, 398.398, 1339.789]),
  ('control: permanent immunity sentinel', (0.5, 0.2, 0, 500, 5, 40), [48.675, 7.802, 443.523, 446.325]),
  ('regression: short immunity endemic', (0.6, 0.25, 10, 800, 8, 100), [333.272, 133.331, 333.396, 3385.33]),
  ('control: boundary zero days', (0.4, 0.2, 30, 100, 5, 0), [95.0, 5.0, 0.0, 0.0]),
  ('regression: no transmission waning only', (0.0, 0.3, 5, 100, 50, 20), [98.35, 0.04, 1.61, 0.0]),
  ('regression: long immunity single wave',
   (0.5, 0.1, 365, 2000, 10, 120),
   [376.102, 3.345, 1620.554, 2084.424]),
  ('regression: one day immunity', (0.5, 0.3, 1, 300, 3, 30), [188.175, 86.35, 25.475, 420.744])],
 [('regression: seasonal coronavirus', (0.4, 0.2, 30, 1000, 5, 80), [543.377, 58.225, 398.398, 1339.789]),
  ('control: permanent immunity sentinel', (0.5, 0.2, 0, 500, 5, 40), [48.675, 7.802, 443.523, 446.325]),
  ('control: boundary zero days', (0.4, 0.2, 30, 100, 5, 0), [95.0, 5.0, 0.0, 0.0]),
  ('regression: no transmission waning only', (0.0, 0.3, 5, 100, 50, 20), [98.35, 0.04, 1.61, 0.0]),
  ('regression: long immunity single wave',
   (0.5, 0.1, 365, 2000, 10, 120),
   [376.102, 3.345, 1620.554, 2084.424]),
  ('regression: one day immunity', (0.5, 0.3, 1, 300, 3, 30), [188.175, 86.35, 25.475, 420.744]),
  ('regression: two week run', (0.9, 0.3, 20, 400, 4, 14), [58.25, 94.786, 246.964, 386.248])],
 [('regression: seasonal coronavirus', (0.4, 0.2, 30, 1000, 5, 80), [543.377, 58.225, 398.398, 1339.789]),
  ('control: permanent immunity sentinel', (0.5, 0.2, 0, 500, 5, 40), [48.675, 7.802, 443.523, 446.325]),
  ('regression: short immunity endemic', (0.6, 0.25, 10, 800, 8, 100), [333.272, 133.331, 333.396, 3385.33]),
  ('control: boundary zero days', (0.4, 0.2, 30, 100, 5, 0), [95.0, 5.0, 0.0, 0.0]),
  ('regression: no transmission waning only', (0.0, 0.3, 5, 100, 50, 20), [98.35, 0.04, 1.61, 0.0]),
  ('regression: one day immunity', (0.5, 0.3, 1, 300, 3, 30), [188.175, 86.35, 25.475, 420.744]),
  ('regression: two week run', (0.9, 0.3, 20, 400, 4, 14), [58.25, 94.786, 246.964, 386.248])],
 [('control: permanent immunity sentinel', (0.5, 0.2, 0, 500, 5, 40), [48.675, 7.802, 443.523, 446.325]),
  ('regression: short immunity endemic', (0.6, 0.25, 10, 800, 8, 100), [333.272, 133.331, 333.396, 3385.33]),
  ('control: boundary zero days', (0.4, 0.2, 30, 100, 5, 0), [95.0, 5.0, 0.0, 0.0]),
  ('regression: no transmission waning only', (0.0, 0.3, 5, 100, 50, 20), [98.35, 0.04, 1.61, 0.0]),
  ('regression: long immunity single wave',
   (0.5, 0.1, 365, 2000, 10, 120),
   [376.102, 3.345, 1620.554, 2084.424]),
  ('regression: one day immunity', (0.5, 0.3, 1, 300, 3, 30), [188.175, 86.35, 25.475, 420.744]),
  ('regression: two week run', (0.9, 0.3, 20, 400, 4, 14), [58.25, 94.786, 246.964, 386.248])],
 [('regression: seasonal coronavirus', (0.4, 0.2, 30, 1000, 5, 80), [543.377, 58.225, 398.398, 1339.789]),
  ('control: permanent immunity sentinel', (0.5, 0.2, 0, 500, 5, 40), [48.675, 7.802, 443.523, 446.325]),
  ('control: boundary zero days', (0.4, 0.2, 30, 100, 5, 0), [95.0, 5.0, 0.0, 0.0]),
  ('regression: no transmission waning only', (0.0, 0.3, 5, 100, 50, 20), [98.35, 0.04, 1.61, 0.0]),
  ('regression: long immunity single wave',
   (0.5, 0.1, 365, 2000, 10, 120),
   [376.102, 3.345, 1620.554, 2084.424]),
  ('regression: one day immunity', (0.5, 0.3, 1, 300, 3, 30), [188.175, 86.35, 25.475, 420.744]),
  ('regression: two week run', (0.9, 0.3, 20, 400, 4, 14), [58.25, 94.786, 246.964, 386.248])]]
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: seasonal coronavirus[442.81, 5.347, 551.843, 956.358][543.377, 58.225, 398.398, 1339.789]Failed
control: permanent immunity sentinel[48.675, 7.802, 443.523, 446.325][48.675, 7.802, 443.523, 446.325]Passed
regression: short immunity endemic[346.394, 37.703, 415.903, 1791.824][333.272, 133.331, 333.396, 3385.33]Failed
control: boundary zero days[95.0, 5.0, 0.0, 0.0][95.0, 5.0, 0.0, 0.0]Passed
regression: no transmission waning only[96.842, 0.04, 3.118, 0.0][98.35, 0.04, 1.61, 0.0]Failed
regression: long immunity single wave[11.123, 0.047, 1988.83, 1986.335][376.102, 3.345, 1620.554, 2084.424]Failed
regression: one day immunity[183.354, 79.113, 37.533, 403.097][188.175, 86.35, 25.475, 420.744]Failed

SHA-256 / a46da19fb18b106162a17a8d03869a51e1c221fb45b2237152474052758a6ab7

HELD IN THE MEMBER ARCHIVE

The verified repair and its recorded checks are member-only.

This mechanism has 7 recorded checks per implementation. The open-access tier publishes the failure and the unsuccessful fix; the repaired source that passes every check, and the observations that prove it, are available to members.

Every case sharing this mechanism uses the same contract and the same repair, so this one record is held back for all of them.

Member access is invitation-based. Sign in with your invited account to inspect the repair.

Sign in to the archive ↗

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

Case digest / 1def2098c907dd615f55ccc5a5de232ea0d34319c8ecd72a50e59d750f65a482