testsAndMisc/docs/superpowers/contracts
Krzysztof kuhy Rudnicki 82e206116a
Some checks are pending
Pre-commit checks / pre-commit (push) Waiting to run
Python tests / test (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Make the geofence tell the truth, and the phone explain itself
The enforcer failed in both directions: nothing blocked at home, and
everything blocked at the office. The comparison was never inverted --
`metres <= threshold` was always right. Three separate causes:

Only ACCESS_COARSE_LOCATION was declared. Android 12+ fuzzes coarse to a
~1-2 km grid against a 150 m fence, so a fix taken at home routinely landed
outside it, read as AWAY, and restored every app the geofence exists to hide.
FINE is now declared and self-granted by the device owner, along with coarse
and background, re-asserted every pass so a reinstall cannot silently drop it.

There were three states but two behaviours. LOCATION_UNKNOWN applies the
identical sweep to AT_HOME -- correct fail-closed design, indistinguishable
from outside. And nothing ever requested a fix: the pass read whatever another
app happened to cache, so at the office with no navigation running the cache
was empty. Passes now acquire a fix inside a location-typed foreground
service, bounded at 20 s, and treat anything older than 30 min as no fix. That
window is deliberately longer than the 15-minute cadence; a shorter one marks
the newest cache stale on every pass of an idle phone and blocks everything.

None of it was diagnosable. `adb logcat -d -s FocusOwner:V` came back empty
while dumpsys showed 82 alarms had fired, and `run-as` is refused on the
release build device owner requires. So the pass now writes a ring-buffered
JSONL record read back in-app: reason, distance vs the fence, fix
age/provider/accuracy, curfew state, and every hidden app with the rule that
hid it. Coordinates are never recorded -- a distance is enough to debug a
geofence, and this is a home address.

Also fixed along the way:

- Hysteresis keyed off `isEnforcing`, which is true under AWAY too because
  YouTube stays hidden, so the threshold was permanently radius+hysteresis.
  It now keys off whether the previous pass was inside the fence.
- The scheduler's curfew-boundary alarms were documented but never scheduled;
  both callers invoked `scheduleNext()` bare, so 05:00 could land 15 min late.
- Installing over the app cancelled its pending alarms, so `adb install -r`
  silently stopped enforcement until someone opened the app. MY_PACKAGE_REPLACED
  now re-arms it, verified on device without launching the app.
- A wrong-typed log record threw instead of being skipped, and the exception
  escaped far enough to leave the page stuck busy -- which disables the
  release-device-owner button, the one control that must work when everything
  else has gone wrong.
- `lib/enforcement.dart` was a second decision layer with no always-blocked
  concept, cited by KDoc as pinned by a `PolicyParityTest` that never existed.
  It would have made the new screen report YouTube visible while it is hidden.
  Deleted; the UI renders the Kotlin record rather than re-deciding.
- Anchoring home accepted a stale or unknown-precision fix. A wrong home
  offsets the fence everywhere and forever, which is what produced a 766 m
  reading while standing at home.

Policy: Play Store is allowed by day (not during curfew) so infakt can be
installed and updated; the sweep is default-deny for third-party packages, so
anything installed from Play is hidden on the next at-home pass. Tachiyomi's
per-source extension apks are covered by a new prefix allowlist rather than an
exact list that goes stale whenever an extension is installed.

`export.py` stopped subtracting the allowlist from `blockable_system_packages`.
Sweepable is not hideable: that list decides which system packages are
eligible for a decision, and `isAllowed` is what protects them. Removing an
allowed system package from the sweep freezes it in its last state -- it would
have stranded Play hidden permanently the moment it was allowlisted.

Verified on the Pixel 6a: FINE granted POLICY_FIXED, `applied AT_HOME` with a
0 m distance from a +/-11 m GPS fix, YouTube/Chrome/Firefox absent from
`pm list packages -e`, Play Store, infakt, RunnerUp and all five Tachiyomi
packages present.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HjxL9kdAzZmGqQA5tMNrZ8
2026-08-14 13:43:05 +02:00
..
agent-automation-bootstrap.json style(prettier): apply markdown/json formatting updates 2026-05-07 22:08:00 +02:00
android-ui-element-driver-2026-08-10.json Add android_ui: drive Android apps by element, never by coordinates 2026-08-10 17:01:28 +02:00
app-icons-generator-2026-07-19.json Add shared launcher-icon generator for the Flutter apps 2026-07-19 16:55:48 +02:00
archwiki-rag-corpus-2026-07-19.json archwiki_rag: offline semantic search over the Arch Wiki 2026-08-10 15:33:18 +02:00
billsplit-apk-buildable-2026-08-03.json billsplit: build a real APK by dropping file_picker for file_selector 2026-08-03 14:15:40 +02:00
billsplit-move-2026-08-03.json Move billsplit Flutter app into the monorepo 2026-08-03 12:22:22 +02:00
brother-printer-file-length-split-2026-07-17.json fix(brother-printer): split oversized files, fix order-dependent entry test 2026-07-17 15:06:25 +02:00
brother-printer-status-accuracy-2026-07-17.json fix(brother-printer): report the truth, not invented status codes 2026-07-17 14:49:23 +02:00
bucket-catch-2026-06-27.json Add bucket_catch: osu!catch browser game with 100% frontend test coverage 2026-06-27 12:21:35 +02:00
byox-ladder-2026-07-17.json feat(byox_ladder): add build-your-own-x difficulty ladder generator 2026-07-17 18:31:21 +02:00
cloud-gallery-2026-07-12.json cloud_gallery: React media-gallery SPA served by dufs (Phase 3) 2026-07-12 06:05:52 +02:00
cloud-gallery-coverage-lint-deploy-2026-07-12.json cloud_gallery: fix build, 100% coverage, aggressive lint; whitelist dufs_client 2026-07-12 17:29:39 +02:00
code-tutor-2026-07-10.json Add code_tutor: interactive codebase-learning CLI 2026-07-11 00:15:46 +02:00
diet-guard-gatelock-migration-2026-06.json Migrate diet_guard to the shared gatelock backend 2026-06-21 18:16:45 +02:00
diet-guard-meal-and-trigger-fix-2026-06-10.json feat(diet_guard): add meal-logging screen-lock gate with trigger fix 2026-06-10 22:32:39 +02:00
digital-wellbeing-bypass-hardening-2026-05.json security: harden digital-wellbeing bypass vectors 2026-05-16 15:41:40 +02:00
dns-filtering-parked-2026-08-05.json Park phone DNS filtering: Private DNS fails closed, so the PC cannot host it 2026-08-05 10:05:16 +02:00
dot-resolver-and-policy-asset-2026-08-05.json Serve the blocklist over DoT and hand the policy to the app as an asset 2026-08-05 09:36:11 +02:00
epopeja-karta-icon-2026-08-03.json app_icons: finish the epopeja_karta entry; whitelist it on the phone 2026-08-03 12:41:13 +02:00
extract-dufs-cloud-repo-2026-07-12.json Extract dufs cloud (web + app + scripts) to github.com/kuhyx/dufs-cloud 2026-07-12 18:38:37 +02:00
extract-inline-python-2026-06-06.json refactor: extract all inline Python from shell scripts into proper .py files 2026-06-06 10:31:48 +02:00
extract-session-autopsy-2026-07-26.json Point the hook test at the extracted session_autopsy, add the artifacts 2026-07-26 20:50:44 +02:00
file-length-split-2026-06-14.json feat: split oversized modules for 500-line limit, fix kasa coverage gap 2026-06-14 07:19:37 +02:00
focus-mode-daemon-file-length-2026-07-17.json fix(wellbeing): split focus_mode_daemon to satisfy the 500-line limit 2026-07-17 17:36:30 +02:00
focus-owner-decision-wiring-2026-08-09.json Wire the enforcement decision to the DPM hide call 2026-08-09 22:00:52 +02:00
focus-owner-enforcement-engine-2026-08-09.json Prove DPM app-hiding survives a reboot; build the enforcement decision layer 2026-08-09 21:36:26 +02:00
focus-owner-geofence-and-observability-2026-08-14.json Make the geofence tell the truth, and the phone explain itself 2026-08-14 13:43:05 +02:00
focus-owner-location-and-workout-2026-08-09.json Provision home coordinates out of git; layer the workout signal; drop the test hook 2026-08-09 21:42:20 +02:00
focus-owner-restore-path-2026-08-09.json focus_owner: keep the unhide path reachable, never hide the enforcer 2026-08-10 15:33:18 +02:00
focus-owner-service-layer-2026-08-09.json Run enforcement from exact alarms, and re-arm it before first unlock 2026-08-09 21:50:58 +02:00
geofenced-allowlist-rewrite-2026-08-11.json Block by hiding apps, which the phone cannot undo 2026-08-11 19:49:11 +02:00
guard-lib-migration-2026-07-04.json feat: migrate hosts-guard and shutdown-schedule-guard to guard-lib 2026-07-04 11:54:08 +02:00
i3bar-claude-usage-icons-cleanup-2026-08-10.json i3blocks: add Claude usage block, fix icon rendering, drop dead blocks 2026-08-10 15:14:34 +02:00
import-media-archives-2026-07-12.json import_media_archives.sh: fold Downloads media_archive zips into the cloud 2026-07-12 17:43:23 +02:00
kcd2-balatro-single-joker-face-2026-07-25.json kcd2_dice_solver: Balatro's die has one joker face, not six 2026-07-25 16:14:04 +02:00
kcd2-dice-solver-deploy-responsive-io-2026-07-26.json kcd2 dice solver: serve it at dice.kuhy.duckdns.org, fit all 43 dice, move inventories between devices 2026-07-26 20:01:21 +02:00
kcd2-dice-solver-initial-commit-2026-07-21.json Track kcd2_dice_solver app and add run.sh dependency installer 2026-07-21 18:17:13 +02:00
keepass-multidevice-sync-2026-07-12.json linux_configuration: unified multi-device KeePass sync over dufs 2026-07-12 05:00:27 +02:00
linux-config-cleanup-2026-05.json refactor(linux_configuration): move remaining dirs + scripts/ to meta/ 2026-05-15 00:53:01 +02:00
linux-config-polling-hardening-2026-05-14.json fix(linux_configuration): harden polling/runtime scripts and add tests 2026-05-14 19:55:42 +02:00
linux-config-runtime-hardening-2026-05-08.json Harden runtime script deployment and enforce installer safety 2026-05-08 17:44:22 +02:00
linux-config-scripts-split-2026-05.json refactor(linux_configuration/scripts): split all scripts into single_use/ and periodic_background/ 2026-05-15 00:32:35 +02:00
makepkg-stale-lock-wrapper-2026-07-16.json fix(pacman): wrap makepkg so an orphaned db.lck can't hang makepkg -i 2026-07-17 07:46:31 +02:00
mandatory-hooks-2026-08-03.json fix(hooks): make git hooks and their toolchain mandatory and fail-closed 2026-08-03 11:09:11 +02:00
media-cloud-sync-2026-07-12.json linux_configuration: move Downloads media into the dufs cloud (browsable) 2026-07-12 05:19:31 +02:00
morning-routine-unified-2026-05-25.json morning_routine: unified alarm+lock orchestrator, fix alarm audio/reliability 2026-05-25 18:55:27 +02:00
mtk-root-toolkit-2026-08-04.json mtk_root: build the rooting toolkit before the phone lands 2026-08-04 20:38:44 +02:00
pacman-hook-stall-2026-08-03.json Diagnose the pacman first-hook stall; fix the drift that hid a stale wrapper 2026-08-03 15:15:34 +02:00
pc-polling-runtime-validation-2026-05-10.json Optimize polling/runtime scripts, add regressions, and sync verification artifacts 2026-05-10 02:58:11 +02:00
persistent-adb-2026-08-03.json phone_focus_mode: reach the phone over adb without touching it 2026-08-03 13:33:45 +02:00
phone-curfew-demo-net-stopgap-2026-06-13.json feat(phone_focus_mode): add on-demand demo curfew + netd-resistant net stopgap 2026-06-13 22:01:32 +02:00
phone-focus-cpu-hardening-2026-07-10.json Harden phone_focus_mode CPU use; whitelist wake_alarm_sync 2026-07-11 00:16:11 +02:00
phone-focus-mode-fresh-install-2026-05-31.json feat(phone): automate BL-9000 fresh-phone recovery after factory reset 2026-05-31 16:22:49 +02:00
phone-focus-mode-netd-cache-fix-2026-05.json phone_focus_mode: fix YouTube DNS blocking via netd cache restart 2026-05-22 15:58:36 +02:00
phone-night-curfew-2026-06-13.json feat(phone_focus_mode): add night curfew (23:00-05:00 at-home strict allow-list) 2026-06-13 16:48:38 +02:00
protondb-gold-silver-fix.json fix: accept ProtonDB gold+silver combinations; add explicit skip reasons 2026-05-08 20:31:16 +02:00
pylint10-r0801-schema-validation-2026-06.json feat: split oversized modules for 500-line limit, fix kasa coverage gap 2026-06-14 07:19:37 +02:00
reverse-survivors-2026-08-03.json feat(reverse_survivors): migrate Reverse Survivors game into the monorepo 2026-08-03 10:45:12 +02:00
reverse-survivors-difficulty-tiers-2026-08-09.json reverse_survivors: difficulty tiers 2026-08-09 23:17:07 +02:00
reverse-survivors-director-powers-2026-08-09.json reverse_survivors: director powers — ambush, frenzy, rift 2026-08-09 23:10:38 +02:00
reverse-survivors-gameplay-extension-2026-08-09.json reverse_survivors: add splitter, artillery, warden and the leech boss 2026-08-09 23:06:20 +02:00
reverse-survivors-status-effects-2026-08-09.json reverse_survivors: survivor status effects (slow, suppress, bleed) 2026-08-09 23:08:51 +02:00
root-cleanup-2026-05-14.json chore: spring-clean repo root (move docs, relocate batch3 script, drop stale outputs) 2026-05-14 20:01:09 +02:00
run-sh-wrapper-smoke.json style(prettier): apply markdown/json formatting updates 2026-05-07 22:08:00 +02:00
screen-locker-scheduled-skip-2026-05.json screen_locker: add scheduled-skip date mechanism + hibernate on alarm nights 2026-05-22 16:00:15 +02:00
screen-locker-sick-tracker-2026-05-14.json feat(screen-locker): add sick-day tracker and commitment debt flow 2026-05-14 19:52:15 +02:00
screen-locker-weekly-check-2026-05-28.json screen_locker: add weekly check feature with UI integration 2026-05-28 07:04:18 +02:00
session-autopsy-package-2026-07-25.json python_pkg: track session_autopsy, finishing its interrupted refactor 2026-07-25 16:56:43 +02:00
session-autopsy-turn-efficiency-2026-07-26.json session-autopsy: measure turn efficiency, the dominant token cost 2026-07-26 19:29:25 +02:00
shell-tests-arch-container-2026-07-19.json Run Arch-only shell tests in a container; harden worktree stubbing 2026-07-19 19:27:36 +02:00
shellcheck-ci-green-2026-08-04.json Fix the 11 shellcheck findings that kept CI red since b83ce5d 2026-08-04 20:55:02 +02:00
shellcheck-strict-gate-2026-08-03.json Fail the build on any shellcheck finding; fix the 222 the old gate hid 2026-08-03 19:49:11 +02:00
shutdown-override-i3blocks-sync-2026-07-10.json feat(digital-wellbeing): time-boxed shutdown overrides + drift-proof i3blocks deploy 2026-07-10 21:57:05 +02:00
stats-hltb-fixes-2026-05-28.json steam_backlog_enforcer: fix stats command — show real Rush/Leisure/Worst data 2026-05-28 07:02:48 +02:00
steam-backlog-cache-refetch-reduction-2026-05-08.json steam_backlog_enforcer: reduce repeated cache refetches 2026-05-08 15:13:25 +02:00
steam-backlog-finished-only-next-pick-2026-05.json steam_backlog_enforcer: only prompt next pick after game is finished 2026-05-23 21:19:44 +02:00
steam-backlog-module-split-2026-05.json Split modules, fix tests, fix pre-commit batching 2026-05-22 22:48:28 +02:00
steam-backlog-protected-ids-2026-05-14.json feat(steam-backlog): protect four additional Steam app IDs 2026-05-14 19:58:40 +02:00
steam-backlog-whitelist-hardening-2026-05.json feat(steam_backlog_enforcer): harden whitelist against circumvention 2026-05-17 20:44:05 +02:00
steam-library-hide-fix-2026-05-17.json steam_backlog_enforcer: fix library_hider crash on invalid AppIDs + improve HLTB hour extraction 2026-05-22 15:59:18 +02:00
sync-tests-fix-coverage-2026-05.json fix: sync test paths, drop stale assertions, fix coverage gap 2026-05-16 15:46:02 +02:00
syncyomi-library-recovery-2026-08-09.json syncyomi_guard: refuse a collapsed payload as the new good copy 2026-08-10 15:33:18 +02:00
template.json style(prettier): apply markdown/json formatting updates 2026-05-07 22:08:00 +02:00
tether-enforcer-hotspot-bypass-2026-07-13.json phone_focus_mode: block hotspot/tethering to close the second-phone bypass 2026-07-13 10:48:59 +02:00
unrooted-focus-mode-policy-and-owner-app-2026-08-05.json Make focus policy and blocklist usable without root; fix workout CDN unblock 2026-08-05 09:15:02 +02:00
usage-report-hz-cpu-fix-20260604.json fix(usage_report): stop charging atop's HZ field as CPU; bundle since-last-report mode 2026-06-04 18:13:47 +02:00
vendor-agent-skills-import.json chore(third_party): vendor agent-skills snapshot 2026-05-07 22:06:00 +02:00
wake-alarm-gatelock-migration-2026-06-22.json Migrate wake_alarm to the shared gatelock backend 2026-06-22 07:33:49 +02:00
wake-alarm-hibernate-2026-05.json wake_alarm + midnight_shutdown: hibernate on alarm nights instead of poweroff 2026-05-22 16:01:04 +02:00
wake-alarm-loudness-typeable-2026-05.json wake_alarm: louder + typeable + multi-fan 2026-05-24 16:20:34 +02:00
wake-alarm-plug-fans-warnings-2026-05.json wake_alarm: Tapo P110 plug control, fan ramp via sudo, loud warnings 2026-05-23 19:51:26 +02:00
wake-alarm-refactor-2026-05-30.json refactor: split wake_alarm modules, fix ruff violations, enforce global coverage 2026-05-30 22:13:32 +02:00
wake-alarm-restore-display-test-gap-2026-06-22.json Fix the real cause of the wake_alarm CI coverage gap 2026-06-22 09:14:29 +02:00
wsg-grabber-2026-07-27.json wsg_grabber: scrape /wsg/, download every new video, triage with keep/pass 2026-07-27 14:55:30 +02:00