Commit Graph

160 Commits

Author SHA1 Message Date
0060b48b10 deps: sickdays 0.3.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PAhbNszs5JKdtnD4uBi3xp
2026-10-17 13:53:14 +02:00
597901dc08 phone: sick-day interop both ways with keep; docs
check.sh now runs Dart->Python (keep, unsorted/duplicate input, a cleared
keep day, a keep-only edit that must not re-stamp state) and
Python->Dart (0.2.0 keep sets plus a 0.1.0 record with no keep, a stale
keep and a malformed one), Python 0.2.0 as the oracle with explicit
paths and HOME pointed at a scratch dir. DOCS-sick-days.md and the
SickDays.kt contract describe the alarm-only native cache.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PAhbNszs5JKdtnD4uBi3xp
2026-10-16 15:31:11 +02:00
ee7e380278 phone: per-locker sheet on the sick-day calendar
Tapping today or a later normal day opens a sheet with one switch per
locker (Workout lock, LeetCode, Book, Diet, Wake alarm), all off, and
"Mark sick"; a sick day reopens with its switches, "Save" (keep-only
edit, nothing written when unchanged) and "Clear sick day". Past days
stay inert. A sick day keeping any locker carries a dot in the calendar
and a "Kept: ..." line in the list. DayCell moves to day_cell.dart for
the 250-line cap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PAhbNszs5JKdtnD4uBi3xp
2026-10-16 15:30:11 +02:00
7fe6108df3 phone: sick-day keep set (sickdays 0.2.0) in the Dart pool; alarm cache filtered
SickDayPool gains keep: mark/clear write state+actor+keep on one tick,
setKept re-stamps only keep+actor, read rules 1-5 in sick_day_keep.dart.
The native SickDays cache now holds only days on which the alarm stands
down, so a sick day that keeps the alarm rings like a normal day.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PAhbNszs5JKdtnD4uBi3xp
2026-10-16 15:30:11 +02:00
5d0f06b19e PC: sick days stand the alarm down only when it is not kept
All PC enforcement (fallback ring, RTC self-wake, trigger, workday penalty
write/retract, audit) now asks sickdays.stands_down(LOCKER_ALARM, day) via
_sick.alarm_stands_down instead of is_sick_day, so a sick day that keeps the
alarm behaves exactly as a normal stick day. Bump sickdays pin to v0.2.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PAhbNszs5JKdtnD4uBi3xp
2026-10-16 15:13:23 +02:00
2e594f041d phone: pin the clock in the stageLocalSettings enforcement test
The test staged a 2026-10-01 event through stageLocalSettings, which called
stageEnforcementData on the real clock; on 2026-10-16 the event aged past
boundEvents' 14-day window and the test went red for everyone.
stageLocalSettings now forwards an optional `now` to stageEnforcementData
(callers unchanged), and the test passes its fixed clock. phone_app suite:
402 passed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xfj1sxKH9VBPqpcAni8Jry
2026-10-16 14:55:26 +02:00
7e40bb138c ci_mirror: build the clean venv with uv (18.3 s -> 2.1 s cold)
The venv rebuild after a requirements.txt change was the largest cold-path
cost of `scripts/check_gate_stamp.sh full`. uv is also what CI installs
with, so the mirror gets closer to CI, not further. The interpreter is
passed as a path: `--python python3` let uv pick an active ~/.venv (3.13)
that crdt-sync 0.9.2 (>=3.14) cannot install into. pip stays as fallback.

Measured under capped.sh (4G, 20 %): `full` warm 10.9 s; fully cold
(no venv, empty PRE_COMMIT_HOME, empty mypy cache) 45.9 s, floor = the
pylint hook env install (~24 s, only after .pre-commit-config.yaml changes).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xfj1sxKH9VBPqpcAni8Jry
2026-10-16 14:55:18 +02:00
4f149e67a4 phone: read the native sick-day cache back on the Sick days screen
A release build gives no way to see the SharedPreferences cache that
AlarmReceiver reads at ring time (no run-as, no log of its contents), so
"the Dart UI shows it" could not prove "the alarm will stay silent".

- SickDays.store/dates log the sorted set under WakeAlarmSickDays.
- AlarmChannel getSickDays returns the cached set (null if unreadable).
- The Sick days screen reads it on open (before the sync rewrites it) and
  after every sync: "Alarm cache: <dates>" / "none" / "unreadable".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xfj1sxKH9VBPqpcAni8Jry
2026-10-16 14:38:25 +02:00
29e64fb7fa Merge branch 'sickdays-phone' into sickdays-pc
# Conflicts:
#	AGENTS.md
2026-10-16 13:26:09 +02:00
e0ef3e1217 docs: sick_day in the phone event contract; portable gradle test note
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xfj1sxKH9VBPqpcAni8Jry
2026-10-16 13:25:31 +02:00
34037e55c1 phone: sick days — picker, silent ring, stick stand-down, pre-alarm sync
- Sick days screen (own name, sick icon, cat-2 fill): tap today or a later
  day to mark it sick, tap again to clear; past days inert. Writes the
  sickdays wire format (state sick/cleared + actor, one HLC per write) to
  sickdays-sync/devices via crdt_sync syncLog.
- Mutual exclusion in both pickers: each syncs the other pool on open and
  refuses a date it holds, naming the pool; an unreadable pool refuses all.
- Native SickDays cache (fail closed via DayCache); AlarmReceiver skips the
  ring with reason "sick_day" (no markFired, no ring_started); StickCheck
  verdict sick_day, streak skips sick days; stakes card says so.
- Pre-alarm pool sync: allow-while-idle alarm at 21:00 and A-30 (request
  code 1006) runs a headless engine (poolSyncMain) that pulls both pools
  from RTDB and rewrites both native caches, so a PC mark arrives with the
  app closed. The ring decision stays a cache read.
- JVM unit tests (JUnit 4.13.2) for DayCache, RingDecision,
  PoolSyncSchedule, StickCheck; Dart tests; Dart->Python interop check.

pylint hook skipped: verify.py imports sickdays, not in the hook env until
the sickdays-v0.1.0 tag exists; run by hand in a sickdays venv (10.00/10).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xfj1sxKH9VBPqpcAni8Jry
2026-10-16 13:22:40 +02:00
8696f2d0bf wake_alarm: sick days stand the PC down (fallback ring, RTC wake, trigger, workday penalty)
A date in the new shared sickdays pool (not a free day) now means, on the PC:
no fallback ring (a ring in progress stops, reason sick_day), no RTC
self-wake for that morning (ours is disarmed), no morning-routine trigger,
and no workday_penalty.json; a penalty issued on a day later marked sick is
retracted (penalty_cancelled, cause sick_day) by the next session refresh or
RTC tick. The audit treats the day as one where nothing is expected.

All pool access goes through wake_alarm/_sick.py: fail closed (unreadable
pool or missing package = not sick), and act modes pull the pool from
Firebase first (RTC --arm on a stick-day target, in-window fallback ticks
and ring polls, the day's first penalty write) because the sickdays timer
pauses through hibernate. Dry runs never pull.

Pins: sickdays-v0.1.0, freedays-v0.4.0, crdt-sync-v0.9.2 (needed by both);
pre-commit 4.7.0, pylint 4.1.3, ruff 0.17.1 (freshness gate).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xfj1sxKH9VBPqpcAni8Jry
2026-10-16 08:45:29 +02:00
3b8cd21969 chore: add MIT LICENSE
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-11 18:14:11 +02:00
ffe7666f49 deps: Flutter 3.47.7, shared_preferences 2.5.6
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018RHwVPyiiQMPh4M3JQwQku
2026-10-09 19:27:56 +02:00
a0731c496c Sync: stop reading screen-locker's sync_token (screen-locker is Firebase-only now)
screen-locker's PC sync went Firebase-only on 2026-10-09 and nothing
maintains ~/.config/screen_locker/sync_token any more. The GitHub-fallback
token list now holds only diet_guard's repo-scoped PAT. Drop the stale
note about shutdown-wrapper.sh mirroring the list (the wrapper was removed
on 2026-08-30).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018RHwVPyiiQMPh4M3JQwQku
2026-10-09 19:11:50 +02:00
57a6c6ba0e dependency freshness: bump pylint 4.1.2, url_launcher 6.3.3, github_device_auth v0.3.2 (CI red fix)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-04 17:39:28 +02:00
8e254dbef6 repo contract: CLAUDE.md commands, test_changed, CI gate, AGENTS.md update
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-04 16:58:12 +02:00
a6d5688eb7 CI: slim Flutter SDK for the interop job; APK only on app changes, Gradle cached
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-02 15:08:47 +02:00
83b9d5c4c7 CI: Flutter 3.47.6 in the workflow pins too
The .fvmrc moved in the previous commit; CI's freshness gate also reads the
flutter-version pins in python-tests.yml and release-apk.yml.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FBbkN4ZB4aUPJPzR2prRan
2026-10-02 14:40:58 +02:00
9325103f5d Flutter 3.47.6; dismiss re-arm test no longer passes only on Tue-Thu
The expectation resolved the next alarm without the earned ramp set, while
the app (correctly) re-arms with the minute the dismiss just earned. On a
non-workday that is one minute apart, so the test failed Fri-Mon on any
Flutter version. It now loads the policy exactly as the app does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FBbkN4ZB4aUPJPzR2prRan
2026-10-02 14:28:55 +02:00
f95cf826d2 gatelock 0.8.2 -> 0.9.0; mypy 2.4.0, pylint 4.1.1, ruff 0.16.10
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
2026-10-02 14:19:53 +02:00
012673aa99 TODO: v2 follow-ups for the next session
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-01 19:39:58 +02:00
9b3c3ba26b Docs: v2 verification status; vmbox can emulate RTC wake now
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-01 12:30:32 +02:00
4527834b45 Take pylint 4.1.1 (newest stable)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-01 12:27:37 +02:00
728e00cde7 Wake enforcement v2: PC fallback ring + RTC self-wake, stacking Tue-Thu phone lockdown, escape hatch until 2026-10-15, stakes in the app, daily incident audit
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-10-01 12:17:06 +02:00
19f23f35a6 Free days: a month calendar of the shared pool; tap a future date to book it, tap a booked one to release it
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-27 20:53:46 +02:00
7f7fd916f7 Earned ramp: a dismissed Mon/Fri/Sat/Sun morning earns the minute; workdays hold, misses and free days earn nothing; workdays from freedays 0.3.0
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-27 20:13:22 +02:00
a4876d84ec Speed up CI: uv installs, split pre-commit into mypy/pylint/rest
- pre-commit: drop the 28 s requirements.txt install (only
  dependency-freshness among the system hooks needs third-party code:
  pyyaml, packaging), run pre-commit directly instead of
  pre-commit/action, and split mypy and pylint into their own matrix
  jobs with per-group hook-env caches. Same hook set, same
  SKIP=free-days-interop (the rest group).
- Tests: uv with a cached wheel store for requirements.txt (pip took
  22 s), -q and -p no:sugar. No -n auto: the suite runs in ~0.5 s and
  measured ~1.2 s under pytest-xdist.
- free-days-interop (the critical path): build the freedays venv with
  uv instead of venv + pip (12 s).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0188kZdx3bb56QM8JFUnbHuM
2026-09-26 17:45:00 +02:00
16f9ddeb13 Keep the test suite's JSONL log out of the live events.jsonl
_logging_setup attaches its JSONL sink the first time an entry point's
main() runs, and the conftest never redirected LOG_JSONL_FILE or
LOG_DEDUPE_FILE. Every suite run appended ~25 fixture warnings ("Synced
alarm out of range: 24:0") to ~/.local/state/wake_alarm/events.jsonl, the
log a failed wake-up is reconstructed from. Patch _logging_setup's names
(it imported them by value) in the autouse _hermetic fixture.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0188kZdx3bb56QM8JFUnbHuM
2026-09-26 17:44:52 +02:00
702f37a7ba Bump ruff 0.16.8 -> 0.16.9 and Gradle 9.7.1 -> 9.8.0: newest stable dependency-freshness gate
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-25 13:27:37 +02:00
d8b07b2be4 Cook the frog: lower the wake baseline a minute a day from 08:00 to 07:00
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-25 13:15:44 +02:00
8be972c31a Record the two deferred hardware wake-defeat ideas as a repo TODO
ESP32 second-alarm device and wearable wake-defeat check were scoped
during the workday-stick session but explicitly deferred (no existing
firmware project, no owned wearable, both need a real purchase first).
Kept here instead of ~/src/todo/BACKLOG.md, which is gitignored and
export-only from the todo app and would silently drop the addition on
the next export.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018kwx6YYv9Mnw9EtRsJ6hbf
2026-09-23 22:07:56 +02:00
8275966a83 Bump pylint 4.0.8 -> 4.0.9: newest stable dependency-freshness gate
CI's dependency-freshness check runs live against PyPI and caught the
new release after this session's local pre-commit run used a stale
snapshot.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018kwx6YYv9Mnw9EtRsJ6hbf
2026-09-23 21:37:38 +02:00
bfe8bab58a Add the Tue/Wed/Thu workday stick: signal focus-owner and write tomorrow's penalty
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-23 21:20:58 +02:00
92b7ae5d76 pre-push is a 1-second stamp check; the suites moved to the manual stage
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-20 21:29:10 +02:00
d953d67ae3 Open the PC from 05:00 until the alarm has been dismissed; the session is the check
The first carrot only opened at 08:30: someone up at 07:00 (the goal) got
the LeetCode gate at the 05:00 login-arm, and the workout lock was held off
by an unrelated clock. A day with no session yet is now exempt until the
phone's alarm plus 15 min -- clamped to the 08:00 baseline like the trigger
-- so the login-arm defers by itself; the alarm rings regardless, and a
dismiss that has produced no session by then means "not up". The refresher
runs from 05:00 (every 10 min until 07:00) so the file is today's when the
locks decide. The rule moved to _session_policy (250-line cap).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XTdfXjbGYYrY7Quxcfz6mg
2026-09-20 08:39:24 +02:00
c3c129b068 Make the morning session the carrot: earn 11:00 by finishing it in time
On 2026-09-19 the phone was powered off after the bathroom tag and nothing
on the PC noticed: every finished session was published and nothing read
it. Now wake-alarm distils the phone's morning into an HMAC-signed
~/.local/state/wake_alarm/morning_session.json (wake-alarm-session.timer,
07:00-11:00 every 2 min) that screen-locker and leetcode-guard read to
defer their locks -- provisionally until min(start + 90 min, 09:30) while
the session is live, until 11:00 once it completed inside that cutoff,
and not at all for a session finished later (the phone switched on at
noon completes the legs then; that must un-lock nothing).

The phone publishes the session at start as well as at finish
(current_session, cleared with the finish stamp), so the PC can tell
"started, not finished" from "never started". A required 1-5 energy tap
joins the weigh-in and ships as latest_energy with a PC reader mirroring
_weight (the shared half is _field_reader).

Also fixes the vmbox harness, red since the 2026-09-11 home-tidy: the
guest tree lives at ~/wake-alarm, and the INSTALL-OK grep matched vm's
echo of the command line. Takes Flutter 3.47.5.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tp54ewdXRLaimUuT8LgYyn
2026-09-19 16:40:51 +02:00
af293413c0 Keep the morning session reachable after leaving the app; drop the still-phone watch
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 09:01:22 +02:00
c7e7695466 Read the phone's newest weigh-in on the PC
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 22:49:08 +02:00
6bfb059309 Take gatelock 0.8.2, flutter_secure_storage 11.2.0, coverage 7.16.1 and ruff 0.16.8
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 22:36:33 +02:00
f31f195187 Keep the morning going after the ring: weigh-in, shower, dress, desk, or it rings again
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 22:35:40 +02:00
84d6cbdc17 Take gatelock 0.8.1, Flutter 3.47.4 and flutter_secure_storage 11.1.1
The freshness gate's three findings. gatelock 0.8.1 restructured
LockConfig, which this repo does not use (only log_integrity), so the
pin moves without a code change; pylint stays at 10 against it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HHCbkJWXHjtTUaqvnHRAqA
2026-09-12 20:02:31 +02:00
07f2408f7e Re-point paths for the ~ reorganisation (home-tidy)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AwtowrowDXx6ccmWVPkCaF
2026-09-11 18:46:34 +02:00
8e60a3667a Run the free-day interop gate in CI where Flutter exists
The pre-commit job has no Flutter and no freedays venv, so the new hook
could only fail there. It now runs as its own job in python-tests.yml
(utils checkout + a venv with crdt-sync and freedays + subosito Flutter),
and the pre-commit job SKIPs that one hook, with the reason next to it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019pBgaXSJKyY3DarYpDatDF
2026-09-11 13:55:53 +02:00
758b2976b8 Gate the free-day rules against the Python package, and fix two picker paths
showDatePicker asserts that initialDate satisfies selectableDayPredicate,
so with today already free the picker asserted in debug and, in release,
pre-selected a disabled day. The cursor now starts on the first non-free
day. And the reason dialog had no Cancel: a barrier tap marked the day
anyway. Both covered by widget tests; the first fails without the fix.

The cross-language check that proved the Dart port was a one-off probe,
deleted after it ran. It is now scripts/free_days_interop/check.sh, a
pre-commit hook on both inputs: Dart writes one pool through every policy
branch, Python replays the same edits into a scratch pool, and every
semantic reading has to agree. The Python package is the oracle -- Dart's
own count compared to what Python reads from Dart's file cannot see a
drift in what Dart writes. Proved by dropping the sticky consumed flag
from release: remaining dart=33 python=32.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019pBgaXSJKyY3DarYpDatDF
2026-09-11 13:53:56 +02:00
146c427d6d Add the free-day picker, and stop the phone ringing on a free day
The shared pool (~/utils/freedays) was CLI-only: the gates on the PC stood
down, but the phone kept ringing at 08:00 and there was nowhere to mark a
day from bed. This is the one picker for every app.

FreeDayPool is a Dart port of the Python rules with the identical record
shape (id = ISO date; state/consumed/actor/reason on one tick; un-mark is
a state flip, never a tombstone), verified by a real cross-language round
trip: a log written here reads back through freedays.is_free_day and
remaining() with the same verdicts and count, and the PC's live pool reads
here as the same 27 of 35 that `freedays status` prints.

The alarm fires from Kotlin with no engine running, so the pool is
mirrored into a native SharedPreferences set after every mark, release and
sync (channel method setFreeDays), and AlarmReceiver consults it before
starting AlarmService. Fail closed: a missing or corrupt cache rings. All
three branches exercised on the API 36 AVD by broadcasting the receiver.

Firebase only for this namespace -- no GitHub mirror; the alarm record
keeps its own because un-migrated installs depend on it.

Known gap, documented rather than papered over: a day marked on the PC
reaches the phone at the next app launch or picker open, not overnight.
The ring path takes no background dependency by design, so mark on the
phone, or open the app once after marking on the PC.

Verified on the phone (release build, 23181JEGR08034): picker shows the
budget, marks 2026-09-30 with a reason, pushes it to
freedays-sync/devices/<uuid>, releases it with a full refund back to 35.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019pBgaXSJKyY3DarYpDatDF
2026-09-11 13:45:42 +02:00
f709fb8028 Bring Flutter, flutter_secure_storage and ruff up to latest stable
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 12:37:33 +02:00
b5701fb359 Sync the NFC tags and home location so a reinstall gets them back
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 12:34:50 +02:00
c0ed168540 Pin freedays v0.2.0
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>
2026-09-07 15:58:35 +02:00
2904d97b2c Bring the phone app's analyzer up to latest stable
very_good_analysis ^10.3.0 -> ^11.0.0, which the freshness gate flagged
against phone_app/pubspec.yaml the moment the pre-push CI mirror ran
--all-files. Pre-existing; it blocked the push rather than being caused
by it.

The major bump newly flags two async_return_with_no_await sites, both now
`return await` rather than suppressed. The rule is correct in both: a
future returned without awaiting escapes the enclosing async function, so
a failure surfaces at the caller with a stack trace that no longer names
the code that made the call. firebase_backend.dart:91 is the one that
matters -- a rejected credential fetch should fail inside the function
that describes itself as recovering from exactly that.

flutter analyze clean, 146 phone-app tests pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 15:30:00 +02:00