testsAndMisc/docs/superpowers/contracts/focus-owner-enforcement-engine-2026-08-09.json
Krzysztof kuhy Rudnicki 1b7958143d Prove DPM app-hiding survives a reboot; build the enforcement decision layer
The whole Device Owner design assumed setApplicationHidden persists across a
reboot, and that had never been tested -- while both shell primitives were
measured to be cleared by one. Settling it looked like it needed a factory
reset. It does not: a managed profile is removable and takes its profile-owner
grant with it, so the DPM API can be exercised and then erased.

  pm create-user --profileOf 0 --managed   -> user 10
  dpm set-profile-owner --user 10 ...
  ... hide, reboot, re-check ...
  pm remove-user 10

hidden=true before the reboot, hidden=true after, agreed by dumpsys and by the
DPM API itself. Afterwards: Device Owner Type -1, no restrictions, and Chrome
in user 0 untouched.

Scope limit, stated because it is easy to overclaim: this proves the API's
hidden state persists under PROFILE OWNER inside a work profile. It does not
prove a DEVICE OWNER can hide a given app in user 0, which is what the design
actually needs -- DO there additionally cannot touch the launcher, the default
dialer/SMS/IME or packages the system deems critical, and the call can return
false silently. That must be tested in the first minute after provisioning,
while clearDeviceOwnerApp() is still a cheap exit.

On top of that, EnforcementDecision turns policy plus conditions into a
hide/show set. It is a pure function, so the whole decision layer is tested
without a device, a clock or a location provider.

packagesToShow is deliberately the complete allowed set rather than a delta.
Failing to hide something is a mild disappointment; failing to UNHIDE strands
the user without a dialer or a bank at 09:00 because the phone rebooted during
curfew. Applying the full set on every evaluation makes a missed run
self-repairing, which matters because BOOT_COMPLETED does not fire until first
unlock -- observed directly, the phone sat at RUNNING_LOCKED for minutes after
a reboot with no network at all.

The workout exception is expressed as packages rather than domains. The rooted
system unblocked youtube.com in a hosts file; hiding an app cannot target a
domain, so the package set is derived from the configured domains and config.sh
stays the source of truth for intent.

Signal sources were checked on the device before being built: StrongLifts is
granted health.WRITE_EXERCISE and Health Connect is installed, so that path is
viable; com.kuhy.workout_app exposes only a MainActivity and Flutter
boilerplate; org.runnerup is not installed here at all. Only the two that can
actually produce a signal will be wired.

HideTestReceiver is temporary and must be deleted before any provisioned build.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AwepyL5Lxs5QKbKkMpxxxL
2026-08-09 21:36:26 +02:00

25 lines
2.1 KiB
JSON

{
"title": "Prove DPM app-hiding persists, and build the enforcement decision layer on it",
"objective": "The Device Owner design rests on setApplicationHidden surviving a reboot, which had never been tested - both shell primitives were measured to be cleared by one. Prove or disprove that WITHOUT spending a factory reset, then build the decision layer that turns the parsed policy plus current conditions into a hide/show set. Success is a measured persistence result with its scope stated honestly, and a pure, fully tested decision function.",
"acceptance_criteria": [
"setApplicationHidden persistence measured across a real reboot, using a removable managed profile so no wipe is spent",
"The test profile and its profile-owner grant are removed afterwards, with user 0 verified untouched",
"The result is recorded with its scope limit: profile owner in a work profile is NOT device owner in user 0",
"EnforcementDecision is a pure function of its inputs - testable with no device, clock or location provider",
"packagesToShow is always the complete allowed set rather than a delta, so a missed run self-repairs",
"Unknown location enforces rather than releasing, matching focus_daemon.sh",
"A policy with redacted coordinates still enforces rather than reading as always-away",
"Geofence hysteresis prevents flapping between radius and radius+hysteresis",
"The workout exception releases the YouTube packages and nothing else",
"Workout signal sources are verified on-device before being built, not assumed"
],
"out_of_scope": [
"Device Owner provisioning and the factory reset - unchanged, still not done",
"The foreground service, BOOT_COMPLETED receiver and alarm scheduling - next step",
"DNS filtering, which remains parked",
"com.kuhy.workout_app as a signal source: verified to expose nothing readable",
"org.runnerup: not installed on this device"
],
"verifier": "pm create-user/dpm set-profile-owner + adb reboot + dumpsys package, then pm remove-user and re-check user 0; cd focus_owner && flutter analyze && flutter test"
}