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; - **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. `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']` on music's registry entry, the four
personal: ['/favorites', '/now-playing', '/playlists', '/queue'], 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 Two facts that make leaving it alone safe rather than lazy:
aspirational; find out which.
Four tables, all `userId` + cascade to `users.id`: `music_favorites`, `music_playlists`, - **The web frontend does not use those routes at all.** Favourites, playlists and now-playing are used
`music_playlist_items`, `music_now_playing` (composite PK `(userId, device)`). 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 Move the routes, the tables and the queries verbatim. `userId` keeps arriving from `X-Officer-User` and
global directory. `MUSIC_ROOT = join(homedir(), 'Music')`, and `stream-audio.ts` and `cliamp-ws.ts` each the queries keep scoping by it, exactly as today.
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 **The one mechanical consequence you cannot avoid:** `registry.test.ts` tests the `personal` mechanism
app-store entry promises a configurable `library` folder and **nothing reads it**. *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 ### 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 `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. 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.
--- ---