# Admin scope tightening — personal resources are owner-only (#36) Decision (2026-09-30, user): **all personal resources are visible and operable by their owner ONLY.** Compared to a normal user, an admin gains exactly three things: system switch control (registration toggle), user management, and the ability to create/modify **global** resources. Admins are curators of the global library, not tenant overseers. Issue: #36. The pre-existing global-create gate (403 for non-admins on `scope: 'global'` create) was already correct; this change removed every `owner-or-admin` READ/MUTATE bypass. ## The rule | Row | Read | Mutate | | --- | --- | --- | | personal (`ownerId` set) | owner only — everyone else (admin included) gets **404** (existence-hiding) | owner only | | global (`ownerId` null) | everyone | **admin only** (`canManage`) | Machines, credentials, MCP servers, profiles, resources, LLM providers carry the scope; machine-scoped surfaces (jobs, agents, sessions listing, inventory, workspace listing, runtime-config, config view) inherit their machine's ownership. ## What changed where - `machines.ts` — `visible()` owner-only; `GET /api/machines` lists own for every role; the module doc dropped "or an admin". - `jobs.ts` / `runtime-config.ts` / `inventory.ts` / `workspace.ts` — `visibleMachine` / `visible` owner-only; the now-dead `MACHINE_OWNER_ONLY` 403 branches were REMOVED (a non-owner never gets past the 404). - `jobs/service.ts` `cancel` — owner-only. - `status.ts` (posture) — every figure is `self` for every role; the `scopes` map stays on the wire but never says `all`. The web readout strip dropped its `all`/`own` markers (dead branches) and the i18n keys went with them. - `mcp-servers.ts` — `/status` filters to own-personal + global for every role; `ownsOrAdmin` → `canManage` (global → admin, personal → owner). - `credentials.ts`, `llm-providers.ts`, `resources.ts`, `profiles.ts` — same `canManage` shape; visibility helpers (`visibleTo`/`serverVisible`/ `visibleProfile`/…) lost their `|| role === 'admin'` arm and the unused `role` param. - `registry.ts`, `marketplace.ts`, `client-config.ts` — profile/server visibility checks aligned (admin no longer resolves another user's personal profile/server, including via `/mcp?profile=` and machine-PAT bundles). - `plugins/realtime.ts` — the `admins` socket room is GONE: `machine:status`, `job:update`, `inventory:updated` emit to `user:` only. ## Tests `packages/server/test/admin-scope.test.ts` (machine routes 404 for admin on a foreign machine; foreign personal credential/mcp unmanageable by admin while global rows remain admin turf; mcp status filtered) + updated assertions in machines/jobs/runtime-config/config-view/status-filter/status-posture (the old expectations — admin sees all, `MACHINE_OWNER_ONLY` 403, posture `all` — were the codified OLD behavior and flipped).