FAILURE MAP
← Case archive

FA-12311 / Battery state accounting / Open access

Cycle wear is inferred from net inventory change · case 01

Opposite direction transfers cancel before discharge throughput is counted.

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

ROOT CAUSE

Opposite direction transfers cancel before discharge throughput is counted.

THE FAILURE

Opposite direction transfers cancel before discharge throughput is counted.

Unsuccessful approach: Counting both directions double counts the stated discharge-only wear metric.

Case contract

Return discharge throughput units for signed charge deltas; positive means charging, negative discharging. This is the numerator of a discharge-only equivalent-cycle metric.

Why this case matters

An explicit synthetic battery bookkeeping model isolates this state-accounting error; it is not an engineering prediction or safety procedure.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(deltas):
    return max(0,-sum(deltas))
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('round trip', solve([10*N,-10*N]), 10*N)
check('charge only', solve([3*N,2*N]), 0)
check('discharge only', solve([-3*N,-2*N]), 5*N)
check('empty', solve([]), 0)
check('mixed', solve([-3*N,9*N,-4*N]), 7*N)
check('zeros', solve([0,-N,0,N]), N)
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
round trip010Failed
charge only00Passed
discharge only55Passed
empty00Passed
mixed07Failed
zeros01Failed

SHA-256 / 52664811e600982dacff2cdc68ebeebf767440b3266dd85b3b224b537e425f8e

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(deltas):
    return sum(abs(x) for x in deltas)
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
check('round trip', solve([10*N,-10*N]), 10*N)
check('charge only', solve([3*N,2*N]), 0)
check('discharge only', solve([-3*N,-2*N]), 5*N)
check('empty', solve([]), 0)
check('mixed', solve([-3*N,9*N,-4*N]), 7*N)
check('zeros', solve([0,-N,0,N]), N)
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
round trip2010Failed
charge only50Failed
discharge only55Passed
empty00Passed
mixed167Failed
zeros21Failed

SHA-256 / 6836e80a16f2a8a48a53a824e8bd2c579bbd0b1821207c86408f7c0754d6cd6f

HELD IN THE MEMBER ARCHIVE

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

This mechanism has 6 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

Integer toy accounting with declared loss rules; no electrochemistry, hardware behavior, or safety claims. 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:38:55.638015+00:00.

Case digest / b5f65d90ac175864c40279d6d7cdeb4c49528b0d806d269b0c3dfebc82500438