the per-user model is not tonight's work either

personal, the four user-scoped tables, and what a member's grant means all stay
exactly as they are. it gets built inside the plugin later, which is the entire
reason the platform's answer is a uniform read/write and nothing more.

leaving it alone is safe rather than lazy: the web frontend does not use those
routes at all — favourites, playlists and now-playing are used only by the phone
and tablet apps — so nothing visible in a browser can regress by carrying them
across verbatim. and /queue, which is in that list, has no route anywhere. dead
or aspirational; carried as-is, not investigated.

the one unavoidable consequence stays named: registry.test.ts tests the personal
mechanism through the music entry, so removing it breaks those tests. re-anchor
on another entry that has personal. a test fix, not a redesign.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-15 01:24:09 +00:00
co-authored by Claude Opus 5
parent 7d65732f77
commit 18c4ebd0b4
+19 -15
View File
@@ -168,23 +168,28 @@ avoid is not a wrong call; it is a tree left half-moved with a question attached
- **Already half-disabled**: `hono.ts` mount and `schema.ts` export are commented out since 2026-08-13;
`officer_db/src/index.ts:49` is still live. So the tree is mid-migration already.
### The per-user shape, which is why music was chosen
### The per-user model is NOT tonight's work
```ts
personal: ['/favorites', '/now-playing', '/playlists', '/queue'],
```
`personal: ['/favorites', '/now-playing', '/playlists', '/queue']` on music's registry entry, the four
user-scoped tables, and the question of what a member's grant *means* — **all of it stays exactly as it
is. Do not design it, do not improve it, do not think about it.** It will be built inside the plugin
later, which is the whole reason the platform's answer is a uniform read/write and nothing more.
No `readOnlyWrites`. Note `/queue` — **no such route exists**, in the sidecar or the frontend. Dead or
aspirational; find out which.
Two facts that make leaving it alone safe rather than lazy:
Four tables, all `userId` + cascade to `users.id`: `music_favorites`, `music_playlists`,
`music_playlist_items`, `music_now_playing` (composite PK `(userId, device)`).
- **The web frontend does not use those routes at all.** Favourites, playlists and now-playing are used
only by the phone and tablet apps. Nothing you can see in a browser depends on them, so nothing in this
extraction can regress by carrying them across untouched.
- `/queue` is in that list and **no such route exists**, in the sidecar or anywhere else. Dead or
aspirational. Carry it as-is; do not investigate.
**And the mismatch that makes music the interesting case:** the state is per-user, the library is one
global directory. `MUSIC_ROOT = join(homedir(), 'Music')`, and `stream-audio.ts` and `cliamp-ws.ts` each
take `homedir()` as their root independently. So a granted member's favourites are theirs, while
`/stream` serves them the **owner's** files and cliamp spawns a process in the **owner's** home. The
app-store entry promises a configurable `library` folder and **nothing reads it**.
Move the routes, the tables and the queries verbatim. `userId` keeps arriving from `X-Officer-User` and
the queries keep scoping by it, exactly as today.
**The one mechanical consequence you cannot avoid:** `registry.test.ts` tests the `personal` mechanism
*through* the music entry, and `registry.ts` uses music as its worked example in prose. Removing the
entry breaks those tests. Re-anchor them on another entry that has `personal` — the smallest edit that
makes them green and still test the mechanism. That is a test fix, not a redesign.
### How to decide the three, if you want a default
@@ -206,8 +211,7 @@ left in the platform is a documented seam; a piece left dangling is a bug.
`assertCapabilityTotality` is **not** part of this. It is worth fixing eventually and the cliamp routes
are the live example of the drift it cannot see, but both are someone else's evening.
**Do not** invent music's per-user visibility model during the move. Extract with the semantics it has, or
the two changes tangle and a bug in either is a bug in both.
---