Signals
User, setup, progress, usage, rule, sleep, immediate context, and local lifecycle.
Current system → completion system
Opal Home uses a deterministic, on-device ranker with a tiny live suggestion set, a soft anti-repeat bonus, and routes that mostly open a destination. It can surface the right idea—then stop before the user makes the promised change.
Eligible suggestion candidates
01 · Current stack
The visible screen is explicit SwiftUI composition. Gemstones and score are fixed shell elements; the feed ranker fills top and supporting lanes, with an optional inline module inserted between them.
Gemstones have their own progress ordering. The score follows as shell content; neither competes in card ranking.
Top admits at most two; supporting admits at most three and does not borrow unused top capacity. Ranked total is five.
The suggestion family cap is one. It prevents simultaneous suggestion clutter, but it does not create rotation over time.
Top Today is passive, cap-exempt, non-dismissible, and excluded from lifecycle accounting. It can make the 2 + 3 ranked stack visibly total six.
02 · Current algorithm
The ranker is stateless and side-effect-free. App glue builds a snapshot; policy orders and admits candidates; routing removes unwired winners; lifecycle updates only after cards become visible.
User, setup, progress, usage, rule, sleep, immediate context, and local lifecycle.
Unknown values suppress dependent cards. Eligible suggestions receive local points.
Urgent rule context, recovery, setup, then fresh and themed suggestions.
Demoted rules, streak or insight, Focus Report, remaining suggestions, fallback.
2 top, 3 supporting, 5 ranked total, 1 suggestion family card.
Cards without a wired destination are removed before render and display credit.
Record last shown, hides, milestones, insight kind, education, and process identity.
Suggestion score
Active hides are filtered before scoring. The ~2-day rule is a bonus, not a hard cooldown: a recently seen card can still win when the eligible pool is small.
Suggestion catalog reality
sleep.trouble
Bedtime-window suggestion; alternates Sleep Stories and Meditations.
Live providerfocus.no_unblocks
Fresh at 2+ weekly unblocks when an active session rule allows unblocks.
Live providerrest.digital_detox
Available after seven known install days; routes to the Timer tab.
Live providerfocus.allow_list
Route exists, but the live provider does not populate its required rule signal.
Signal-darkfocus.open_budget
Route exists, but top-app opens are not wired into the current snapshot.
Signal-darksleep.improve
Cataloged, but explicitly deferred by ranking policy.
Deferredsleep.no_phone_morning
Cataloged, but explicitly deferred by ranking policy.
Deferredfocus.time_limit_social
Waiting for a complete creation destination.
Deferredfocus.study_session
Cataloged, but explicitly deferred by ranking policy.
Deferredfocus.brain_music
Waiting on its soundscape destination.
Deferred03 · Case study
Today’s card promises a stricter rule. Its CTA invokes the generic action hook and resolves the first active unblock-allowed session rule, but only opens that rule’s editor. The user must infer the change—and Home cannot know whether it happened.
Create bullet proof focus rules with no unblock allowed.
Running now · 9:00–17:00
Turn off unblocks for this rule. Review the exact change before applying it.
Workday Focus · Applies to future blocks
No unblocks are allowed while this rule is active. Everything else stayed the same.
target
Exact device-local rule instance—not “first matching rule” at navigation time.
lever
Typed change: unblock policy from non-strict to strict.
precondition
Revalidate rule exists, is editable, and still matches the promised before-state.
completion
Credit only after persistence succeeds and the fresh rule snapshot confirms the delta.
04 · Why suggestions repeat
Current ordering is deterministic and sensible for its inputs. Repetition emerges because the pool is small, identity is coarse, and a card tap is not connected to the state change that should retire that actionable instance.
Bedtime help, no-unblocks, and digital detox carry most of the production variety.
few eligible alternativesThe family cap prevents a stack of suggestions in one session; it does not spread exposure across days.
density control onlyMost suggestions have no durable identity for template × rule × lever, so one completion cannot retire one exact opportunity.
coarse historyRecently shown cards lose a bonus but remain eligible. A high fresh-signal score can still dominate.
soft anti-repeatMorning, day, evening, and night preferences help relevance, but they narrow an already shallow pool.
relevance without breadthAllow-list and open-budget signals are unavailable live; five more suggestion IDs remain deferred.
catalog ≠ live set05 · Prioritized improvements
More templates without better outcome semantics will create more doors into generic screens. Establish the action contract first, then expand levers, variety, and data.
Ship the no-unblocks commitment path end-to-end and make it the reference contract for every actionable suggestion.
Move from generic “modify” suggestions to small, reversible or clearly confirmed deltas on known rules.
Once actions close the loop, activate the broader catalog and use local, privacy-safe outcomes to improve selection.
Commitment UI anatomy
The flow should be narrower than the full rule editor. It explains why the suggestion appeared, names the exact rule, shows the material consequence, and makes confirmation deliberate without turning a recommendation into a scavenger hunt.
“You unblocked twice this week.”
“Workday Focus,” not an inferred rule.
Allowed becomes no unblocks allowed.
What becomes impossible, and when.
A specific “Confirm & apply” action.
Domain write, then fresh-state verification.
Name the applied rule and unchanged parts.
Retire this exact rule-lever instance.
06 · Weekday morning
Same local signal, same Monday morning. The difference is whether the system treats a suggestion as a destination link or as a state transition with an observable end.
Workday allows unblocks; weekly count reaches two.
focus.no_unblocks scores fresh and preferred.
User sees the running rule and leaves without finding the lever.
The same rule state still qualifies; card-ID history only softens rank.
no_unblocks × Workday × unblockPolicy.
Unblocks allowed → no unblocks, with consequences visible.
Rule persistence succeeds and the refreshed snapshot is strict.
That instance is retired; another eligible opportunity—or no suggestion—wins.