Skip to content

Spotlight: the saved Macs, a tap connecting - #99

Open
addhumal wants to merge 10 commits into
Saffsanity:mainfrom
addhumal:spotlight-macs
Open

addhumal wants to merge 10 commits into
Saffsanity:mainfrom
addhumal:spotlight-macs

Conversation

@addhumal

@addhumal addhumal commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Closes #104.

What it does

Indexes every saved Mac this device has not been removed from in iOS/iPadOS Spotlight (CoreSpotlight, "Mac mini", "Connect with Sill"), and connects when the user taps the result. Device only: no wire change.

SpotlightMacs (pbxproj AE01/FE01) builds the searchable item records (domain "me.saffer.sill.macs", identifier "mac:<Mac ID>", expirationDate = .distantFuture so iOS does not age them out after 30 days) and decides what a tap dials. storeSavedMacs() re-indexes whenever the saved list changes, so a renamed, forgotten or revoked Mac is updated or removed at once. A tap arrives as a CSSearchableItemActionType user activity (never a URL scheme that another app could open) and dials the Mac's network or Direct row immediately, or waits out the 3 s local-network window (DiscoveryPolicy.networkFirst) before dialling its Remote row or saved addresses. Ignored while a session is already active.

Why

Once a Mac is paired, opening Sill and waiting on the connect screen is an extra step when you already know which Mac you want. Indexing paired Macs in Spotlight lets a swipe down on the Home Screen connect directly, using the same local-first route order as tapping the Mac's row on the connect screen.

site/privacy.html notes that paired Macs' names are kept in the device's on-device Spotlight index.

Checks

  • Tests/checks/spotlight-macs: 24 checks covering item identifiers, revoked Macs excluded, identifier parsing and rejection, and the tap dial rule before and after the 3 s window. 15 of 15 mutants caught. Added to CI's mutants list and the checks README.
  • Tests/checks/run-all.sh and swift build -c release pass with only the known warnings.
  • Verified on an iPad Air simulator (iOS 27.0) with -SillSpotlightTap mac:<Mac ID>: saved Mac indexed, tap waited 3 s when not on the LAN and dialled the saved address, unknown identifiers ignored.

Windows App's Spotlight entries, from the roadmap: each saved Mac this device was not removed from
is a Spotlight item ("Mac mini", "Connect with Sill"), all written again whenever the saved list
is, so a renamed, forgotten or removed Mac goes with its old self. A tap comes back as a user
activity (CSSearchableItemActionType), not a link, so no other app can make Sill dial (the
roadmap's sill://connect is not needed). It dials that Mac as a tap on its row: its network row,
else its Direct row, at once; its Remote row, or with none its saved addresses, only once the
network has had its 3 s (DiscoveryPolicy.networkFirst), as the connect screen shows Remote rows
only then. Ignored while a session runs; dropped if the Mac is forgotten meanwhile. DEBUG's seeded
saved Macs (-Sill.savedMacs) never reach the real Spotlight; -SillSpotlightTap mac:<Mac ID> stands
in for a tap.

SpotlightMacs (pure, pbxproj AE01/FE01): identifiers, which Macs are indexed, which row a tap
dials. The privacy policy says the saved Macs' names are in the device's own Spotlight index.

Checks: Tests/checks/spotlight-macs, 16 checks and 10 of 10 mutants, in CI's mutants matrix. On an
iPad Air simulator (iOS 27.0): a saved Mac indexed ("1 saved Mac indexed"); a tap waiting out the
network's 3 s and taking the saved dial; an identifier not Sill's ignored.
Review finding 1. Each write deleted Sill's items and added the list once the delete was done, so
two writes close together interleaved (delete, delete, old list, new list) and the older list
could land last: a launch without the device key indexed the saved Macs and cleared them a moment
later, and the cleared Mac stayed in Spotlight (seen in the simulator), against what the privacy
policy says. Now one write at a time (SpotlightMacs.Run, pure): a write asked for while one runs
waits, and runs once after it with the list as it is then. A delete that fails ends the write
with one line instead of being ignored.

Checks: spotlight-macs 23 checks (7 new, red before Run existed) and 15 of 15 mutants (5 new). On
the simulator the same launch now logs "1 saved Mac indexed", then "0 saved Macs indexed".
Found in the review before this push: CoreSpotlight expires an item a month after it was written
(CSSearchableItem.h), and the items are written again only when the list changes or Sill
launches, so a Mac paired and not opened for a month left Spotlight. Its item now lasts as long
as the saved Mac (expirationDate distantFuture).
# Conflicts:
#	.github/workflows/ci.yml
#	Tests/checks/README.md
#	iOSClient/StreamClient.swift
# Conflicts:
#	.github/workflows/ci.yml
#	Tests/checks/README.md
@Saffsanity

Copy link
Copy Markdown
Owner

From a pass over all the open pull requests (nothing is decided yet): #117 also extends storeSavedMacs() in StreamClient+Remote.swift and adds a paragraph at the same spot in site/privacy.html; the two are compatible, so whichever lands second keeps both bodies and both sentences. #66 (with #72 and #73) compiles the StreamClient files into its Mac client through symlinks, so SpotlightMacs.swift would need a link in Sources/MacClient/Shared there; the other overlaps (#93, #94, #95, #107) are the ci.yml mutants line and adjacent project-file entries.

@addhumal

addhumal commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor Author

Thanks. Merged main in (03e9b51, after #78, #79, #80 and #98), with no rebase; storeSavedMacs() and site/privacy.html keep both this PR's and #117's additions when the second lands.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: Index saved Macs in Spotlight on iPhone and iPad

2 participants