todo: one file per item, grouped by theme, with a generated index
TODO.md had reached 1050 lines and 72 open items across 28 sections, read mostly on a phone. It is now a directory: todo/<theme>/<item>.md, one card per file, with frontmatter carrying id, status, created date and order, and the prose body copied across verbatim. TODO.md becomes a generated index (bun run todo:index). Dates: where an item's prose stated one it is used; otherwise its old section's; otherwise 2026-08-20, floored at the day before the split rather than invented. date_source records which. Shaped for a two-way Kanban board, filed as todo/tooling — a card is a file, id is the identity, frontmatter is the machine's half and the body is the owner's. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
---
|
||||
id: plugin-repos/12-stale-headscale-route-paths-in-comments
|
||||
title: "~12 stale `/headscale` route paths in comments across `web/`, plus `App.tsx:78` in the platform"
|
||||
theme: plugin-repos
|
||||
status: done
|
||||
created: 2026-08-21
|
||||
date_source: stated
|
||||
order: 4
|
||||
---
|
||||
|
||||
~12 stale `/headscale` route paths in comments across `web/`, plus `App.tsx:78` in the platform.
|
||||
**Done.** Verified 2026-08-21: none left in either. The one remaining mention is a form
|
||||
placeholder, `https://headscale.example.com`, which is correct — that IS a Headscale URL.
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
theme: plugin-repos
|
||||
heading: "Plugin repos — what writing their READMEs turned up"
|
||||
kind: theme
|
||||
---
|
||||
|
||||
Three READMEs were written on 2026-08-16 (`music`, `offscale`, `example`) and pushed to their own repos.
|
||||
Writing them meant reading each plugin against its own documentation, which is the cheapest audit there
|
||||
is. Everything below was found that way and none of it is fixed.
|
||||
|
||||
**Offscale is still branded headscale in shipped, user-visible places.**
|
||||
|
||||
**Documentation that actively lies.**
|
||||
|
||||
**Done.** Verified 2026-08-21: zero occurrences of either name.
|
||||
|
||||
**Conventions a plugin author has to guess.** All verified in `discover.ts`/`mount.ts`, none documented
|
||||
outside the example's new README:
|
||||
|
||||
**Genuinely missing.**
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
id: plugin-repos/a-manifest-is-module-cached-for-the-process
|
||||
title: "A manifest is module-cached for the process lifetime: editing it does nothing until `pm2 restart officer`, and `outdated` cannot see a version bump either"
|
||||
theme: plugin-repos
|
||||
status: done
|
||||
created: 2026-08-21
|
||||
date_source: stated
|
||||
order: 14
|
||||
---
|
||||
|
||||
A manifest is module-cached for the process lifetime: editing it does nothing until
|
||||
`pm2 restart officer`, and `outdated` cannot see a version bump either.
|
||||
**Fixed 2026-08-21 (`da30d1a6`).** `importFresh` keys the import on the file's mtime — a changed
|
||||
manifest is re-read, an unchanged one is still a cache hit. Found the expensive way: a reinstalled
|
||||
jellyfin was judged against the DELETED plugin's manifest, so it was ruled ineligible for the user
|
||||
list and provisioning silently did nothing. Note the limit: only the named file is re-read, so a
|
||||
plugin's own imports still need a restart.
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
id: plugin-repos/a-plugin-s-assets-icon-png-is-only-published
|
||||
title: "A plugin's `assets/icon.png` is only published while installed, so its real icon is invisible in the store before install"
|
||||
theme: plugin-repos
|
||||
status: open
|
||||
created: 2026-08-20
|
||||
date_source: assumed
|
||||
order: 19
|
||||
---
|
||||
|
||||
A plugin's `assets/icon.png` is only published while installed, so its real icon is invisible in the
|
||||
store before install. The catalogue's `iconUrl` works around it, and an author has to know to add one.
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
id: plugin-repos/panel-keys-and-layout-apptypes-must-agree-and
|
||||
title: "Panel `key`s and layout `appType`s must agree, and a mismatch fails SILENTLY — `PluginScreen.tsx` pins `appTypes.allowed` with `fallback: allowed[0]`, so a typo renders the first panel"
|
||||
theme: plugin-repos
|
||||
status: open
|
||||
created: 2026-08-20
|
||||
date_source: assumed
|
||||
order: 12
|
||||
---
|
||||
|
||||
Panel `key`s and layout `appType`s must agree, and a mismatch fails SILENTLY — `PluginScreen.tsx`
|
||||
pins `appTypes.allowed` with `fallback: allowed[0]`, so a typo renders the first panel.
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
id: plugin-repos/permission-key-prefixing-is-convention-not
|
||||
title: "Permission-key prefixing is convention, not validation"
|
||||
theme: plugin-repos
|
||||
status: open
|
||||
created: 2026-08-20
|
||||
date_source: assumed
|
||||
order: 15
|
||||
---
|
||||
|
||||
Permission-key prefixing is convention, not validation. Only a collision with a CORE key is refused,
|
||||
silently, at mount, with a console error.
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
id: plugin-repos/plugin-md-has-11-stale-self-references
|
||||
title: "`PLUGIN.md` has ~11 stale self-references (`headscale_servers`, `listHeadscaleServers`, permission key `headscale`, `/api/headscale`, panel keys, `useHeadscaleSection()`)"
|
||||
theme: plugin-repos
|
||||
status: done
|
||||
created: 2026-08-20
|
||||
date_source: assumed
|
||||
order: 5
|
||||
---
|
||||
|
||||
`PLUGIN.md` has ~11 stale self-references (`headscale_servers`, `listHeadscaleServers`, permission
|
||||
key `headscale`, `/api/headscale`, panel keys, `useHeadscaleSection()`).
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
id: plugin-repos/plugins-example-manifest-ts-12-lists-web
|
||||
title: "`plugins/example/manifest.ts:12` lists `web/Router.tsx` as the frontend convention; discovery requires `web/panels.ts` AND `web/layout.ts`"
|
||||
theme: plugin-repos
|
||||
status: done
|
||||
created: 2026-08-20
|
||||
date_source: assumed
|
||||
order: 10
|
||||
---
|
||||
|
||||
`plugins/example/manifest.ts:12` lists `web/Router.tsx` as the frontend convention; discovery
|
||||
requires `web/panels.ts` AND `web/layout.ts`. The same file documents an `ownerOnly` field that does
|
||||
not exist and never did.
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
id: plugin-repos/plugins-music-musicapi-md-documents-now
|
||||
title: "`plugins/music/MUSIC_API.md` documents now-playing as one snapshot per user with no mention of `?device=`, which the schema makes part of the primary key"
|
||||
theme: plugin-repos
|
||||
status: open
|
||||
created: 2026-08-20
|
||||
date_source: assumed
|
||||
order: 9
|
||||
---
|
||||
|
||||
`plugins/music/MUSIC_API.md` documents now-playing as one snapshot per user with no mention of
|
||||
`?device=`, which the schema makes part of the primary key. A mobile client written to that doc is
|
||||
correct only by accident.
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
id: plugin-repos/plugins-music-musicapi-md-says-favourites-and
|
||||
title: "`plugins/music/MUSIC_API.md` says favourites and now-playing are served by the platform from Postgres; the sidecar serves them itself, scoped by `X-Officer-User`"
|
||||
theme: plugin-repos
|
||||
status: open
|
||||
created: 2026-08-20
|
||||
date_source: assumed
|
||||
order: 8
|
||||
---
|
||||
|
||||
`plugins/music/MUSIC_API.md` says favourites and now-playing are served by the platform from
|
||||
Postgres; the sidecar serves them itself, scoped by `X-Officer-User`. It also documents the playlist
|
||||
item key as `<albumRel>/<file>` while the schema and favourites use the home path — the same file
|
||||
contradicts itself.
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
id: plugin-repos/plugins-music-web-musicplayerhost-tsx-header
|
||||
title: "`plugins/music/web/MusicPlayerHost.tsx` header says it is mounted once in the persistent DashboardLayout; it moved into `MusicDetail`"
|
||||
theme: plugin-repos
|
||||
status: open
|
||||
created: 2026-08-20
|
||||
date_source: assumed
|
||||
order: 18
|
||||
---
|
||||
|
||||
`plugins/music/web/MusicPlayerHost.tsx` header says it is mounted once in the persistent
|
||||
DashboardLayout; it moved into `MusicDetail`. That is exactly the comment that would mislead
|
||||
someone about why playback stops off-route.
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
id: plugin-repos/plugins-offscale-offscaleapi-md-claims-to
|
||||
title: "`plugins/offscale/OFFSCALE_API.md` claims to publish the contract \"in full\" and omits six live surfaces, including all of `/_officer/companion/*` and `/_officer/enroll/invites`"
|
||||
theme: plugin-repos
|
||||
status: open
|
||||
created: 2026-08-20
|
||||
date_source: assumed
|
||||
order: 7
|
||||
---
|
||||
|
||||
`plugins/offscale/OFFSCALE_API.md` claims to publish the contract "in full" and omits six live
|
||||
surfaces, including all of `/_officer/companion/*` and `/_officer/enroll/invites`.
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
id: plugin-repos/plugins-offscale-plugin-md-445-449-says-the
|
||||
title: "`plugins/offscale/PLUGIN.md:445-449` says the ACL assistant is deliberately unwired and must not be wired up"
|
||||
theme: plugin-repos
|
||||
status: open
|
||||
created: 2026-08-20
|
||||
date_source: assumed
|
||||
order: 6
|
||||
---
|
||||
|
||||
`plugins/offscale/PLUGIN.md:445-449` says the ACL assistant is deliberately unwired and must not be
|
||||
wired up. It IS wired — `sidecar/assist.ts`, `claude-proxy.ts`, `web/PolicyAssistant.tsx` and the
|
||||
manifest's `readOnlyWrites` all ship.
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
id: plugin-repos/plugins-offscale-spawns-the-ssh-binary
|
||||
title: "`plugins/offscale` spawns the `ssh` binary (`sidecar/ssh.ts`) but declares no `osDependencies`, so install never checks for it and the Console fails at runtime instead of refusing at install"
|
||||
theme: plugin-repos
|
||||
status: done
|
||||
created: 2026-08-16
|
||||
date_source: stated
|
||||
order: 16
|
||||
---
|
||||
|
||||
`plugins/offscale` spawns the `ssh` binary (`sidecar/ssh.ts`) but declares no `osDependencies`, so
|
||||
install never checks for it and the Console fails at runtime instead of refusing at install.
|
||||
**Already fixed** — the manifest declares `ssh` with per-manager packages, and its own comment
|
||||
records the 2026-08-16 change. Verified 2026-08-21: the probe reports `offscale ssh=ok`. The entry
|
||||
outlived the fix.
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
id: plugin-repos/scripts-reindex-music-ts-resolves-its-port
|
||||
title: "`scripts/reindex-music.ts` resolves its port file from `process.env.DATA_PATH ??"
|
||||
theme: plugin-repos
|
||||
status: done
|
||||
created: 2026-08-13
|
||||
date_source: stated
|
||||
order: 17
|
||||
---
|
||||
|
||||
`scripts/reindex-music.ts` resolves its port file from `process.env.DATA_PATH ?? cwd/data`, and
|
||||
`DATA_PATH` stopped being an env var on 2026-08-13. Run from the repo it looks in
|
||||
`platform/data/music/.server` and never finds it. One line.
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
id: plugin-repos/the-appname-table-prefix-is-unenforced
|
||||
title: "The `<appName>_` table prefix is unenforced"
|
||||
theme: plugin-repos
|
||||
status: open
|
||||
created: 2026-08-20
|
||||
date_source: assumed
|
||||
order: 13
|
||||
---
|
||||
|
||||
The `<appName>_` table prefix is unenforced. The barrel is `export *` across every plugin into one
|
||||
`public` schema, so two plugins choosing the same unprefixed name collide with no error until push.
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
id: plugin-repos/the-companion-contract-docs-the-offscale-code
|
||||
title: "The Companion contract docs the offscale code cites (`COMMS/OFFSCALE_COMPANION_API.md`, `COMMS/OFFSCALE_INVITE_ENROLLMENT.md`) exist nowhere — `COMMS/` was deleted"
|
||||
theme: plugin-repos
|
||||
status: open
|
||||
created: 2026-08-20
|
||||
date_source: assumed
|
||||
order: 11
|
||||
---
|
||||
|
||||
The Companion contract docs the offscale code cites (`COMMS/OFFSCALE_COMPANION_API.md`,
|
||||
`COMMS/OFFSCALE_INVITE_ENROLLMENT.md`) exist nowhere — `COMMS/` was deleted. Two of the plugin's
|
||||
eight sections depend on a service with no published spec.
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
id: plugin-repos/web-consoleview-tsx-22-mints-terminal-session
|
||||
title: "`web/ConsoleView.tsx:22` mints terminal session ids as `headscale-console-<id>`"
|
||||
theme: plugin-repos
|
||||
status: done
|
||||
created: 2026-08-16
|
||||
date_source: stated
|
||||
order: 3
|
||||
---
|
||||
|
||||
`web/ConsoleView.tsx:22` mints terminal session ids as `headscale-console-<id>`. That is persisted
|
||||
state rather than a comment, so renaming it orphans live console sessions — cheap now, less so later.
|
||||
**Done 2026-08-16**, and the file carries a comment recording it — a pty session KEY, not a label.
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
id: plugin-repos/web-offscaleserverpicker-tsx-26-renders-the
|
||||
title: "`web/OffscaleServerPicker.tsx:26` renders the literal heading `Headscale`"
|
||||
theme: plugin-repos
|
||||
status: done
|
||||
created: 2026-08-21
|
||||
date_source: stated
|
||||
order: 2
|
||||
---
|
||||
|
||||
`web/OffscaleServerPicker.tsx:26` renders the literal heading `Headscale`.
|
||||
**Done.** Verified 2026-08-21: it renders `Offscale`.
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
id: plugin-repos/web-panels-ts-registers-three-panels-named
|
||||
title: "`web/panels.ts` registers three panels named \"Headscale servers\", \"Headscale\", \"Headscale\" — these are what a user reads in the panel picker"
|
||||
theme: plugin-repos
|
||||
status: done
|
||||
created: 2026-08-21
|
||||
date_source: stated
|
||||
order: 1
|
||||
---
|
||||
|
||||
`web/panels.ts` registers three panels named "Headscale servers", "Headscale", "Headscale" — these
|
||||
are what a user reads in the panel picker.
|
||||
**Done.** Verified 2026-08-21: the three read "Offscale servers", "Offscale", "Offscale".
|
||||
Reference in New Issue
Block a user