assertPermissionTotality exists to refuse a surface nobody has gated, and it was reading the wrong list: Object.keys(handlers) — the map of implementations — while Bun served a hand-written route table twenty lines away. The comment beside it said neither could be a stale copy of the other. That was false, and it had a live instance: /api/cliamp/ws and /api/cliamp/audio/ws stayed in the route table for two days after their handlers and registry claims were commented out. Not exploitable — isWsProviderAllowed finds no permission and 403s a member, while the owner upgrades onto a dead socket — but precisely the drift the guard is for, invisible to the guard. Now there is one declaration. WS_ROUTES maps path → provider, the route table is generated from it, and the check reads it. A socket route cannot exist without being checked. Two smaller guards arrived with it. A route naming a provider with no handler refuses to boot, with the path in the message, instead of 500-ing on first connect. And the provider union that was inline in upgradeWs is named, so the route table typechecks against what that function can actually serve — which caught my first attempt, where WS_ROUTES was Record<string, string>. sidecar and dev-proxy are listed explicitly as served-but-absent-from-WS_ROUTES, because they upgrade through their own handlers rather than upgradeWs. Named so the absence cannot read as an oversight. Half the TODO was stale and it is recorded as such rather than quietly closed: the eight red tests it cites have been green since cliamp was deleted on 2026-08-15. Deleting cliamp removed the symptom and left the shape, which is the more interesting half. Verified against the real prefix lists rather than by reasoning: the served set passes, one unclaimed provider is refused by name, all five generated routes answer 401, and the server boots. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5.4 KiB
TODO — the index
Deferred work. The items live in todo/, one file each, grouped by theme; this file is the map
over them and is GENERATED — run bun run todo:index after any change rather than editing it here.
Format and the two-way-sync contract: todo/README.md.
Context, corrected 2026-08-07. This list used to open by saying Officer was "collapsing from multi-tenant / open-source-ready to a single-user platform", and told you to treat multi-tenant indirection as accidental complexity. That direction was reversed. The permission model shipped on 2026-08-07 to serve a real goal — deploy to the company server, onboard people, give each one their own Gitea account through the platform. Per-user scoping is now a requirement, and the items that proposed deleting it have been removed rather than left to mislead the next reader.
What did NOT reverse: execution permissions (terminal, chat, tasks, files, desktop, browser) run as
the owner's OS user and can never be granted. Indirection there really is accidental complexity.
Urgent
- due 2026-08-22 — Settings to choose which server each feature uses — fleet/settings-to-choose-which-server-each-feature
Themes
86 open, 23 closed, across 29 themes.
Records — no items, kept for the reasoning
- Affordances (2026-08-19)
- Inputs outside forms (2026-08-19) — swept, fixed, closed
- Release-binary dependencies (2026-08-19)
Newest ten
2026-08-22A plugin's permission should be on for every role by default, off only on request — multi-user/a-plugin-s-permission-should-be-on-for-every2026-08-22A user's settings should export and import as a plain file — settings/a-user-s-settings-should-export-and-import-as2026-08-22The same for system settings, owned by the Super Admin — settings/the-same-for-system-settings-owned-by-the2026-08-21No way to see which affordances are reaching your agents, or to turn one off — affordances/no-way-to-see-which-affordances-are-reaching2026-08-21Generalise it: deliver a turn to a named session, from anywhere in the backend — agent-delivery/generalise-it-deliver-a-turn-to-a-named2026-08-21The cost of resuming grows with the transcript — agent-delivery/the-cost-of-resuming-grows-with-the-transcript2026-08-21'An agent spawned by a background job is invisible in the interface' — background-jobs/a-spawned-agent-is-invisible-in-the-interface2026-08-21Show how long a turn took, beside its cost and tokens — chat/show-how-long-a-turn-took-beside-its-cost2026-08-21Map every custom component, centralise it, and let a theme override it — components/map-every-custom-component-and-centralise-it2026-08-21Watch a directory, and attach actions to what lands in it — file-watchers/watch-a-directory-and-attach-actions-to-what