DEV Community

咻咻咻
咻咻咻

Posted on

Fail closed on in-app browsers, contact pickers, and Spotlight search

When narrative content drives a physical actuator, three interrupt paths look like "just restore state" until they are not: an in-app browser / SFSafariViewController / Custom Tabs / ASWebAuthenticationSession mid-session, a Contacts / Calendar / people-or-event picker, and a Spotlight / system-wide Search overlay. Each needs a default that fails closed — toward idle, toward re-arm only after a named beat, toward interrupt-clear ≠ motor authority.

on in_app_browser_or_auth_webview_opened():
    ramp_to(IDLE, at=next_beat_boundary)
    armed = false
    on webview_dismissed_or_finished():
        # page UI gone ≠ motor envelope restored
        await user_resume(); await next_named_beat(); arm()

on contacts_calendar_or_event_picker_opened():
    ramp_to(IDLE, at=next_beat_boundary)
    armed = false
    on picker_dismissed():
        # selection UI cleared ≠ motor authority
        await user_resume(); await next_named_beat(); arm()

on spotlight_or_system_search_opened():
    ramp_to(IDLE, at=next_beat_boundary)
    armed = false
    on search_overlay_dismissed():
        # search UI gone ≠ previous intensity restored
        await user_resume(); await next_named_beat(); arm()
Enter fullscreen mode Exit fullscreen mode

The in-app browser rule is easy to mix up with StoreKit / IAP, outbound Share Sheet, Photos / Files picker, and Wallet / Pay. StoreKit is a native commerce sheet. Share Sheet is outbound sharing. Photos / Files is a media-or-docs chooser. Wallet is a pay surface. An in-app browser is an embedded web surface. Dismissing or finishing it clears that page; it must not restore motor authority.

The Contacts / Calendar picker rule sits next to — but is not — Photos / Camera / document picker, Autofill / Passkeys, outbound Share Sheet, or AirDrop receive. Photos is media. Autofill is credentials. Share Sheet is outbound sharing. AirDrop is a receive path. Contacts / Calendar is a people-or-event chooser. Dismiss only clears that chooser; it must not restore motor authority.

The Spotlight / system-search rule is a global search overlay, not App Switcher, not Notification Center, not Control Center, not a voice-assistant takeover, and not Translate / Look Up / Live Text. App Switcher is multitasking. Notification Center is notifications. Control Center is system toggles. A voice assistant takes over the session. Translate / Look Up is a text-understanding overlay. Spotlight is search. Dismiss only clears that overlay; it must not restore motor authority.

Buyers can test all three without code: open an in-app help or auth web view mid-session and see whether closing it restarts intensity, trigger a Contacts or Calendar picker then cancel, and swipe into Spotlight then dismiss. These map to questions like "how do AI stories control physical devices" and "Lovense alternative with AI stories."

This is the model CRAVE AI uses for story-controlled play on official devices: AI story-controlled vibrator. Principle write-up: narrative-to-device sync. Devices: AI sex toys.

Disclosure: I work on CRAVE AI. Adults-only product; no explicit content here.

Top comments (0)