From 5525ca6f955ecf872fe41785e86121851141c9a2 Mon Sep 17 00:00:00 2001 From: Krzysztof kuhy Rudnicki Date: Mon, 2 Nov 2026 11:14:40 +0100 Subject: [PATCH] Move TODOs to todo app Co-Authored-By: Claude Opus 5.5 (1M context) --- TODO-hardening-continue.md | 23 --- TODO-hardware-wake-defeat.md | 63 -------- TODO-wake-enforcement-v2-followups.md | 90 ----------- prompts/TODO-dopamine-ux-wake-alarm.md | 202 ------------------------- 4 files changed, 378 deletions(-) delete mode 100644 TODO-hardening-continue.md delete mode 100644 TODO-hardware-wake-defeat.md delete mode 100644 TODO-wake-enforcement-v2-followups.md delete mode 100644 prompts/TODO-dopamine-ux-wake-alarm.md diff --git a/TODO-hardening-continue.md b/TODO-hardening-continue.md deleted file mode 100644 index 0cdc975..0000000 --- a/TODO-hardening-continue.md +++ /dev/null @@ -1,23 +0,0 @@ -# Wake-alarm hardening — residue - -REMOVE ME AFTER FINISH - -Phases 0-7 shipped. The PC alarm window, gate and `_alarm.py` were deleted in -`e67cef0` (2026-08-30), so the old "item 8 mutual gating" (PC half) no longer -has anything to gate and was dropped. Context: `DOCS-wake-enforcement.md`. - -## Remaining - -1. **Item 13, black screen.** Host-only, other repo - (`~/src/testsAndMisc/linux_configuration`). The original plan file - (`~/.claude/plans/wake-alarm-still-does-witty-toucan.md`) is gone, so the - symptom is no longer written down: needs kuhy to restate it, or drop it. -2. **Two-tag dismiss sequence, end to end on the Pixel.** Needs kuhy: a second - physical NFC tag (only one is registered, so every on-device run fell - through to the 5-minute bypass). -3. **Locked-keyguard dismiss, run to completion.** Needs kuhy: a run with a - locked phone (PIN-prompt path is implemented but unproven). - -## done - -Items 1-3 each confirmed on the phone or dropped by kuhy; then delete this file. diff --git a/TODO-hardware-wake-defeat.md b/TODO-hardware-wake-defeat.md deleted file mode 100644 index a574388..0000000 --- a/TODO-hardware-wake-defeat.md +++ /dev/null @@ -1,63 +0,0 @@ -# Hardware ideas: defeat a fully-powered-off phone - -REMOVE ME AFTER FINISH - -Both items below were scoped during the 2026-09-23 workday-stick session -(`DOCS-morning-session-pc.md`) and explicitly deferred out of scope for that -session: no existing firmware project and no owned wearable, both need a real -purchase before any code gets written. Written here instead of -`~/src/todo/BACKLOG.md` because that file is gitignored/export-only from the -todo app and a manual edit there is silently lost on the next export — this -is the durable copy. - -## Item 1 — second wake-alarm device: rings independently of the phone's power state - -### what -An ESP32 + buzzer that polls the same Firebase alarm/session record -wake-alarm already reads and keeps ringing until it sees a dismiss or a -started session — so powering the phone off can no longer silently kill the -whole wake attempt the way it does today. - -### where -new repo (no existing ESP32/PlatformIO/Arduino project anywhere in `~/src` -to build on — checked). Firebase-only, per the "new syncing apps are -Firebase-only" rule. - -### must -- must not require the phone to relay anything — the whole point is - surviving the phone being off. -- optional: a physical snooze/dismiss button, since the phone's own dismiss - gate isn't reachable from the device. - -### done -On a Tue/Wed/Thu, power the phone off right at the alarm and the ESP32 -still rings, and keeps ringing, until the phone's session shows a start. - -### verify -Bench test first (USB power, no case), then a real overnight run. - -### read first -- `DOCS-phone-alarm.md` (the Firebase alarm schema to poll) -- `DOCS-morning-session-pc.md` (why this exists: the workday-stick project, - 2026-09-23) - -## Item 2 — wearable wake-defeat check - -### what -A cheap fitness band whose own sleep log (stored on the band, synced later) -can show "asleep again after the alarm rang" even when the phone was fully -off and missed the whole thing. - -### where -new app or an extension of `phone_app/`, once a device is picked. - -### must -- must not: buy or integrate anything before checking Gadgetbridge's - current supported-device list — research first, kuhy owns no wearable and - none is integrated anywhere in `~/src` today (checked). - -### done -Not yet scoped — picking a supported device is the blocking step. - -### verify -Blank — desktop, once there's something to verify. diff --git a/TODO-wake-enforcement-v2-followups.md b/TODO-wake-enforcement-v2-followups.md deleted file mode 100644 index 7e6ced8..0000000 --- a/TODO-wake-enforcement-v2-followups.md +++ /dev/null @@ -1,90 +0,0 @@ -# Wake enforcement v2 — follow-ups for the next session - -REMOVE ME AFTER FINISH - -Handoff from the 2026-10-01 session that built v2. Read -`DOCS-wake-enforcement.md` (the contract + verification status) and -`AGENTS.md` first. Start **after the morning of 2026-10-02** so there is real -evidence to check. - -## Prompt to paste into the new session - -> Work through ~/src/wake-alarm/TODO-wake-enforcement-v2-followups.md top to -> bottom. Verify each item yourself on the real target (phone 23181JEGR08034, -> this PC) before calling it done, then delete the TODO file in the final -> commit. - -## 1. Check the first real morning (2026-10-02, Fri, carrot day) - -- `python -m wake_alarm._audit 2026-10-02` (and the 11:05 file in - `~/data/wake-alarm/incidents/`). Expected: phone `alarm_fired` - (`reason=daily`), `ring_started_published` with `source=alarm` (headless - engine, release build — never verified in release before) or - `ring_screen`, `stick_check` verdict for a non-stick day, no fallback ring - unless the phone really was silent. -- `adb logcat` for `WakeAlarmHeadless` / `WakeAlarmStick*` if anything is - missing. Firebase fields `ring_started`, `phone_events` must be non-empty - (`enforcement_view(fetch_firebase_logs())`). -- Any MISMATCH in the report is a bug to fix, not a note. - -## 2. focus-owner reacting to a real lockdown (needs kuhy's OK + timing) - -Never verified on the Pixel. Either wait for the first real Tue/Wed/Thu miss -and read focus-owner's Debug log (`LOCKDOWN_ACTIVATED` with the through-date, -then a `WORKDAY_LOCKDOWN` pass), or — with kuhy's explicit OK, at a time he -names — trigger one and lift it with the escape button (logs an escape). - -## 3. Root ring vs a card held busy by PipeWire - -Host test 2026-10-01: `wake-alarm-ring-alsa.service` got `Device or resource -busy` while the user's PipeWire held card `Generic_1` (ALC897). kuhy approved -killing the holder (`fuser -k -TERM /dev/snd/pcmCD0p` after 3 busy opens, -in `scripts/pc/ring_alsa.sh`), but the auto-mode classifier refused the edit -twice. **kuhy must add a permission rule first**, or choose the non-killing -alternative: when the root unit cannot open the card, `_ring_player` falls -back to `PipeWireBackend` (PipeWire holds the card, so it can mix the ring -in). Add a vmbox case that holds `snd-dummy` open and proves the ring still -plays. - -## 4. S5 (poweroff) RTC wake test on the host - -Hibernate (S4) wake is verified and is the default mode. S5 is not. The -self-resume boot unit (`~/data/claude-scratch/wake-fw/s5_after_boot.sh`, -never installed) was refused by the classifier. Simplest: with kuhy present, -`sudo -n rtcwake -m no -s 240` + record the epoch, `systemctl poweroff`; kuhy -powers on if it does not wake; then compare `uptime -s` with the epoch. If S5 -works, decide with kuhy whether to switch `pc_wake.json` to `poweroff` (covers -a typed `shutdown`, not just the power key). - -## 5. utils dependency upgrade — prepared, uncommitted - -In `~/src/utils` (do NOT stage the other session's `ts_config/README.md`, -`scripts/lib/alias-imports.mjs`, `test/alias-imports.test.js`): pylint 4.1.1 -×3, typescript-eslint 8.71.0 (ts_config/ts_core/web_ui), @eslint-react -5.23.3, eslint-plugin-sonarjs 4.2.2, pnpm 12.8.1 (+ lockfiles, -`ts_config/pnpm-workspace.yaml`), allowlist: typescript-eslint entry removed, -typescript entry now `blocked_by: transitive:typescript-eslint@8.71.0`. -Lint + tests pass in all three. `finish_auto.sh` fails at its test step with -corepack `MODULE_NOT_FOUND .../pnpm/12.8.1/bin/pnpm.cjs` (pnpm 12.8 ships a -native binary; corepack 0.36 can't launch it). Global pnpm 12.8.1 is now -installed directly (`corepack disable pnpm`); find what in the gate still -calls corepack (read `~/data/claude-scratch/wake-v2/utils-commit.log`), fix, -commit, watch CI green. - -## 6. Fleet repos still pinning typescript-eslint 8.70.0 - -The allowlist entry that excused them is gone, so their freshness gate turns -red on the next run: konbini-67, iron-and-anvil, awesome-mcp-explorer, -europe-county-map and any other repo pinning it (`grep -rl -'"typescript-eslint": "8.70.0"' ~/src --include=package.json`). Bump each to -8.71.0, lint + test, commit, CI green. - -## 7. Small leftovers - -- `~/src/todo`: `cupertino_icons` 1.0.9 → 2.0.0 — another session had - uncommitted work there; only bump once its tree is clean. -- Global `~/.claude/CLAUDE.md` sandbox-first note says the vmbox guest is - BIOS-only; vmbox has `--uefi` and `vm wake` (RTC-wake emulation) since - utils 694c013. Ask kuhy before editing that file. -- Clear the test data left in the `wake_alarm_api36` emulator (escape for - 10-01, ringStarted, stick state) before it is ever signed into sync. diff --git a/prompts/TODO-dopamine-ux-wake-alarm.md b/prompts/TODO-dopamine-ux-wake-alarm.md deleted file mode 100644 index 07b61c6..0000000 --- a/prompts/TODO-dopamine-ux-wake-alarm.md +++ /dev/null @@ -1,202 +0,0 @@ -> **This file is a ready-to-use prompt.** Open this repo and say -> "do dopamine-ux-wake-alarm". It is self-contained -- it needs no context from -> any other session. -> -> Canonical copy: `~/src/utils/dopamine-ux/09-wake-alarm.md` (source of truth; this is a -> distributed copy). Running order and cross-prompt rules: `~/src/utils/dopamine-ux/00-INDEX.md`. -> Generated 2026-08-16 from a survey of this repo -- line numbers are accurate -> as of that date; **anchor on the symbol names, not the line numbers.** - -## ⛔ WHEN YOU FINISH THIS PROMPT - -Do **both**, in the same session that completes the work: - -1. **Delete this file** and commit that deletion together with the - implementation: - ```bash - git rm prompts/dopamine-ux-wake-alarm.md - ``` - Do not leave a finished prompt lying in the repo -- a stale prompt is - indistinguishable from a pending one, and the next session will re-run it. - -2. **Log completion in the canonical index**, in `~/src/utils` (a *different* repo, - so it needs its own commit): - ```bash - cd ~/src/utils - # append to the "Completion log" table in dopamine-ux/00-INDEX.md: - # | 09-wake-alarm.md | DONE | | | - git add dopamine-ux/00-INDEX.md - git commit -m "dopamine-ux: mark 09-wake-alarm.md done" - git push - ``` - -If you finish only part of the prompt, do **neither** -- instead edit this file -to strike out what is done and state what remains, so the next session starts -from the true state. Partial completion must never be recorded as DONE. - ---- - -Add motion and haptics to the wake-alarm phone app - -## findings (2, ranked by value over effort) - -1. **Setting an alarm gives no confirmation or haptic** — and since the real - alarm lives in another app entirely, confirming the handoff is the only - reassurance this app can offer. -2. **Zero motion, and the thinnest local theme in the fleet** — it lacks - `AppSpacing`/`AppRadius`/`AppTextSize`, so widgets copied from sibling apps - will not compile here. - -## what - -`~/src/wake-alarm/phone_app` is the smallest surface in this project: 12 Dart files, -a sync companion that sets a time, syncs it, and hands off to the system clock -app. It has **zero motion, zero haptics, zero audio, zero progress feedback** — -verified 2026-08-16. Its settings screen is a 56-line `StatelessWidget` with two -`ListTile`s and no state at all. - -Bring it up to the fleet's baseline: a confirmation the alarm was actually set, -motion tokens on its transitions, and a haptic on the one action that matters. - -**This app is deliberately last and deliberately small.** It also carries the -project's sharpest hazard — see `must not` about alarm audio. - -## where - -Repo: `~/src/wake-alarm`. Flutter app: `~/src/wake-alarm/phone_app` (**underscore**, not -`phone-app`). The repo root is a Python package; the Flutter app is only the -`phone_app/` subdirectory. - -Primary: -- `phone_app/lib/screens/home_screen.dart` — `_setPhoneAlarm()` ~:86-96 builds an - `AndroidIntent(action: 'android.intent.action.SET_ALARM', arguments: {HOUR, - MINUTES, SKIP_UI: false, MESSAGE: 'Wake Alarm'})` via `android_intent_plus`. - The `CircularProgressIndicator` is at ~:189. The only `Duration` in the whole - app is `.timeout(const Duration(seconds: 3))` ~:95 — **an intent timeout, not - animation. Do not tokenise it.** -- `phone_app/lib/screens/settings_screen.dart` — 56 lines, `StatelessWidget`, - `ListView` ~:21-53, `MaterialPageRoute` ~:30, :49. -- `phone_app/lib/services/sync_settings.dart` — holds **only** the GitHub token - in the keystore (`FlutterSecureStorage`, `_secureTokenKey = 'github_token'` - ~:31, `load()` ~:36, `save()` ~:61). There is no general app-preferences class. -- `phone_app/lib/ui/theme.dart` — local hand-copy, **no `design_system` - dependency**. `buildAppTheme()` ~:12, `AppStatusColors` ~:54. ⚠️ Unlike the - other apps it does **not** declare `AppSpacing`/`AppRadius`/`AppTextSize`, so a - widget copied from diet-guard or workout_app **will not compile here**. Wired at - `phone_app/lib/main.dart` ~:18. - -## must - -**Step 1 — motion + haptics (no new dependency).** - -- Add `HapticFeedback.mediumImpact()` when the alarm is successfully set — the - single most important action in the app. Fire it on the tap, not after the - intent round-trips. `HapticFeedback` is in `package:flutter/services.dart`; add - `` to - `phone_app/android/app/src/main/AndroidManifest.xml` if absent. -- Give setting the alarm a **clear confirmation**: which time was set, and that - the handoff to the system clock succeeded. Today the user gets a `_status` - string and a spinner. Since the actual alarm lives in another app, confirming - the handoff is the only reassurance this app can offer — make it unambiguous. -- Transcribe the motion tokens from prompt 01 into `phone_app/lib/ui/theme.dart`, - matching the existing hand-copy convention. Add `AppSpacing`/`AppRadius`/ - `AppTextSize` **only if** you need them; otherwise leave the file's shape alone. -- Apply motion tokens to the two `MaterialPageRoute` transitions. -- Honour `MediaQuery.of(context).disableAnimations`. - -**Step 2 — sound (optional here; consider skipping).** - -- A UI confirmation cue would need an audio dependency, an `assets:` block, a - settings toggle, **and** a preferences class that does not exist yet (see - below). For an app whose entire job is to hand off to another app, that is a - poor value ratio. -- **Recommendation: skip sound in this app** and say so explicitly in the session - summary. If you do add it, it needs the full opt-out toggle like everywhere - else — and the toggle work below. -- To add any toggle here you must do three things the other apps do not require: - (a) convert `SettingsScreen` from `StatelessWidget` to `StatefulWidget`, - (b) create a preferences class — there is no `AppSettings` equivalent; model it - on `~/src/todo/lib/data/app_settings.dart`, and note `shared_preferences: ^2.3.0` - is **already a dependency**, (c) add the `SwitchListTile` to the `ListView`. - -**Both steps:** - -- must not: **touch anything under `~/src/wake-alarm/wake_alarm/`.** That is the - desktop Python daemon that produces the real alarm noise — sine-tone WAVs via - `paplay` → `aplay` → `speaker-test` (`_audio.py`, `_play_on_all_sinks` ~:218, - pcspkr evdev fallback `_beep_pcspkr` ~:81), escalating 440Hz → 1000Hz → loud in - the loop at `_alarm.py` ~:393-407, with sink volume save/restore in `_sinks.py`. - **Never route a UI-sound opt-out through any of it.** A toggle that silences a - wake-up alarm is a bug that makes someone late for work. -- The two systems never share a process, package, or file — `phone_app` has no - audio engine at all — so a UI sound layer here **structurally cannot** touch - alarm playback. Keep it that way; do not build a bridge between them. -- must not: change the alarm-setting intent, its arguments, or the 3s timeout. - Feedback wraps that call; it does not modify it. -- must not: add a streak, a counter, or any reward for setting an alarm. Waking - up is not a metric this app owns, and rewarding "alarms set" rewards the wrong - act entirely. -- must not: copy a widget from another app without checking it only uses symbols - this app's thinner theme actually declares. - -## done - -1. Setting an alarm produces a haptic and an unambiguous confirmation naming the - time that was set. -2. Page transitions use the shared motion tokens; no inline animation `Duration` - remains (the 3s intent timeout stays). -3. `cd ~/src/wake-alarm/phone_app && flutter analyze` is clean. -4. `cd ~/src/wake-alarm/phone_app && flutter test` passes. -5. With OS "remove animations" enabled, the app works and durations are zero. -6. `git diff` shows **no changes under `~/src/wake-alarm/wake_alarm/`**. -7. The summary states whether sound was added or deliberately skipped. - -## verify - -**On the phone.** - -``` -adb devices # confirm 23181JEGR08034 -cd ~/src/wake-alarm/phone_app -flutter build apk --release -adb install -r build/app/outputs/flutter-apk/app-release.apk -``` - -Never `flutter install`, never `adb uninstall`, never `pm clear` — the app stores -a GitHub token in the keystore and wiping it means re-authenticating. - -Then set a real alarm on the device: confirm the haptic fired (state it as a -physical observation), the confirmation named the right time, and **the system -Clock app actually received the alarm**. The last one is the real test — this -app's job is the handoff, so verify the alarm exists in the Clock app, not just -that this screen said so. - -Do **not** test by letting an alarm actually fire unless kuhy asks — that -involves the desktop daemon and real noise. - -## read first - -- `phone_app/lib/screens/home_screen.dart` — `_setPhoneAlarm()` in full, - including the timeout and the `_status` string handling. -- `phone_app/lib/ui/theme.dart` — note what it does **not** declare before - writing any widget. -- `~/src/todo/lib/data/app_settings.dart` — the preferences-class pattern, only if - you decide to do step 2. -- `~/src/utils/unified-design-system/motion.md` — vocabulary from prompt 01. - **Prompt 01 must have run first.** - -## context you would otherwise rediscover - -- **The Flutter app produces no audio whatsoever.** No audio package, no - `assets:` block; `assets/` contains only launcher icons. It fires an Android - `SET_ALARM` intent and the **system Clock app** rings. The desktop Python - daemon is an entirely separate program on a different machine. -- The repo root (`~/src/wake-alarm/wake_alarm/`, `wake_alarm.egg-info`) is the Python - package. Only `phone_app/` is Flutter. -- This app has **no `design_system` dependency** and the thinnest local theme in - the fleet. Adding the dependency is out of scope here (see prompt 07 for what - that migration looks like when done properly). -- No streaks, no charts, no progress, no completion counts exist — and none - should be added. This is a two-button utility. - -REMOVE ME AFTER FINISH