Commit Graph

21 Commits

Author SHA1 Message Date
89e6eed105 Bump sync_settings_ui to 0.6.1
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (mypy, mypy, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (pylint, pylint, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (rest, , mypy,pylint,free-days-interop) (push) Waiting to run
Tests / test (push) Waiting to run
Tests / free-days-interop (push) Waiting to run
release-apk / release (APK) (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-11-08 18:28:23 +01:00
06b70ab312 Bump crdt_sync to v0.12.0
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-11-08 14:24:46 +01:00
13f6e3f5d2 Use google_account_token for sign-in
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WzxdWY1k4muZfdVJfb7YGJ
2026-11-02 11:27:35 +01:00
fd65c454e3 chore: bump deps to newest stable
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WzxdWXTUM9dpnCS2wtFkx4
2026-11-01 20:13:43 +01:00
05738db15a feat: JSON export/import on device
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WzxdWXTUM9dpnCS2wtFkx4
2026-11-01 19:55:04 +01: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
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
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
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
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
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
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
5117f5a0c9 Latest stable dependencies, and the gate that keeps them there
**The two shared Python libraries were four minor versions behind and the gate
could not see it.** They are PEP 508 direct references
(`gatelock @ git+...@gatelock-v0.4.1`), which parsed as unpinned PyPI packages
that do not exist on PyPI -- an undeterminable answer, not a stale one.
utils@7a682a4 teaches the gate that shape; this repo is the first to benefit:
gatelock v0.4.1 -> v0.7.2, crdt-sync v0.5.1 -> v0.9.1. The system install was
already on 0.7.1/0.9.0, so only the manifests were adrift.

Python side: bandit 1.7 -> 1.9.4, mypy 1 -> 2.3.1, pylint 3 -> 4.0.7,
pytest 8 -> 9.1.1, pytest-cov 4 -> 7.1.0, pytest-randomly 3 -> 4.1.0,
ruff 0.8 -> 0.16.5, python-kasa 0.7 -> 0.10.2, and the rest exact-pinned.
Five majors and not one lint or type finding: `scripts/ci_mirror.sh` builds a
clean venv from requirements.txt and runs the whole CI set, 465 tests at 100%
branch coverage.

phone_app takes crdt_sync_dart v0.11.1 and the flutter_secure_storage 11 chain
(compileSdk 37 / AGP 9.3.2 / Gradle 9.7.1). 79 tests green, analyzer clean,
release APK builds.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CRykabMwPgDzFHcARoqpaK
2026-08-28 14:56:16 +02:00
b9abbf7043 phone_app: use the shared github_device_auth package
The inline `_DeviceCodeDialog` (86 lines) was byte-for-byte identical to
diet-guard's, and `services/github_device_auth.dart` was a fourth copy of
the auth client. Both now come from `github_device_auth` in the
kuhyx/utils monorepo.

This app's client was not merely a drifted copy -- it carried a fix the
other three lacked: `pollForToken` swallowed a transient socket failure and
kept polling, because GitHub can close the connection at the exact moment
the user authorizes. Extracting todo's version would have silently deleted
that. The package took this behaviour instead, so the fix now protects all
four apps rather than just this one.

It is expressed as `on http.ClientException` rather than the local
`SocketException` arm, because the package is also imported by
diet-guard's **web** build where `dart:io` will not compile. Verified that
nothing is lost: package:http wraps a dead socket as
`_ClientSocketException`, which implements both types.

19 tests pass, analyze clean, and the release APK is installed on the
phone and launching.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U4Rj3s7K2qzrLNgJqqPhno
2026-08-15 16:16:17 +02:00
90a7dafb48 phone_app: migrate Sync settings to the shared sync_settings_ui package
Settings screen becomes a thin dispatcher with two links: "Sync settings"
(the shared sync_settings_ui package, Firebase-only) and "Advanced sync
(GitHub)" (app-local, moved verbatim -- the shared package carries no
GitHub surface).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdSp6Nbrs9xvsWkCMDN9a1
2026-08-14 11:29:32 +02:00
37a7829757 phone_app: add Google sign-in support for the Firebase sync account
Same pattern as todo, diet_guard_app, and workout_app: openFirebaseWithGoogle()
(google_platform.dart abstracts the plugin's platform-channel dependence),
isFirebaseConfigured() reading the stored session rather than the account
marker alone, and the settings screen offering "Sign in with Google" ahead
of the password form.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KdSp6Nbrs9xvsWkCMDN9a1
2026-08-14 11:26:33 +02:00
03392e7ea5 Discover alarm device directories instead of reading a fixed phone path
The PC read one hardcoded path, wake-alarm-sync/devices/phone/alarm.json,
and never parsed the HLC. The phone's device id is migrating from the fixed
constant "phone" to a per-install uuid (a role constant collides as soon as
a second install takes the same role, and a reinstall inherits the previous
install's CRDT identity). A reader pinned to the old path would have stopped
seeing the alarm the moment the phone migrated, fallen through to the cache
and then to FALLBACK_ALARM_HOUR -- i.e. woken at the wrong time, silently.

So the PC half ships first, and this commit is that half plus the phone
change it makes safe:

- _fetch_firebase_alarm() lists SYNC_DEVICES_PREFIX, reads every device's
  alarm.json, and picks the newest by the hour field's HLC rather than by
  listing order. device_id breaks an exact tie so two devices stamped in the
  same millisecond don't alternate between ticks; a device whose payload
  doesn't parse is skipped rather than allowed to win with a bad value.
- SYNC_ALARM_PATH stays as a last-resort read for a backend that lists
  nothing, so an un-migrated install keeps working. The GitHub mirror still
  reads the single fixed path.
- The phone persists a uuid under SharedPreferences 'crdt.nodeId' (the key
  todo and home_inventory already use) and pushes under it. deviceId is now
  an instance field, injectable so tests don't touch real prefs.

Parsing and ranking moved to _alarm_payload.py: _sync.py was over the repo's
500-line cap, and the wire format deserves testing without network or disk --
a misparse here doesn't raise, it just resolves to the wrong wake-up time.

Verified against the live RTDB, not just mocks: seeded a uuid-named device
directory and confirmed the reader discovered it, read it and ranked it --
losing to the phone with an old stamp, winning with a new one (03:15 vs the
real 07:45). Test device deleted; --show returns 07:45 and the cache is
intact.

354 tests, 100% branch coverage. Phone app: 10 tests, analyzer clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZH89WEqAjuJT8WZdqc7AP
2026-08-09 17:06:43 +02:00
98f6c5c26c Sync the phone's alarm through Firebase, mirroring to GitHub
Completes the cutover started on the PC side: phone_app was still pinned to
crdt_sync_dart-v0.2.0, so the Flutter half was writing only to GitHub even
though _sync.py had already moved.

pushWith() now takes a RemoteStore instead of a GitHubClient, so one call
serves Firebase, GitHub, or the MirrorStore that writes both; syncBackend()
picks which, and returns the bare GitHub client when this device has not been
set up for Firebase -- the normal cutover state, and also the rollback. The
remote path is byte-identical on both backends, so only the transport differs
and the PC's parse is untouched.

Settings gained the Firebase section that actually calls saveAccount(). Its
absence was the bug found in diet-guard: without it openFirebase() always
returned null, so the app was a Firebase no-op on real hardware no matter
what the tests said. Signing in happens immediately on Connect, so a wrong
password surfaces on-screen rather than as a silent failure at push time.

The three UI problems kuhy hit in diet-guard are avoided here rather than
repeated: GitHub is demoted into "Advanced (GitHub mirror)" instead of
sitting beside Firebase as a peer choice, the connected account renders as
read-only text with a Disconnect button rather than an empty-looking form,
and the status card reports the Firebase state it is actually reading.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017FH32BgGQbQLDstBhR26Xa
2026-08-05 09:20:02 +02:00
64c25e67e9 phone_app: replace the stock Flutter launcher icon
Some checks are pending
pre-commit / pre-commit (push) Waiting to run
Tests / test (3.10) (push) Waiting to run
Tests / test (3.11) (push) Waiting to run
Tests / test (3.12) (push) Waiting to run
Adopt the shared icon family (python_pkg/app_icons in testsAndMisc): a
charcoal #1B1D21 field carrying an orange clock glyph, orange being this
app's own theme seedColor.

The clock is deliberately drawn without bell "ears" - at launcher size they
read as noise rather than as an alarm clock.

Adds the adaptive-icon layers the project never had, including an Android 13
monochrome layer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-19 16:59:38 +02:00
512fdd5c95 Migrate phone_app alarm sync from GitHub Gist to crdt_sync
Some checks are pending
pre-commit / pre-commit (push) Waiting to run
Tests / test (3.10) (push) Waiting to run
Tests / test (3.11) (push) Waiting to run
Tests / test (3.12) (push) Waiting to run
phone_app: the alarm now syncs through the shared crdt_sync transport
(v0.2.0) into the fixed private repo kuhyx/syncs, replacing the bespoke
Gist. AlarmSyncService is the sole writer: it holds the alarm locally in a
crdt_sync LogStore (one HLC-stamped Record) and pushes it to
wake-alarm-sync/devices/phone/alarm.json. gist_service.dart is deleted;
SyncSettings drops the Gist id and keeps only a token; the device-flow scope
moves from `gist` to `repo` (the Contents API needs private-repo access).

shutdown-wrapper.sh: the PC reader now fetches that alarm from the Contents
API (Accept: application/vnd.github.raw, so no base64) and parses the
crdt_sync Record Log with jq (.alarm.fields.alarm_hour[0]). Single-file read
of the sole "phone" device; unchanged fallback to WAKE_AFTER_HOURS on any
miss so a parse failure can never brick the wake. Config moves from
gist_sync.json {token, gist_id} to sync.json {token}.

Verified: flutter analyze clean + tests pass; shellcheck clean and the full
get_synced_alarm_epoch verified against the real Log format; on-device the
app builds, installs with adb install -r (no data loss), launches and
renders. Live round-trip needs a one-time repo-scoped re-auth on the phone
and ~/.config/wake_alarm/sync.json on the PC.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019KwUCPESvE5CjCtmUFz8xQ
2026-07-11 22:45:14 +02:00
0704e44912 Add wake_alarm_sync phone-side Flutter companion app
Some checks are pending
pre-commit / pre-commit (push) Waiting to run
Tests / test (3.10) (push) Waiting to run
Tests / test (3.11) (push) Waiting to run
Tests / test (3.12) (push) Waiting to run
New Flutter app (com.kuhy.wake_alarm_sync) that sets the phone alarm and
writes the wake time to a GitHub Gist for cross-device sync: Gist service,
GitHub device-flow auth, sync settings, home/settings screens. Source only;
build/.dart_tool/.idea artifacts excluded by the app's .gitignore.

Not yet gated by CI (wake-alarm CI is Python-only) and pending on-device
verification.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RRCdR4D8SaVrN2xraMQxM
2026-07-10 23:16:11 +02:00