Commit Graph

5 Commits

Author SHA1 Message Date
c310861855 slots: minute-of-day consumers (phase 2 of 3: Python side)
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
2026-10-10 19:53:39 +02:00
b77145010c Stop asking for meals on a shared free day
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>
2026-09-07 15:22:38 +02:00
42d15b6a91 Grade against 3.14 too, not just run on it
`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
2026-08-29 11:35:06 +02:00
843f5e0221 Extract diet_guard from testsAndMisc as a standalone repo
Rewrites python_pkg.diet_guard imports to diet_guard, vendors the
shared as_float coercion helper, drops the monorepo PYTHONPATH from
install.sh and the systemd unit (package is now pip-installed), and
scaffolds standalone lint/test config matching testsAndMisc's real
enforced bar (pylint --fail-under=10 with tests excluded and the
use-implicit-booleaness/consider-using-with disables, mypy's actual
disabled-error-code set, ruff ALL, bandit, 100% branch coverage).
2026-06-22 12:18:39 +02:00
400f89b469 feat(diet_guard): add meal-logging screen-lock gate with trigger fix
Add the diet_guard package: a screen-locking meal-logging gate that fires
on 4-hour slots (08/12/16/20) and records calories/macros, persisting an
autocompleting food bank.

- Trigger fix: the systemd timer fires at session start (Persistent=true)
  before lightdm has written ~/.Xauthority, so the gate crashed with a
  TclError instead of locking the screen. Add wait_for_display() /
  _display_is_ready() in _gatelock.py and wire it into _cli._cmd_gate so the
  gate retries on the next tick instead of crashing; add
  Environment=XAUTHORITY=%h/.Xauthority to the service as belt-and-suspenders.
- Food-bank hardening: a transiently corrupt food_bank.json was warned about
  on every keystroke and then silently overwritten (data loss). _read_bank
  now quarantines it via _quarantine_corrupt_bank() (warn-once + timestamped
  backup) before starting fresh.
- Multi-item meals: new _meal.py (MealItem, meal_total, MEAL_SOURCE),
  remember_meal() + _upsert() in _foodbank.py, and a "+ Add item" control in
  the gate that logs both the individual items and the composite meal.
- Bundle resolve_nutrition's manual macros into a ManualMacros dataclass to
  stay within the argument-count limit.

diet_guard at 100% branch coverage; full pre-commit suite passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 22:32:39 +02:00