mirror of
https://github.com/kuhyx/diet-guard.git
synced 2026-11-10 19:07:15 +01:00
Every Python consumer now speaks slot minutes:
- satisfaction is nearest-slot snapping (_slot_wire.satisfied_by_entries)
at every "is this slot logged?" site: gate, CLI status, MCP, catering
occupancy and dedup. Nothing on disk is rewritten; 07:00/10:00 entries
keep covering 07:15/10:15 after a schedule move.
- log_meal writes slot_fields(minute) before signing (slot + slot_min).
- schedule store and sync encode via schedule_to_wire/from_wire; a
whole-hour schedule stays byte-identical (f/l/n only).
- CLI ate --hour takes HH or HH:MM; MCP log_meal takes "HH:MM" or a
legacy int hour, validated against today's slots; get_slots returns
{minute, label}.
- gate History tab: first/last are HH:MM ttk.Comboboxes (quarter-hour
list, typed times, Up/Down step without posting the popdown), locked
as disabled; validation mirrors normalized().
- gate timer fires every 15 min; docs rewritten for minutes.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015npsYVB2PdtWkG7MPAi4tn
24 lines
1.1 KiB
SYSTEMD
24 lines
1.1 KiB
SYSTEMD
[Unit]
|
|
Description=Periodically run the Diet Guard gate check
|
|
|
|
[Timer]
|
|
# Check on a WALL-CLOCK schedule (every 15 min: :00, :15, :30, :45).
|
|
# The meal slots and the enforcement window are enforced inside gate_is_due(),
|
|
# so the timer only needs to fire often enough to notice a slot opening. Slots
|
|
# can sit on any quarter hour (interior slots round to the 15-minute grid, and
|
|
# a 07:15 first meal is common), so a 30-min tick would let a slot go
|
|
# unenforced for up to half an hour; 15 min lands on every grid slot exactly.
|
|
# A first/last meal typed off the grid (07:23) is caught by the next tick.
|
|
#
|
|
# Why OnCalendar and not OnBootSec/OnUnitActiveSec: the gate is a *blocking*
|
|
# oneshot -- it stays up until a meal is logged -- and a monotonic schedule
|
|
# computed no next elapse once the service had run (and none at all across a
|
|
# reboot), leaving the timer dormant (NextElapse=infinity). OnCalendar re-arms
|
|
# every period regardless of how long the gate stayed open, and Persistent
|
|
# catches a run missed while the machine was suspended.
|
|
OnCalendar=*-*-* *:00/15:00
|
|
Persistent=true
|
|
|
|
[Install]
|
|
WantedBy=timers.target
|