Move TODOs to todo app

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Krzysztof Rudnicki 2026-11-02 11:14:40 +01:00
parent 58c4260b6e
commit 5525ca6f95
4 changed files with 0 additions and 378 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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/pcmC<N>D0p` 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.

View File

@ -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 <YYYY-MM-DD> | <impl commit sha> | <one-line note> |
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
`<uses-permission android:name="android.permission.VIBRATE"/>` 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