diet-guard/app/test
Krzysztof kuhy Rudnicki 83c3030b55 Derive meal slots from an eating window and a meal count
First step of the configurable meal schedule: the pure arithmetic, in both
languages, with nothing wired to it yet. MealSchedule(8, 20, 5) gives
08, 11, 14, 17, 20; the default MealSchedule(8, 20, 4) reproduces the hours
that are currently hardcoded, so nothing changes behaviour until a user picks
something else.

Two properties are load-bearing and both are tested rather than asserted in
prose:

Integer arithmetic only, no floats and no round(). Python's round() is
banker's (round(2.5) == 2) and Dart's is half-away-from-zero
(2.5.round() == 3), so a floating-point derivation would silently disagree
across devices -- and a slot one device offers but the other does not is a
checkpoint that can never be satisfied, i.e. a permanent lock. The shared
vector table plus an identical 6912-case sweep in both suites is what catches
that class of bug before it reaches a device.

Counts are clamped to the window width rather than rejected. A narrow window
(08-12 across 6 meals) would otherwise repeat an hour -- 8, 9, 10, 10, 11, 12
-- and slot hours are used as set members, map keys and notification ids, so a
repeat silently drops a checkpoint. Clamping also means the two languages
cannot disagree about which inputs are errors.

The enforcement cutoff is now derived as last + 2h (clamped to midnight)
rather than sharing the constant that also bounded the slot range. The clamp
matters: 23:00 + 2 = 25 would make `hour < cutoff` vacuously true and the
window would never close.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159b4E5hh512jYUeaJVNxfM
2026-08-16 14:21:12 +02:00
..
desktop Split the remaining seven Dart test files 2026-08-15 20:53:55 +02:00
models Derive meal slots from an eating window and a meal count 2026-08-16 14:21:12 +02:00
screens Pin meal pills to one row; drop the "Logged" restatement 2026-08-16 14:18:39 +02:00
services Split the last four Dart lib files; file-length gate now reports zero 2026-08-15 21:07:24 +02:00
widgets Pin meal pills to one row; drop the "Logged" restatement 2026-08-16 14:18:39 +02:00
fake_notifications.dart Add OAuth device flow, background notifications, and fix AGP9 release crash (Milestones 3–4) 2026-06-25 17:29:23 +02:00
fake_secure_storage.dart Add Flutter half of cross-device sync (Milestone 3) 2026-06-22 22:42:27 +02:00
firebase_backend_google_test.dart Split the last four Dart lib files; file-length gate now reports zero 2026-08-15 21:07:24 +02:00
google_platform_test.dart Add Google sign-in support for the Firebase sync account 2026-08-12 23:36:10 +02:00
google_sign_in_backend_test.dart Add Google sign-in support for the Firebase sync account 2026-08-12 23:36:10 +02:00
keyboard_operability_test.dart Stop two keyboard tests hanging, and make the CI mirror mirror CI 2026-08-04 21:50:15 +02:00
repo_invariants_test.dart Automate CLAUDE.md's structural rules, then cut it to 189 lines 2026-08-15 16:39:57 +02:00
widget_test.dart app: run the companion app's desktop target as a web build 2026-07-20 16:31:32 +02:00