diet-guard/app/lib/services
Krzysztof kuhy Rudnicki 24be05b9c3 feat: mirror the catering parser and slot spread in Dart, gated by one fixture
The phone is getting its own Kuchnia Wikinga importer so the feature works
with the PC switched off. That turns a risk `_kuchnia_spread.py` called
"theoretical" into a live one: two implementations must now agree exactly on
which dishes are dropped, which slot each lands on, and the JSON a banked
record encodes to. Disagreement means each device re-adds what the other
dropped, and since `add_manual_entry` restamps `t` unconditionally, the whole
curated bank republishes to every peer on every refresh. A slot mismatch is
worse -- a checkpoint one device offers and the other does not can never be
satisfied.

So the port lands with its gate rather than after it. One shared fixture,
`tests/fixtures/kuchnia_day.json`, is asserted by both `pytest` and
`flutter test`: same input, same expected dishes, drops, slots, bank keys and
records. Two suites written independently from the same prose is not a gate.

The fixture is five real dishes (a scrubbed 2026-08-22 capture) plus synthetic
meals that each pin one drop or fallback path -- a per-100 g mix-up, an absurd
portion, a stringly-typed number, a non-dict entry, a missing `nutrition`, a
missing `mealPriority`, and a twin-dish pair. Without those, "the same meals
are dropped" is a vacuous assertion against an all-happy-path capture. Both
halves were mutation-checked: flipping an expected slot, drop count or record
value fails each suite, and flipping `435.0` to `435` fails the byte-identity
test while the value comparison still passes, which is why both exist.

Three traps the port had to survive, each caught before it shipped:

- `_ENERGY_TOLERANCE` is **0.35**. The prose said "~1%", which describes how
  closely the captured day agreed, not the threshold; porting 0.01 would drop
  dishes the PC keeps. That paragraph now says so.
- `jsonEncode(435)` emits `435` where Python emits `435.0`, so every Dart
  macro is forced to `double` and a canonical-encoding test pins it.
- Dart's `List.sort` is unstable where Python's `sorted` is stable, so the
  Dart comparator carries the payload index as a final tiebreak.

The real dishes live in their own file rather than as a literal in the
generator: transcribing them by hand corrupted three of the five, and the
error was invisible until the generated fixture was diffed against the
capture.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QQpCiPaSbyRpwsLkH3dgsX
2026-08-23 08:00:54 +02:00
..
app_settings_service.dart Remove unused features; fix reminder false alarms; share all state 2026-07-26 16:39:52 +02:00
average_service.dart Step Dart dates by the calendar, not by 24 hours 2026-08-09 15:06:41 +02:00
background_check_service.dart app: run the companion app's desktop target as a web build 2026-07-20 16:31:32 +02:00
background_sync_service.dart Read the meal schedule from a forward-only history (Dart) 2026-08-16 14:41:37 +02:00
background_tasks_io.dart app: run the companion app's desktop target as a web build 2026-07-20 16:31:32 +02:00
background_tasks_web.dart app: run the companion app's desktop target as a web build 2026-07-20 16:31:32 +02:00
background_tasks.dart app: run the companion app's desktop target as a web build 2026-07-20 16:31:32 +02:00
budget_history_service.dart Remove unused features; fix reminder false alarms; share all state 2026-07-26 16:39:52 +02:00
budget_schedule.dart Remove unused features; fix reminder false alarms; share all state 2026-07-26 16:39:52 +02:00
day_status_service.dart Step Dart dates by the calendar, not by 24 hours 2026-08-09 15:06:41 +02:00
desktop_wrapper.dart Remove unused features; fix reminder false alarms; share all state 2026-07-26 16:39:52 +02:00
document_store_factory.dart app: run the companion app's desktop target as a web build 2026-07-20 16:31:32 +02:00
document_store_indexeddb.dart app: test the IndexedDB stores instead of shipping them unverified 2026-07-20 16:56:15 +02:00
document_store_io.dart app: run the companion app's desktop target as a web build 2026-07-20 16:31:32 +02:00
document_store_web.dart app: test the IndexedDB stores instead of shipping them unverified 2026-07-20 16:56:15 +02:00
document_store.dart app: run the companion app's desktop target as a web build 2026-07-20 16:31:32 +02:00
due_slot_check.dart Read the meal schedule from a forward-only history (Dart) 2026-08-16 14:41:37 +02:00
firebase_backend.dart Split the last four Dart lib files; file-length gate now reports zero 2026-08-15 21:07:24 +02:00
firebase_client.dart Split the last four Dart lib files; file-length gate now reports zero 2026-08-15 21:07:24 +02:00
foodbank_service_manual.dart Split the last four Dart lib files; file-length gate now reports zero 2026-08-15 21:07:24 +02:00
foodbank_service.dart Split the last four Dart lib files; file-length gate now reports zero 2026-08-15 21:07:24 +02:00
frame_stats.dart app: package the desktop app as the web build, and delete the Linux embedder 2026-07-20 16:32:24 +02:00
fuzzy.dart Add Flutter companion app skeleton with local meal logging 2026-06-22 18:22:42 +02:00
github_client_factory_io.dart app: use the shared github_device_auth package 2026-08-15 16:15:24 +02:00
github_client_factory_web.dart app: use the shared github_device_auth package 2026-08-15 16:15:24 +02:00
github_client_factory.dart app: run the companion app's desktop target as a web build 2026-07-20 16:31:32 +02:00
google_platform_io.dart Add Google sign-in support for the Firebase sync account 2026-08-12 23:36:10 +02:00
google_platform_web.dart Add Google sign-in support for the Firebase sync account 2026-08-12 23:36:10 +02:00
google_platform.dart Add Google sign-in support for the Firebase sync account 2026-08-12 23:36:10 +02:00
google_sign_in_backend.dart Add Google sign-in support for the Firebase sync account 2026-08-12 23:36:10 +02:00
kuchnia_parse.dart feat: mirror the catering parser and slot spread in Dart, gated by one fixture 2026-08-23 08:00:54 +02:00
kuchnia_spread.dart feat: mirror the catering parser and slot spread in Dart, gated by one fixture 2026-08-23 08:00:54 +02:00
log_storage_service.dart Remove unused features; fix reminder false alarms; share all state 2026-07-26 16:39:52 +02:00
meal_schedule_history.dart Read the meal schedule from a forward-only history (Dart) 2026-08-16 14:41:37 +02:00
meal_schedule_service.dart Read the meal schedule from a forward-only history (Dart) 2026-08-16 14:41:37 +02:00
notification_backend_factory.dart app: run the companion app's desktop target as a web build 2026-07-20 16:31:32 +02:00
notification_backend_io.dart app: run the companion app's desktop target as a web build 2026-07-20 16:31:32 +02:00
notification_backend_web.dart app: run the companion app's desktop target as a web build 2026-07-20 16:31:32 +02:00
notification_backend.dart app: run the companion app's desktop target as a web build 2026-07-20 16:31:32 +02:00
notification_service.dart Read the meal schedule from a forward-only history (Dart) 2026-08-16 14:41:37 +02:00
sync_device_id.dart Push under a persisted per-install uuid, not a fixed role id 2026-08-09 17:18:42 +02:00
sync_health.dart Make the phone publish on every tick, and fail closed on Firebase errors 2026-08-10 14:35:37 +02:00
sync_merge_banks.dart Split wrapper_server and sync_merge into siblings 2026-08-15 16:42:27 +02:00
sync_merge_budget.dart Sync the meal schedule as sched: fields on the budget record 2026-08-16 14:49:08 +02:00
sync_merge_schedule.dart Sync the meal schedule as sched: fields on the budget record 2026-08-16 14:49:08 +02:00
sync_merge.dart Split wrapper_server and sync_merge into siblings 2026-08-15 16:42:27 +02:00
sync_service.dart Sync the meal schedule as sched: fields on the budget record 2026-08-16 14:49:08 +02:00
sync_settings.dart app: run the companion app's desktop target as a web build 2026-07-20 16:31:32 +02:00
sync_state_factory_io.dart Sync meals and the food bank through Firebase, mirroring to GitHub 2026-08-05 08:35:21 +02:00
sync_state_factory_web.dart Sync meals and the food bank through Firebase, mirroring to GitHub 2026-08-05 08:35:21 +02:00
sync_state_factory.dart Sync meals and the food bank through Firebase, mirroring to GitHub 2026-08-05 08:35:21 +02:00
token_vault_factory.dart app: run the companion app's desktop target as a web build 2026-07-20 16:31:32 +02:00
token_vault_io.dart app: run the companion app's desktop target as a web build 2026-07-20 16:31:32 +02:00
token_vault_web.dart app: run the companion app's desktop target as a web build 2026-07-20 16:31:32 +02:00
token_vault.dart app: run the companion app's desktop target as a web build 2026-07-20 16:31:32 +02:00