Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/ADR-INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Generated by `scripts/adr_index.py` from the records in `docs/decisions/` — do not edit; run
`make adr-index` after adding or changing one, and CI fails on a stale copy (ADR-0127 point 6).

140 current records (140 accepted,
142 current records (142 accepted,
0 proposed), 10 retired. A record whose status carries a note has had a point superseded by a later one; the note says which.

## Apple clients
Expand Down Expand Up @@ -43,6 +43,8 @@ Generated by `scripts/adr_index.py` from the records in `docs/decisions/` — do
| [0139](decisions/ADR-0139-the-apple-clients-record-where-a-queue-was-started-from.md) | The Apple Clients Record Where a Queue Was Started From | accepted |
| [0146](decisions/ADR-0146-the-site-leads-with-the-mac.md) | The Site Leads with the Mac | accepted |
| [0148](decisions/ADR-0148-familiar-server-has-a-stable-download-link.md) | Familiar Server Has a Stable Download Link | accepted |
| [0151](decisions/ADR-0151-the-phone-makes-and-edits-smart-playlists.md) | The Phone Makes and Edits Smart Playlists | accepted |
| [0152](decisions/ADR-0152-on-the-phone-search-belongs-to-the-screen.md) | On the Phone, Search Belongs to the Screen | accepted |

## Playback

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# ADR-0013: The Mac Is a Management Surface Too

Status: accepted — points 1 and 5 superseded by
[ADR-0050](ADR-0050-the-web-app-is-a-management-surface.md)
[ADR-0050](ADR-0050-the-web-app-is-a-management-surface.md); point 2 superseded for playlists by
[ADR-0151](ADR-0151-the-phone-makes-and-edits-smart-playlists.md)

Point 1 said "Both clients keep everything… which costs nothing to keep". That was measured and found
false; ADR-0050 records what it cost. Point 5 kept "a complete player at a computer, not an admin
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ADR-0061: The Phone's Tabs Are Home, Search and Library

Status: accepted
Status: accepted; points 1 and 2 superseded by [ADR-0152](ADR-0152-on-the-phone-search-belongs-to-the-screen.md)

Date: 2026-08-17

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# ADR-0151: The Phone Makes and Edits Smart Playlists

Status: accepted

Date: 2026-10-07

Implementation:
- Accepted 2026-10-07.

Supersedes point 2 of [ADR-0013](ADR-0013-the-mac-is-a-management-surface-too.md), for playlists
only.

## Context

ADR-0013 point 2 says **"iOS stays the listening path. The phone is not a management client"**, and
point 3 puts smart playlist CRUD on the Mac. `familiar-apple` still cites both:
`SmartPlaylistsListView.swift` keeps creating, refreshing and deleting `#if os(macOS)`, and its
empty state on the phone reads "They're made on the Mac or in the web app, and fill themselves."

**The phone stopped being only a listening path on 2026-08-15, and nothing recorded it.**
`familiar-apple` #119 ("Add visible iOS playlist editing", `2bb5b2d`) gave the phone, in the iOS
branch of `BrowseViews.swift` (lines 722–797 at the time of writing):

- **Edit Rules** on a smart playlist's screen, opening the same `SmartPlaylistEditor` the Mac uses;
- **Edit Contents**, **Rename** and **Delete** on an ordinary playlist.

No ADR was written, so the record and the app have disagreed for seven weeks. That is the defect
ADR-0061 point 5 names: "the record and the app disagreed for weeks and neither one knew."

The prompt for this ADR is the owner, travelling with only the phone, wanting to **make** a smart
playlist and finding no way to. The phone can now change any rule of a smart playlist that exists,
and cannot write the first one. That line follows from no principle: it is where #119 stopped.

ADR-0013 point 2 says managing the library from a phone "is still a second-class experience by
design", and gives no reason specific to playlists. Point 3 lists smart playlist CRUD beside pending
review, proposed changes and mixtapes, and point 4 keeps settings, imports and backup on the web.
Pending review, proposed changes, settings, imports and backup all change what the server holds or
how it runs. A smart playlist changes neither: it is a saved question about the library. It is a description
of **what to listen to**, and the test ADR-0018 and ADR-0019 used to bring Discover to the phone,
whether it is a way of finding something to play, is one it passes. The editor is already built
from the server's own field list, so writing a rule on the phone needs no new screen, only a way in.

## Decision

1. **Playlists are not management.** On the phone, as on the Mac, a listener can create, edit,
rename and delete ordinary playlists and smart playlists. This supersedes ADR-0013 point 2 for
playlists and for nothing else.

2. **The phone gets "New Smart Playlist"**, opening the existing `SmartPlaylistEditor` with no
playlist, the way the Mac's `+` does. It sits in the toolbar of the smart playlists list, and the
empty state names it rather than sending the listener to another device.

3. **Refresh and Delete join Edit Rules** on a smart playlist's screen on the phone, under the same
actions menu, so a smart playlist has the same three operations an ordinary one already has
there.

4. **#119's editing is recorded as decided here, not as an exception.** Nothing it added is removed.

5. **Everything else ADR-0013 point 2 kept off the phone stays off it**: settings, pending review,
proposed changes, mixtapes, imports, backup, and every other surface whose subject is the server
rather than what to play next.

## Alternatives Considered

- **Leave ADR-0013 point 2 as it is and remove #119's editing from the phone.** Restores agreement
between the record and the app at the cost of the feature. Rejected: the owner uses it, and the
reason given for the original line, that a phone is a poor place to manage a server, does not
describe a playlist.
- **Record #119 and still keep creation on the Mac.** Smallest change, and creating is where a new
rule is most likely to be written badly on a small keyboard. Rejected: the editor that edits a rule
is the one that would create it, the phone already writes every field of one, and "you can change
any rule but not write the first" is the gap that prompted this ADR.
- **Create on the phone through a simpler, phone-only editor**, such as a handful of preset rules.
Easier to use with a thumb. Rejected for now: a second editor is a second thing to keep in step
with the server's field list, which `SmartPlaylistEditor` already reads, and the full editor
already works on the phone through Edit Rules.

## Consequences

- **Positive:** the record matches the app again, and a smart playlist can be made where the idea
for it happens.
- **Positive:** the phone and the Mac offer the same playlist operations, so nothing about a
playlist has to be explained per device.
- **Tradeoff:** ADR-0013's simple rule, "the phone is not a management client", becomes a rule with
an exception. Point 5 states the boundary so it does not drift further one feature at a time.
- **Follow-up:** `SmartPlaylistsListView`'s header comment and empty state, and the `LibraryView`
comment on `smartPlaylistsStore`, describe the old split and change with the code.
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# ADR-0152: On the Phone, Search Belongs to the Screen

Status: accepted

Date: 2026-10-07

Implementation:
- Accepted 2026-10-07.

Supersedes points 1 and 2 of [ADR-0061](ADR-0061-the-phones-tabs-are-home-search-and-library.md).

## Context

ADR-0061 ratified three tabs, **Home, Search and Library**, on the grounds that "searching is a root
action, not a destination". The owner, using the phone while travelling on 2026-10-07, found two
things wrong with how that turned out:

- **The Search tab only searches tracks.** `phoneSearchRoot` (`familiar-apple`
`App/Shared/LibraryView.swift:1059`) is the tracks list with `.searchable(prompt: "Search
tracks")`. Looking for an artist there finds the artist's tracks, never the artist.
- **The phone already searches artists and albums, and nobody could find it.** The Library tab's
section screens carry a field scoped to what they show — "Search artists", "Search albums",
"Search tracks", "Filter playlists" (`searchPrompt`, `LibraryView.swift:2040`) — applied at
`LibraryView.swift:735`. On this SDK the system puts that field at the **bottom** of the screen
(noted at `LibraryView.swift:1548`), under the transport and beside a tab bar that has a
magnifying glass of its own. A listener who wants to search reaches for that tab, and the tab
searches something else.

So the phone has two searches with different scopes, and the visible one is the narrower one.
The owner's ask is the scoped one, made visible: **on the Artists screen you search artists, on
Albums you search albums.**

ADR-0061 point 5 requires an ADR for a navigation change on either client. Removing a tab is one.

## Decision

1. **Two tabs: Home and Library.** The Search tab is removed. This supersedes ADR-0061 points 1
and 2. Its points 3 and 4 stand: the Library tab is `LibraryRootList`, unchanged.

2. **Every list screen's search field sits at the top**, under the title, always visible
(`.searchable(placement: .navigationBarDrawer(displayMode: .always))`), and searches what that
screen lists: Tracks searches tracks, Artists artists, Albums albums, Playlists and Smart
Playlists filter by name. The scopes and prompts are the ones the screens already have; only the
placement changes.

3. **Screens with nothing to search get no field**, as now: Home, Discover and Ambient
(`isSearchable`, `LibraryView.swift:738`).

4. **The Mac is untouched.** Its sidebar and toolbar search already follow the selected section.

## Alternatives Considered

- **Keep the Search tab and make it search everything**: artists, albums and tracks in one list of
results, the shape the Music app uses. It keeps ADR-0061's "root action" and needs no navigation
change. Rejected for now: no endpoint answers all three (the only `/search` route, in
`admin_artists.py`, finds artists for the admin tools), so it would be three requests merged on
the device, ranked by nothing, and it would still leave a second, differently scoped field on
every section screen. It could come back as its own ADR, and nothing here prevents it.
- **Keep the Search tab as it is and only move the section fields to the top.** The smallest change.
Rejected: the phone would then show two magnifying glasses with different scopes on the same
screen, which is the confusion that prompted this.
- **Make the Search tab open the Library section in use with its field focused.** One search,
reached from the tab bar. Rejected: a tab that navigates another tab is a surprise, and on Home it
would have to pick a section arbitrarily.

## Consequences

- **Positive:** one search per screen, where the eye goes, and its scope is the screen's title.
- **Positive:** artists and albums are searchable from where they are browsed, with no new endpoint.
- **Tradeoff:** searching for a track takes one more tap than today: Library, then Tracks.
ADR-0061 argued that cost was worth a tab; this ADR argues the scoped field is worth more.
- **Tradeoff:** a field that is always visible takes a row of every list screen.
- **Follow-up:** the placement must be checked on an iOS 26 device, not only a simulator on an older
runtime: iOS 26 moved search into the tab bar, and a simulator on 18.5 has hidden a bug that only
existed on 26 before.
Loading