Pulls every other device's pushed log from GitHub-backed dumb storage,
merges it with the local log, and pushes this device's own merged copy
back -- the PC half of the diet-guard-app sync plan.
- _sync_merge.py: pure union-by-id merge, tombstone always wins, legacy
(time, desc) dedup for pre-id entries. Commutative and idempotent.
- _sync_github.py: minimal GitHub Contents API client (list/get/put),
distinguishing a 404 on an unused path from the repo itself being
unreachable.
- _sync.py: orchestration -- pull, merge, re-sign every persisted entry
regardless of origin, write, rebuild the food bank, push. Re-signing
unconditionally is load-bearing: an unsigned phone-origin entry would
otherwise be silently dropped on the very next read once a machine
holds the shared HMAC key.
- _foodbank.rebuild_food_bank(): the "replay a full log into a fresh
bank" entrypoint the Python side was missing (the Dart port already
had its equivalent). Backs sync's bank-rebuild step.
- New diet-guard-sync.service/.timer (15-minute cadence, headless, a
separate unit from the gate so a held lock can't stall sync) and a
new install.sh step to install them.
- Created the private kuhyx/diet-guard-sync GitHub repo for storage.
Incidental to this feature: adding the `sync` subcommand pushed _cli.py
past the repo's 500-line cap, so `gate`'s CLI glue moved out alongside
sync's into _cli_gate.py/_cli_sync.py -- same split pattern already used
for the gate window logic itself, not a sync-specific design choice.
338 tests, 100% branch coverage. Verified importing and running cleanly
under /usr/bin/python (the production interpreter), not just the dev
venv -- the gap that caused the earlier 3-day outage.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FU3f5KQ1GHXsbbSecfVEyF
Lays the Python-side groundwork for the phone companion app's eventual
log sync (Milestone 0 of the diet-app-as-wise-balloon plan):
- log_meal() stamps every entry with a UUID id for union-by-id merging
across devices.
- undo_last_today() now tombstones (deleted: true, re-signed) instead of
popping the entry, so a sync merge can't resurrect a stale copy of
something already undone on another device.
- log_meal() accepts components, the full per-item macros for a
composite meal, so a food bank rebuilt purely by replaying the log can
recover every component's standalone nutrition.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FU3f5KQ1GHXsbbSecfVEyF
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).
MealGate now composes gatelock.GateRoot + gatelock.LockWindow instead of
inheriting the deleted _GateWindow/_GateRoot, and its HMAC signing goes
through gatelock.log_integrity. This is the first of three migrations
(diet_guard -> screen-locker -> wake_alarm) extracting the lock-window
mechanics that diet_guard's own _GateWindow proved out into a shared,
reusable package. Window-mechanics tests moved with the code; diet_guard's
suite now only tests its own wiring (LockConfig choice, hook delegation).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XCdT46zV8hESDvbgYMGDLt
Split diet_guard/_gatelock.py, wake_alarm/_alarm.py, and the
usage_report.py/_usage_report_parsing.py pair into focused
sub-modules so every Python file is <= 500 lines, satisfying
test_file_length.py. Install python-kasa into .venv (declared in
requirements but missing after the 3.13->3.14 venv upgrade),
fixing 8 failing smart_plug tests and restoring 100% coverage.
Also includes prior in-progress work from the working tree: the
wake_alarm Progress/View/Hardware field-grouping refactor,
brother_printer query module + tests, diet_guard foodbank/state/cli
updates, new shared coerce/logging_setup helpers, morning_routine
orchestrator tweaks, dwm window-manager config, gaming scripts, and
misc maintenance/digital-wellbeing script updates.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>