Fill all with catering always fetched and filled today, so picking 24.10
on 23.10 reported "No catering delivery today." FillAllFlow.tap now takes
the picked day: fetch, slot schedule, occupancy and dedup all resolve
against it, and logDishes stamps each dish at its slot time on that day.
- A plan only confirms onto the day it was proposed for; changing the
date (or back to today) disarms it.
- A later-day fill leaves today's delivery queue and prefill alone and
returns the form to today, as a manual "Log for later" does.
- Only today's fetch records the single-day "already fetched" marker;
recording a later date would skip that day's automatic fetch.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VwYgigocPkPWa73QZRtU38
due_slots asks sickdays.stands_down(LOCKER_DIET, day) instead of
is_sick_day, so a sick day that keeps diet is a normal day for the gate.
Bump sickdays pins to v0.2.0.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PAhbNszs5JKdtnD4uBi3xp
due_slots() returns nothing on a sick day, like a free day: no lock, no debt;
logging still works. Unreadable pool reads as not sick (fail closed). Pins
sickdays-v0.1.0 and freedays-v0.4.0 (pyproject, requirements, pylint hook env).
Phone gap documented in docs/DOCS-sick-days.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xfj1sxKH9VBPqpcAni8Jry
The dropdown menu opens centred on the current value, so a "Custom…" item
at either end of ~95 entries was always a long scroll away. Each meal-time
field now has a clock IconButton ("Type or pick an exact time") opening the
same 24h showTimePicker with the same clamping. The off-grid current value
is still offered as an item.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015npsYVB2PdtWkG7MPAi4tn
At the end of the list it sat ~95 grid items down; now it is the first
item, above 00:00. Test pins the order.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015npsYVB2PdtWkG7MPAi4tn
Pins that fm/lm survive both the sync wire and a disk reload, and that a
quarter-hour pick in SettingsScreen goes through the real _applySchedule.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015npsYVB2PdtWkG7MPAi4tn
- FoodEntry.slot -> slotMinute: read via entrySlotMinute, written via
slotFields (whole-hour stays byte-identical, else slot_min), kept by
copyWithDeleted and the edit screen, so the phone never republishes a
stripped copy of a PC entry. Out-of-range peer values echo, never throw.
- Satisfaction is nearest-slot snapping (satisfiedSlots) everywhere:
loggedSlotsToday, due check, kuchnia occupancy, future-day logged set
(that day's schedule), slot selector. Schedule edits no longer un-log.
- Future pre-log builds DateTime from slot ~/ 60, slot % 60.
- Schedule history + sync go through scheduleToWire/scheduleFromWire.
- Notifications: ids are slot minutes; syncToSlots cancels whatever the
platform reports active (getActiveNotifications, reminder channel) that
is not due, covering legacy hour ids; full 0..1439 sweep only if the
lookup throws.
- Settings: 15-minute dropdowns + "Custom..." (24h showTimePicker), off-grid
values always selectable, counts capped by grid capacity; editor moved
to widgets/meal_schedule_editor.dart + meal_time_dropdown.dart.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015npsYVB2PdtWkG7MPAi4tn
Meal-slot checkpoints move from whole hours to minute-of-day ints
(0..1439) in the pure model and slot arithmetic of both languages:
MealSchedule(first_minute, last_minute, count) / (firstMinute:,
lastMinute:, count:), interior slots snapped to the 15-minute grid,
endpoints exact, integer-only. New: nearest_slot, satisfied_slots,
slot_fields / entry_slot_minute (additive "slot_min" wire field) and
schedule_to_wire / schedule_from_wire ("fm"/"lm" only when off the hour,
so whole-hour data stays byte-identical), parse_hhmm.
tests/fixtures/meal_schedule_vectors.json (scripts/
build_meal_schedule_fixture.py) is read by both suites; kuchnia_day.json
slot values regenerated as minutes.
Consumers (CLI, gate, storage, sync, app screens, kuchnia, notifications)
are intentionally broken until phase 2. patch-targets skipped: it fails
only because diet_guard._gatelock no longer imports.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015npsYVB2PdtWkG7MPAi4tn
gatelock 0.9.0 adds gatelock.morning_session (the shared reader of
wake-alarm's morning carrot, now used by screen-locker, leetcode-guard and
book-guard); nothing here changes behaviour. The tag moved the freshness
gate, so the pin moves with it, together with today's lint-tool releases.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FBbkN4ZB4aUPJPzR2prRan
The first -n auto Tests run segfaulted in Tk's focus_force(): keyboard
focus is global to an X display, and four workers were sharing the one
xvfb-run display, stealing each other's focus. Stressed locally (layout +
keyboard tests x40, -n 8): 5 of 2760 failed on a shared display (focus-ring
assertions), 0 of 4600 with pytest-xvfb's per-process display -- and faster.
The geometry xvfb-run used moves into pyproject; the workflow keeps the
Xvfb install guard and drops xvfb-run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0188kZdx3bb56QM8JFUnbHuM
The dependency-freshness workflow (--strict) went red on 9.7.1 -> 9.8.0.
todo, punchme, signal-bot and dufs-cloud already build their release APKs
on 9.8.0 with the same AGP 9.3.2, so only the wrapper URL moves.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0188kZdx3bb56QM8JFUnbHuM
Both released upstream since the last bump; the dependency-freshness gate
(pre-commit hook and the --strict CI workflow) reports them behind.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0188kZdx3bb56QM8JFUnbHuM
pre-commit took ~119 s as one job (24 s of pip, then every hook env and
every hook in series); Tests took ~56 s (26 s of pip, 7 s of apt-get for an
xvfb the image already ships, 17 s of -v pytest). Same hooks, same flags,
same 100% bar -- just parallel runners, cached uv wheels, xdist workers.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0188kZdx3bb56QM8JFUnbHuM
LockConfig's colours moved into a nested LockPalette record; every
_COLORS.<colour> read follows. Nothing about the gate's behaviour changed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HHCbkJWXHjtTUaqvnHRAqA
Also bumps Flutter 3.47.3, flutter_secure_storage 11.1.0, idb_shim 2.9.9,
mcp 2.2.0 and ruff 0.16.7 so the freshness gate lets this through.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AwtowrowDXx6ccmWVPkCaF
v0.2.0 drops freedays's gatelock dependency (importing gatelock pulled in
tkinter, so the headless pool needed a GUI toolkit) and adds the sync
timer that makes a day marked on the phone actually reach this machine.
Mechanical, but not optional: the freshness gate compares the pinned tag
against the newest release, so leaving v0.1.0 here would turn this repo
red on its next commit.
Suite re-run against v0.2.0 before pinning it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Split out from the free-day change only by sequence -- diet-guard's
pre-push CI mirror runs the freshness gate over --all-files, so these
were already blocking a push before that work started.
permission_handler 13.0.1 -> 13.0.2 and workmanager 0.10.9 -> 0.10.10
are patch bumps. very_good_analysis ^10.3.0 -> ^11.0.0 is the major one,
and it newly flags 8 async_return_with_no_await sites across the desktop
wrapper and the sync/Firebase services.
Each is now `return await`, not a suppression. The rule is right in every
one of these cases: without the await the future escapes the enclosing
async function, so a rejection surfaces at the caller with a stack trace
that no longer points at the code that made the call.
background_check_service.dart:33 is the clearest example -- its own
comment says the push "is retried with backoff rather than silently
dropped", which is only true if the failure happens inside the function.
Nothing in CI or pre-commit runs `flutter analyze`, so this would not
have failed anything. Leaving a newly-red analyzer for the next person to
find is how a repo stops being analyzable at all.
flutter analyze clean, 706 Flutter tests pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Third app onto freedays (~/utils/freedays), the shared pool of
pre-declared days when every gate app stands down. due_slots() returns
nothing on a free day, so no slot is ever due, the lock never opens and
nothing is said about the missing meals.
Read from one local file, never the network, so this cannot hang the
systemd-fired gate -- and an unreadable pool reads as "not free", which
means the normal rules apply rather than the gate quietly switching
itself off. Tested explicitly: fail closed, not open.
The conftest redirect is load-bearing. The pool lives under
~/.local/share, outside every diet_guard path the suite already isolates,
so without it a real free day on this machine would fail every "the gate
is due" test here for a reason that looks nothing like the cause.
gatelock moves v0.7.2 -> v0.7.3, and the pylint hook's own pins (which
had drifted further, to gatelock v0.7.1 and crdt-sync v0.6.0) come with
it. Not cosmetic: pip refuses two different direct URLs for one
distribution, so any stale pin alongside freedays -- which requires
v0.7.3 -- is an unresolvable environment rather than a warning.
requirements.txt also picks up pylint 4.0.8, pytest-randomly 5.0.0 and
ruff 0.16.6, which the freshness gate flagged once this file was touched.
1043 tests pass at 100% coverage across the pytest-randomly major bump.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The freshness gate was already red on this before today's Python work touched
the repo -- it only surfaced now because the CI mirror runs the gate over the
whole tree, while the commit hook had no reason to look at requirements.txt.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SfnJmxxsZ534AKk16rC2Gr
`requires-python` and the CI pin already said 3.14, but ruff, mypy and pylint
were still grading against 3.10 -- three tools judging an interpreter nothing
runs any more, and ruff withholding the pyupgrade fixes that only become safe
at the newer target. `pin_ci_python.py` rewrites exactly these three knobs.
The fixes ruff then had to make are what the stale target was hiding: 18 files
on `datetime.timezone.utc` instead of `datetime.UTC` (UP017), plus ruff's
stable formatter applying PEP 758 -- `except (A, B):` becomes `except A, B:`.
That second one makes the source 3.14-only at the syntax level, which is
exactly what `requires-python = ">=3.14"` already promised; kuhy chose it
deliberately over holding ruff a release back (2026-08-29).
ruff, ruff-format, mypy --strict and pylint all clean at the new target.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SfnJmxxsZ534AKk16rC2Gr