FA-64106 / Medication dosing calculations / Open access
Gravity drip rate and infusion end time: whole drop rounding · case 01
A calculated 37.5 gtt/min is counted as 37.
ROOT CAUSE
Drops per minute are truncated instead of rounded half-up.
THE FAILURE
Drops per minute are truncated instead of rounded half-up.
Unsuccessful approach: Always rounding up miscounts rates like 33.3 gtt/min as 34.
Case contract
Input {volume_ml, duration_min, drop_factor (gtt/mL), start "HH:MM" 24-hour}. drops/min = volume*drop_factor/duration rounded half-up to a whole drop; mL/h = volume*60/duration rounded half-up to 0.1; end = start + duration on a 24-hour clock with day_offset = number of midnights crossed (ending exactly at 00:00 counts as the next day). Return {gtt_min, ml_h, end, day_offset}.
Why this case matters
Manual gravity infusions depend on drop-factor arithmetic and clock arithmetic across midnight, each with its own failure modes.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
gtt = Fraction(x['volume_ml'] * x['drop_factor'], x['duration_min'])
gtt_i = math.floor(gtt)
mlh = Fraction(x['volume_ml'] * 60, x['duration_min'])
mlh_t = math.floor(mlh * 10 + Fraction(1, 2))
h, m = map(int, x['start'].split(':'))
total = h * 60 + m + x['duration_min']
day = total // 1440
total = total % 1440
return {'gtt_min': gtt_i, 'ml_h': mlh_t / 10, 'end': '%02d:%02d' % (total // 60, total % 60), 'day_offset': day}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('macrodrip set afternoon start',
{'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:05'},
{'gtt_min': 31, 'ml_h': 125.0, 'end': '22:05', 'day_offset': 0}),
('drop rate rounds half up',
{'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
{'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
('fractional drop rate rounds down',
{'volume_ml': 103, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
{'gtt_min': 34, 'ml_h': 103.0, 'end': '10:30', 'day_offset': 0}),
('ends exactly at midnight',
{'volume_ml': 500, 'duration_min': 150, 'drop_factor': 20, 'start': '22:00'},
{'gtt_min': 67, 'ml_h': 200.0, 'end': '00:30', 'day_offset': 1}),
('multi-day infusion',
{'volume_ml': 2000, 'duration_min': 2940, 'drop_factor': 60, 'start': '13:15'},
{'gtt_min': 41, 'ml_h': 40.8, 'end': '14:15', 'day_offset': 2}),
('short microdrip before noon',
{'volume_ml': 50, 'duration_min': 31, 'drop_factor': 60, 'start': '10:45'},
{'gtt_min': 97, 'ml_h': 96.8, 'end': '11:16', 'day_offset': 0})],
[('macrodrip set afternoon start',
{'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:10'},
{'gtt_min': 42, 'ml_h': 125.0, 'end': '22:10', 'day_offset': 0}),
('drop rate rounds half up',
{'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
{'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
('fractional drop rate rounds down',
{'volume_ml': 106, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
{'gtt_min': 35, 'ml_h': 106.0, 'end': '10:30', 'day_offset': 0}),
('ends exactly at midnight',
{'volume_ml': 500, 'duration_min': 180, 'drop_factor': 20, 'start': '21:30'},
{'gtt_min': 56, 'ml_h': 166.7, 'end': '00:30', 'day_offset': 1}),
('multi-day infusion',
{'volume_ml': 2000, 'duration_min': 3000, 'drop_factor': 60, 'start': '13:15'},
{'gtt_min': 40, 'ml_h': 40.0, 'end': '15:15', 'day_offset': 2}),
('short microdrip before noon',
{'volume_ml': 50, 'duration_min': 32, 'drop_factor': 60, 'start': '10:45'},
{'gtt_min': 94, 'ml_h': 93.8, 'end': '11:17', 'day_offset': 0})],
[('macrodrip set afternoon start',
{'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 10, 'start': '14:15'},
{'gtt_min': 21, 'ml_h': 125.0, 'end': '22:15', 'day_offset': 0}),
('drop rate rounds half up',
{'volume_ml': 250, 'duration_min': 100, 'drop_factor': 10, 'start': '08:00'},
{'gtt_min': 25, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
('fractional drop rate rounds down',
{'volume_ml': 109, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
{'gtt_min': 36, 'ml_h': 109.0, 'end': '10:30', 'day_offset': 0}),
('ends exactly at midnight',
{'volume_ml': 500, 'duration_min': 210, 'drop_factor': 20, 'start': '21:00'},
{'gtt_min': 48, 'ml_h': 142.9, 'end': '00:30', 'day_offset': 1}),
('multi-day infusion',
{'volume_ml': 2000, 'duration_min': 3060, 'drop_factor': 60, 'start': '13:15'},
{'gtt_min': 39, 'ml_h': 39.2, 'end': '16:15', 'day_offset': 2}),
('short microdrip before noon',
{'volume_ml': 50, 'duration_min': 33, 'drop_factor': 60, 'start': '10:45'},
{'gtt_min': 91, 'ml_h': 90.9, 'end': '11:18', 'day_offset': 0})],
[('macrodrip set afternoon start',
{'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:20'},
{'gtt_min': 31, 'ml_h': 125.0, 'end': '22:20', 'day_offset': 0}),
('drop rate rounds half up',
{'volume_ml': 250, 'duration_min': 100, 'drop_factor': 20, 'start': '08:00'},
{'gtt_min': 50, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
('fractional drop rate rounds down',
{'volume_ml': 112, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
{'gtt_min': 37, 'ml_h': 112.0, 'end': '10:30', 'day_offset': 0}),
('ends exactly at midnight',
{'volume_ml': 500, 'duration_min': 240, 'drop_factor': 20, 'start': '20:30'},
{'gtt_min': 42, 'ml_h': 125.0, 'end': '00:30', 'day_offset': 1}),
('multi-day infusion',
{'volume_ml': 2000, 'duration_min': 3120, 'drop_factor': 60, 'start': '13:15'},
{'gtt_min': 38, 'ml_h': 38.5, 'end': '17:15', 'day_offset': 2}),
('short microdrip before noon',
{'volume_ml': 50, 'duration_min': 34, 'drop_factor': 60, 'start': '10:45'},
{'gtt_min': 88, 'ml_h': 88.2, 'end': '11:19', 'day_offset': 0})],
[('macrodrip set afternoon start',
{'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:25'},
{'gtt_min': 42, 'ml_h': 125.0, 'end': '22:25', 'day_offset': 0}),
('drop rate rounds half up',
{'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
{'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
('fractional drop rate rounds down',
{'volume_ml': 115, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
{'gtt_min': 38, 'ml_h': 115.0, 'end': '10:30', 'day_offset': 0}),
('ends exactly at midnight',
{'volume_ml': 500, 'duration_min': 270, 'drop_factor': 20, 'start': '20:00'},
{'gtt_min': 37, 'ml_h': 111.1, 'end': '00:30', 'day_offset': 1}),
('multi-day infusion',
{'volume_ml': 2000, 'duration_min': 3180, 'drop_factor': 60, 'start': '13:15'},
{'gtt_min': 38, 'ml_h': 37.7, 'end': '18:15', 'day_offset': 2}),
('short microdrip before noon',
{'volume_ml': 50, 'duration_min': 35, 'drop_factor': 60, 'start': '10:45'},
{'gtt_min': 86, 'ml_h': 85.7, 'end': '11:20', 'day_offset': 0})]]
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 |
|---|---|---|---|
| macrodrip set afternoon start | {'day_offset': 0, 'end': '22:05', 'gtt_min': 31, 'ml_h': 125.0} | {'day_offset': 0, 'end': '22:05', 'gtt_min': 31, 'ml_h': 125.0} | Passed |
| drop rate rounds half up | {'day_offset': 0, 'end': '09:40', 'gtt_min': 37, 'ml_h': 150.0} | {'day_offset': 0, 'end': '09:40', 'gtt_min': 38, 'ml_h': 150.0} | Failed |
| fractional drop rate rounds down | {'day_offset': 0, 'end': '10:30', 'gtt_min': 34, 'ml_h': 103.0} | {'day_offset': 0, 'end': '10:30', 'gtt_min': 34, 'ml_h': 103.0} | Passed |
| ends exactly at midnight | {'day_offset': 1, 'end': '00:30', 'gtt_min': 66, 'ml_h': 200.0} | {'day_offset': 1, 'end': '00:30', 'gtt_min': 67, 'ml_h': 200.0} | Failed |
| multi-day infusion | {'day_offset': 2, 'end': '14:15', 'gtt_min': 40, 'ml_h': 40.8} | {'day_offset': 2, 'end': '14:15', 'gtt_min': 41, 'ml_h': 40.8} | Failed |
| short microdrip before noon | {'day_offset': 0, 'end': '11:16', 'gtt_min': 96, 'ml_h': 96.8} | {'day_offset': 0, 'end': '11:16', 'gtt_min': 97, 'ml_h': 96.8} | Failed |
SHA-256 / 0886ee84cc816db4f5cdd260724ac8e0f92483013a5dd71d94cddfd05583c978
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
gtt = Fraction(x['volume_ml'] * x['drop_factor'], x['duration_min'])
gtt_i = math.ceil(gtt)
mlh = Fraction(x['volume_ml'] * 60, x['duration_min'])
mlh_t = math.floor(mlh * 10 + Fraction(1, 2))
h, m = map(int, x['start'].split(':'))
total = h * 60 + m + x['duration_min']
day = total // 1440
total = total % 1440
return {'gtt_min': gtt_i, 'ml_h': mlh_t / 10, 'end': '%02d:%02d' % (total // 60, total % 60), 'day_offset': day}
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('macrodrip set afternoon start',
{'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:05'},
{'gtt_min': 31, 'ml_h': 125.0, 'end': '22:05', 'day_offset': 0}),
('drop rate rounds half up',
{'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
{'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
('fractional drop rate rounds down',
{'volume_ml': 103, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
{'gtt_min': 34, 'ml_h': 103.0, 'end': '10:30', 'day_offset': 0}),
('ends exactly at midnight',
{'volume_ml': 500, 'duration_min': 150, 'drop_factor': 20, 'start': '22:00'},
{'gtt_min': 67, 'ml_h': 200.0, 'end': '00:30', 'day_offset': 1}),
('multi-day infusion',
{'volume_ml': 2000, 'duration_min': 2940, 'drop_factor': 60, 'start': '13:15'},
{'gtt_min': 41, 'ml_h': 40.8, 'end': '14:15', 'day_offset': 2}),
('short microdrip before noon',
{'volume_ml': 50, 'duration_min': 31, 'drop_factor': 60, 'start': '10:45'},
{'gtt_min': 97, 'ml_h': 96.8, 'end': '11:16', 'day_offset': 0})],
[('macrodrip set afternoon start',
{'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:10'},
{'gtt_min': 42, 'ml_h': 125.0, 'end': '22:10', 'day_offset': 0}),
('drop rate rounds half up',
{'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
{'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
('fractional drop rate rounds down',
{'volume_ml': 106, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
{'gtt_min': 35, 'ml_h': 106.0, 'end': '10:30', 'day_offset': 0}),
('ends exactly at midnight',
{'volume_ml': 500, 'duration_min': 180, 'drop_factor': 20, 'start': '21:30'},
{'gtt_min': 56, 'ml_h': 166.7, 'end': '00:30', 'day_offset': 1}),
('multi-day infusion',
{'volume_ml': 2000, 'duration_min': 3000, 'drop_factor': 60, 'start': '13:15'},
{'gtt_min': 40, 'ml_h': 40.0, 'end': '15:15', 'day_offset': 2}),
('short microdrip before noon',
{'volume_ml': 50, 'duration_min': 32, 'drop_factor': 60, 'start': '10:45'},
{'gtt_min': 94, 'ml_h': 93.8, 'end': '11:17', 'day_offset': 0})],
[('macrodrip set afternoon start',
{'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 10, 'start': '14:15'},
{'gtt_min': 21, 'ml_h': 125.0, 'end': '22:15', 'day_offset': 0}),
('drop rate rounds half up',
{'volume_ml': 250, 'duration_min': 100, 'drop_factor': 10, 'start': '08:00'},
{'gtt_min': 25, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
('fractional drop rate rounds down',
{'volume_ml': 109, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
{'gtt_min': 36, 'ml_h': 109.0, 'end': '10:30', 'day_offset': 0}),
('ends exactly at midnight',
{'volume_ml': 500, 'duration_min': 210, 'drop_factor': 20, 'start': '21:00'},
{'gtt_min': 48, 'ml_h': 142.9, 'end': '00:30', 'day_offset': 1}),
('multi-day infusion',
{'volume_ml': 2000, 'duration_min': 3060, 'drop_factor': 60, 'start': '13:15'},
{'gtt_min': 39, 'ml_h': 39.2, 'end': '16:15', 'day_offset': 2}),
('short microdrip before noon',
{'volume_ml': 50, 'duration_min': 33, 'drop_factor': 60, 'start': '10:45'},
{'gtt_min': 91, 'ml_h': 90.9, 'end': '11:18', 'day_offset': 0})],
[('macrodrip set afternoon start',
{'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:20'},
{'gtt_min': 31, 'ml_h': 125.0, 'end': '22:20', 'day_offset': 0}),
('drop rate rounds half up',
{'volume_ml': 250, 'duration_min': 100, 'drop_factor': 20, 'start': '08:00'},
{'gtt_min': 50, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
('fractional drop rate rounds down',
{'volume_ml': 112, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
{'gtt_min': 37, 'ml_h': 112.0, 'end': '10:30', 'day_offset': 0}),
('ends exactly at midnight',
{'volume_ml': 500, 'duration_min': 240, 'drop_factor': 20, 'start': '20:30'},
{'gtt_min': 42, 'ml_h': 125.0, 'end': '00:30', 'day_offset': 1}),
('multi-day infusion',
{'volume_ml': 2000, 'duration_min': 3120, 'drop_factor': 60, 'start': '13:15'},
{'gtt_min': 38, 'ml_h': 38.5, 'end': '17:15', 'day_offset': 2}),
('short microdrip before noon',
{'volume_ml': 50, 'duration_min': 34, 'drop_factor': 60, 'start': '10:45'},
{'gtt_min': 88, 'ml_h': 88.2, 'end': '11:19', 'day_offset': 0})],
[('macrodrip set afternoon start',
{'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:25'},
{'gtt_min': 42, 'ml_h': 125.0, 'end': '22:25', 'day_offset': 0}),
('drop rate rounds half up',
{'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
{'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
('fractional drop rate rounds down',
{'volume_ml': 115, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
{'gtt_min': 38, 'ml_h': 115.0, 'end': '10:30', 'day_offset': 0}),
('ends exactly at midnight',
{'volume_ml': 500, 'duration_min': 270, 'drop_factor': 20, 'start': '20:00'},
{'gtt_min': 37, 'ml_h': 111.1, 'end': '00:30', 'day_offset': 1}),
('multi-day infusion',
{'volume_ml': 2000, 'duration_min': 3180, 'drop_factor': 60, 'start': '13:15'},
{'gtt_min': 38, 'ml_h': 37.7, 'end': '18:15', 'day_offset': 2}),
('short microdrip before noon',
{'volume_ml': 50, 'duration_min': 35, 'drop_factor': 60, 'start': '10:45'},
{'gtt_min': 86, 'ml_h': 85.7, 'end': '11:20', 'day_offset': 0})]]
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 |
|---|---|---|---|
| macrodrip set afternoon start | {'day_offset': 0, 'end': '22:05', 'gtt_min': 32, 'ml_h': 125.0} | {'day_offset': 0, 'end': '22:05', 'gtt_min': 31, 'ml_h': 125.0} | Failed |
| drop rate rounds half up | {'day_offset': 0, 'end': '09:40', 'gtt_min': 38, 'ml_h': 150.0} | {'day_offset': 0, 'end': '09:40', 'gtt_min': 38, 'ml_h': 150.0} | Passed |
| fractional drop rate rounds down | {'day_offset': 0, 'end': '10:30', 'gtt_min': 35, 'ml_h': 103.0} | {'day_offset': 0, 'end': '10:30', 'gtt_min': 34, 'ml_h': 103.0} | Failed |
| ends exactly at midnight | {'day_offset': 1, 'end': '00:30', 'gtt_min': 67, 'ml_h': 200.0} | {'day_offset': 1, 'end': '00:30', 'gtt_min': 67, 'ml_h': 200.0} | Passed |
| multi-day infusion | {'day_offset': 2, 'end': '14:15', 'gtt_min': 41, 'ml_h': 40.8} | {'day_offset': 2, 'end': '14:15', 'gtt_min': 41, 'ml_h': 40.8} | Passed |
| short microdrip before noon | {'day_offset': 0, 'end': '11:16', 'gtt_min': 97, 'ml_h': 96.8} | {'day_offset': 0, 'end': '11:16', 'gtt_min': 97, 'ml_h': 96.8} | Passed |
SHA-256 / e0eeaca643b8b2ad32502950d7b1b7cd323513eaf644ea7ca73c1dc781167c58
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
A deterministic toy software model with explicitly stipulated thresholds and formulas; it is not clinical guidance, not a validated medical calculator, and makes no claim of conformance to any published protocol. Numbered variants vary patient and order inputs. 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:21.202713+00:00.
Case digest / d7571945ee6d9461b6fbf8c161eb9b335b5a9bce862591186884e0c8c6fa0509