docs: remove references to the source app and recording

Prepare for open-sourcing: scrub the prior-art attribution from the spec,
agent guide, and code comments so the project documents its own behavior.

- Reword RULES_FEATURE_SPEC.md to describe OpenAppLock's rules feature
  directly (drop the screen-recording source line and "as observed"/
  "not demoed"/"as shown" framing)
- Replace "the reference app/UI/style/defaults" comments and test names
  with direct descriptions of the behavior
- No behavior change; comments, docs, and @Test display names only

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-13 22:23:14 -04:00
parent 32b1694e0a
commit d005ed4fb1
13 changed files with 52 additions and 56 deletions

View File

@@ -1,9 +1,8 @@
# OpenAppLock — "Rules" Feature Spec (derived from Opal screen recording)
# OpenAppLock — "Rules" Feature Spec
Source: `ScreenRecording_06-12-2026 11-26-19_1.MP4` (iPhone, 4:29). The rules feature
appears roughly between 1:003:00 of the recording, on Opal's "My Apps" tab.
This spec describes what was observed, then maps it onto an implementation plan
for OpenAppLock.
This spec describes OpenAppLock's recurring app-blocking **rules** feature: the
behavior the app implements, then how it maps onto the native iOS presentation
(see §6).
---
@@ -11,13 +10,13 @@ for OpenAppLock.
A **Rule** is a recurring, automated app-blocking policy. Unlike a one-off
block/timer session, a rule re-arms itself on a schedule. Three rule types are
offered (Opal's "New Rule" sheet):
offered, presented on the "New Rule" sheet:
| Type | Icon | Example shown | Semantics |
|------|------|---------------|-----------|
| **Schedule** | calendar grid | "e.g. 9-5, Daily" | Block selected apps during a daily time window on chosen days |
| **Time Limit** | hourglass | "e.g. 45m/day" | After N minutes of cumulative use of selected apps per day, block them until a reset point |
| **Open Limit** | padlock | "e.g. 5 opens/day" | After N opens of selected apps per day, block them (not demoed in video; inferred from card) |
| **Open Limit** | padlock | "e.g. 5 opens/day" | After N opens of selected apps per day, block them |
**Common attributes** — present for *every* rule kind:
@@ -28,7 +27,7 @@ offered (Opal's "New Rule" sheet):
independently of any rule. When editing a rule the user picks an existing
list or creates a new one; editing a list affects every rule that uses it.
Deleting a list detaches it from its rules (they fall back to "no apps").
- **Hard Mode** — boolean, PRO-gated in Opal; subtitle "No unblocks allowed". When off, the rule detail shows "Unblocks allowed: Yes"
- **Hard Mode** — boolean; subtitle "No unblocks allowed". When off, the rule detail shows "Unblocks allowed: Yes"
- **Enabled/disabled** — a rule can be disabled without deleting ("Disable Rule")
**Per-kind options** — each kind carries only the options that make sense for
@@ -87,10 +86,10 @@ Dark theme throughout (near-black background, very dark green tint).
2. **Blocked Apps** — section header; horizontal row of currently-blocked app
icons. Each icon has a lock badge overlay and a teal/green rounded-rect
outline; caption "Unblock" under the icon. Tapping unblocks (with friction
if hard mode — not demoed).
if hard mode).
*(OpenAppLock)* Time/Open Limit rules whose budget is spent for the day
also appear here, blocked until midnight.
3. **Usage** *(OpenAppLock addition — not in the Opal video)* — a section
3. **Usage** *(OpenAppLock addition)* — a section
showing live tracking for every enabled Time/Open Limit rule scheduled today
**that is not currently blocking**. Each row leads its subtitle with the rule
**type** so the kind is clear without relying on the icon:
@@ -175,8 +174,7 @@ Sections (each an inset rounded group with a small icon + caption header):
1. **📅 During this time**
- Rows `From` / `To` with right-aligned time + stepper chevrons (`09:00 ⌃⌄`).
- A dotted vertical line with ●/○ endpoints visually links From → To.
- Tapping a row expands an inline wheel time picker (24h, demoed changing
From 22:00 → 23:00).
- Tapping a row expands an inline wheel time picker (24h).
2. **On these days:** — trailing summary label ("Weekdays"/"Weekends"/custom);
row of 7 circular toggles `S M T W T F S`; selected = filled white circle
with black letter, unselected = dark circle.
@@ -188,8 +186,8 @@ Sections (each an inset rounded group with a small icon + caption header):
blocked" / "Only these apps are allowed" accordingly.
4. **Hard Mode** `⚡PRO` badge — subtitle "No unblocks allowed"; trailing
toggle.
5. **Block Adult Content** *(OpenAppLock addition — not in the Opal video;
**Schedule rules only**)* — subtitle "Filter adult websites while this rule
5. **Block Adult Content** *(OpenAppLock addition; **Schedule rules only**)* —
subtitle "Filter adult websites while this rule
is active"; trailing toggle. Maps to Screen Time's web-content filter
(`ManagedSettingsStore.webContent.blockedByFilter = .auto(...)`), applied
and cleared together with the rule's shield. Surfaces in the rule detail
@@ -217,7 +215,7 @@ Same chrome (back / title / rename). Sections:
### 3.6 Rule Editor — Open Limit type
Not demoed beyond its card. Spec by analogy: "When I open [apps]" /
Spec by analogy with the other editors: "When I open [apps]" /
"More than `N opens ⌃⌄` (Daily)" / day picker / "Then block until …" /
Hard Mode / Hold to Commit. *(No Block Adult Content toggle — Schedule-only.)*
@@ -243,11 +241,10 @@ Full-height sheet:
letting users add arbitrary domains.
- Footer: "**N Apps Selected**" caption + white pill "**Save**" (+ "Cancel").
> Implementation note: Opal ships its own app categorization. On iOS, third
> parties cannot enumerate installed apps; the system-sanctioned route is
> `FamilyActivityPicker` (FamilyControls), which provides its own
> category/app/website UI and returns opaque tokens. **v1 of OpenAppLock should
> embed `FamilyActivityPicker`** instead of cloning Opal's custom picker.
> Implementation note: On iOS, third parties cannot enumerate installed apps;
> the system-sanctioned route is `FamilyActivityPicker` (FamilyControls), which
> provides its own category/app/website UI and returns opaque tokens. **v1 of
> OpenAppLock embeds `FamilyActivityPicker`** rather than a custom app picker.
>
> **App Lists (OpenAppLock):** the selection itself lives on a reusable
> **App List** (`@Model AppList`: name + encoded `FamilyActivitySelection`).
@@ -305,11 +302,11 @@ Full-height sheet:
(which lists only rules whose budget is exhausted); it shows under "Usage"
with its remaining opens.
5. **Disable vs delete** — "Disable Rule" pauses scheduling but keeps the
rule (card presumably shows disabled state). No delete flow was shown;
add delete via swipe/long-press or a button in the editor.
rule (the card shows a disabled state). Delete is offered from the rule
editor's actions menu.
6. **Commit friction** — creating/committing a rule uses press-and-hold
("Hold to Commit"), echoing Opal's philosophy that *starting* a commitment
should be deliberate. Editing uses a plain "Done".
("Hold to Commit"), making the *start* of a commitment deliberate. Editing
uses a plain "Done".
7. **Live countdowns** — "Starts in 22h" / "6h left" update over time
(minute granularity is fine).
8. **Overlapping rules — strictest enforcement wins.** When several rules
@@ -503,20 +500,20 @@ Xh", "Xh left") is **derived**, not stored.
- All shared logic lives in `Shared/` (notably `LimitEnforcement`), unit
tested from the app test target.
### 5.6 Out of scope (seen in video, not part of "rules")
### 5.6 Out of scope (not part of "rules")
- Onboarding flow, paywall ("You know Opal works. Make it permanent."),
Home tab gem/score UI, Timer tab (one-off focus sessions, "Leave Early?"
friction screen), notification nudges ("Complete Your Setup").
- Onboarding flow, paywall, Home tab gem/score UI, Timer tab (one-off focus
sessions, "Leave Early?" friction screen), notification nudges ("Complete
Your Setup").
---
## 6. Native UI re-skin (current presentation)
OpenAppLock has since replaced the Opal-style custom presentation with the bare
OpenAppLock has since replaced its custom themed presentation with the bare
iOS design language, keeping the backend (models, logic, services), the
flows, and the accessibility identifiers intact. Sections 15 remain as the
reference for *what* the feature does; presentation now maps as follows.
spec for *what* the feature does; presentation now maps as follows.
After onboarding the app is a three-tab `TabView` (`MainTabView`), each tab its
own `NavigationStack`: