teams: the four open questions are answered
A team owns a shared folder. Any Admin may create one. A team may grant a capability the member's role lacks, capped so the creator cannot attach anything they do not hold themselves. Deleting a role is refused while anyone holds it in a team, same as globally. Dashboards deferred deliberately: they need editor-versus-viewer, which is a permission shape nothing here has, since every grant today is read-or-write over a whole capability. Also records two things phase 4 must not get wrong. The folder boundary is a Linux group, not the grant — every role already holds files at write, so the capability was never what kept teams apart. And the grant cache is keyed on role today; teams make it per-user, which is easy to lose silently. Plus the quota model and its prerequisite: enforcement is the kernel's, because members have terminal and can write past anything the platform counts. Neither officer-dev nor alpha can carry filesystem quotas today and neither can be fixed while running. edge-pertento is where it matters — the first real multi-user host — and it should be checked before it gains accounts. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
This commit is contained in:
+63
-7
@@ -214,13 +214,69 @@ written once and the code moves every day.
|
|||||||
- `bun run docs:check` — the permission count claim in `CLAUDE.md` moves whenever the registry does.
|
- `bun run docs:check` — the permission count claim in `CLAUDE.md` moves whenever the registry does.
|
||||||
- Any schema phase: verify by query per host, never by `db:push`'s exit code.
|
- Any schema phase: verify by query per host, never by `db:push`'s exit code.
|
||||||
|
|
||||||
|
## Teams — decided 2026-08-23
|
||||||
|
|
||||||
|
The four open questions were answered by the owner. Recorded here so phase 4 is implementation rather
|
||||||
|
than another round of design.
|
||||||
|
|
||||||
|
**A team owns a shared folder.** Not only an authorization grouping — storage is the part that was
|
||||||
|
actually wanted. Team *dashboards* are a probable later addition and were explicitly deferred, because
|
||||||
|
they need a permission shape nothing here has: people who can edit a dashboard's STRUCTURE versus people
|
||||||
|
who only see what it renders. Every grant today is read-or-write over a whole capability, so that is a new
|
||||||
|
model rather than a new level. Build the folder; leave room for the dashboards.
|
||||||
|
|
||||||
|
**Any Admin may create a team**, not the owner alone. Teams are self-service for people already trusted to
|
||||||
|
administer the platform. This is what makes the quota section below necessary rather than optional: an
|
||||||
|
Admin creating a team is an Admin allocating disk.
|
||||||
|
|
||||||
|
**A team may grant a capability the member's own role lacks** — the union, per D6 — with one rule on top:
|
||||||
|
**whoever creates the team can only attach capabilities they hold themselves.** Escalation is capped at the
|
||||||
|
creator's own reach rather than the whole registry. `execution` and `admin` stay ungrantable regardless,
|
||||||
|
and `confined` still resolves to nothing for an account with no Linux user.
|
||||||
|
|
||||||
|
**Deleting a role is refused while anyone holds it, in a team or globally.** The same rule D4 already
|
||||||
|
applies to global holders, extended rather than special-cased; the refusal should name the teams.
|
||||||
|
|
||||||
|
### Two things phase 4 must not get wrong
|
||||||
|
|
||||||
|
**The shared folder is enforced by the kernel, not by the grant.** Every role already holds `files` at
|
||||||
|
`write` — they are the seeded `confined` defaults — so the capability is not what keeps one team out of
|
||||||
|
another's folder. A Linux group per team is. The grant says whether someone can use the files surface at
|
||||||
|
all; group membership says which folders they reach. Both are required and they are not substitutes.
|
||||||
|
|
||||||
|
**The grant cache is keyed on ROLE today**, deliberately: "at most one entry per role, and a new account
|
||||||
|
needs no warm-up" (`permissions/authorize.ts`). Teams end that — effective permissions become role plus
|
||||||
|
memberships, which is per-user. That property is easy to lose without noticing and awkward to recover, so
|
||||||
|
it should be a decision in the implementation rather than a side effect.
|
||||||
|
|
||||||
|
## Quotas — the model, and the prerequisite nobody can skip
|
||||||
|
|
||||||
|
The owner declares platform-level defaults and maxima: per user, and per team. Admins allocate inside
|
||||||
|
them. A change re-applies at the Linux level through `POST /users/:id/provision-linux`, which already
|
||||||
|
exists as a retry path and becomes "re-apply current policy to this account".
|
||||||
|
|
||||||
|
**Enforcement is the kernel's job, not the platform's.** Members hold `terminal` at `write` and have their
|
||||||
|
own Linux accounts, so a quota the platform tracks by counting bytes through the file browser is
|
||||||
|
decorative — a member opens a terminal or SSHes in and writes past it. Only filesystem quotas bind.
|
||||||
|
|
||||||
|
**Which means a filesystem that can carry them.** Checked on 2026-08-23: neither `officer-dev` nor `alpha`
|
||||||
|
can. Both are ext4 with homes on the root filesystem, no `usrquota`/`grpquota`/`prjquota` mount options,
|
||||||
|
and neither has the ext4 `quota` or `project` feature. Enabling `project` needs `tune2fs -O project` on an
|
||||||
|
UNMOUNTED filesystem, and `/` cannot be unmounted on a running server — so it is a rescue boot, not a
|
||||||
|
config change.
|
||||||
|
|
||||||
|
The cheap moment is when a host is built, by giving the Linux homes their own filesystem with quota
|
||||||
|
features from the start. Retrofitting a live host is expensive and gets more so with every account on it.
|
||||||
|
|
||||||
|
**Where this actually matters is `edge-pertento`** — the first real multi-user deployment, and the only
|
||||||
|
one that will have accounts that are not the owner's. `officer-dev` is a development machine and will not
|
||||||
|
be multi-user; alpha is the owner's own. Check edge-pertento's disk before it gains more accounts.
|
||||||
|
|
||||||
|
**On a host that cannot enforce, the platform says so** — "policy recorded, not enforceable here" — rather
|
||||||
|
than storing numbers that do nothing. A feature that silently does nothing is worse than one that admits
|
||||||
|
it cannot.
|
||||||
|
|
||||||
## Open questions
|
## Open questions
|
||||||
|
|
||||||
1. **Does a team have its own capabilities, or only its own levels?** Whether `team_permissions` can grant a
|
None outstanding for phase 4. The four that were here are answered above.
|
||||||
capability the account's global role does not have at all. Union says yes; that may be more than wanted.
|
|
||||||
2. **Who may create a team?** Owner only, or any Admin. Bears on whether a team is an administrative object
|
|
||||||
or a self-service one.
|
|
||||||
3. **Does a team own anything?** A team folder, a team dashboard. The answer decides whether teams are
|
|
||||||
purely an authorization grouping or become a storage boundary — and the second is a much larger feature.
|
|
||||||
4. **What happens to a user's team memberships when a role is deleted?** D4 refuses to delete a role anyone
|
|
||||||
holds globally; the same question exists per team and is not answered here.
|
holds globally; the same question exists per team and is not answered here.
|
||||||
|
|||||||
Reference in New Issue
Block a user