docs(configure): define the org-membership tier vocabulary on the users page - #245
Merged
Merged
Conversation
…rs page `sys_member.role`'s four tiers (`owner`, `admin`, `delegated_admin`, `member` — ADR-0108) were used on two pages and defined on none, so a reader who met `delegated_admin` had nowhere in the corpus to go. Add a dedicated "Organization-membership tiers" section to `configure/users.mdx` — the page that already lists `sys_member` among the objects it covers. The section gives each tier a one-line meaning, states that a tier is a grade deciding what you can reach rather than a bundle of what you may do, separates `delegated_admin` from the `adminScope` mechanism documented as "Delegated administration" on the permission-sets page, and separates `sys_member` from the `sys_business_unit_member` org-tree placement the page already covers. The two consuming pages (`configure/notifications.mdx`, `build/automation/approvals.mdx`) now link to it. Those are link-only edits: no word is added or removed, only re-wrapped. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016TUrhcggSFrYctvp5dsV1A
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #153
The four-value org-membership tier vocabulary (
owner,admin,delegated_admin,member— ADR-0108,sys_member.role) was used on two pages and defined on none.A reader who met
delegated_adminhad nowhere in the corpus to go, and the nearestthing they would reach for — "Delegated administration" on the permission-sets page —
is a different mechanism.
Where the section went, and why
content/docs/configure/users.mdx, in a new## Organization-membership tierssection. Three reasons, all checkable:
configure/users.mdx:12already lists the objects the page covers andsys_memberis among them. The page had claimed the object whose
rolefield this is and thennever defined its tiers — an omission on an existing owner page, not a new home.
configure/permissions/documents what a principal may do. Upstream is explicitthat this tier is not that (
objectstack:packages/spec/src/identity/membership-role.ts):"It carries NO ObjectStack authority by construction … Role = can reach the
endpoint; adminScope = what the endpoint permits." A tier that confers no
authority, filed inside the authority model, invites the exact misreading the card
exists to prevent.
near what they govern." Near what it governs = near
sys_member.Position within the page: between "Add people" and "Place people in the org tree
(memberships)". The tier is chosen at admission — it is a value on the invitation the
preceding section just described — so this is where the chronology puts it. It also
puts the two senses of "membership" side by side, which is where a reader conflates
them, so the distinction is drawn at the seam instead of pages apart. It is deliberately
not folded into the existing memberships section: that section is
sys_business_unit_member, a different object, and merging the two would merge two ofthe three facts the spec names as "look like one — do not merge them".
What the section says, and what each claim was measured against
Everything below is read off
objectstackorigin/main, not inferred from the name:membership-role.tsBUILTIN_MEMBERSHIP_ROLE_OPTIONSownermay invite at any tierinvitation-role-cap.tsorgRoleGrade(owner = 3, the ceiling)owneris the only tier that may remove another ownerremoveMemberpredicate, quoted inmember-role-canonical.tsadminmay invite at any tier exceptownerinvitationRoleCapFailure(requested grade may not exceed the issuer's) plus better-auth'screatorRolecheckdelegated_adminmay issue invitations without being an org admin, and that reach is the whole of itMEMBERSHIP_ROLE_DELEGATED_ADMINdoc comment;isOrgAdminGradereturns false for itadminmay invite only asmemberinvitationRoleCapFailure, both refusal branchesROLE_NOT_FOUNDat better-auth's door)owner/adminmemberships are auto-granted an organization-admin permission set scoped to that organizationplugin-security/src/auto-org-admin-grant.tsThat last row is why the "grade, not a bundle" line can be stated without hand-waving:
it names where the visible power of
owner/adminactually comes from (a permissionset, on the ordinary permission path), so the tier is not left looking like the source
of it.
delegated_adminwas the value most at risk of being written wrong, so it gets its ownsubsection rather than a table cell. Its "on its own" row is the narrow, measured claim
— lets you invite a plain member, and place nobody — rather than anything the name
suggests: the invitation cap holds a below-admin issuer to plain
member, and placementauthority comes solely from a separately-granted
adminScope. Nothing about "what adelegated admin may do" is claimed beyond what those two files enforce.
The two consuming pages
configure/notifications.mdxandbuild/automation/approvals.mdxnow link to the newsection. These are link-only edits: no word is added or removed on either page —
the diff is a Markdown link wrapped around text that was already there, plus a re-wrap
so the lines stay under the files' existing width. The tier enumerations stay in place;
they are useful where they are, and removing them would have been the prose rewrite the
card ruled out.
Verification
All runs on the final commit
5c7c4a1, from the repo root, exit codes captured beforeany pipe:
pnpm turbo run build type-check test --forceTasks: 3 successful, 3 total, wrapper exit 0node .github/scripts/check-locale-surface.mjsnode apps/docs/scripts/gen-zh-hant.mjs --checknode .github/scripts/check-translation-ownership.mjsnode .github/scripts/check-translations.mjsnode .github/scripts/check-translation-output.mjs --self-testnode .github/scripts/check-node-floor.mjsThe locale-surface oracle is unchanged, and that is positive evidence. The gate
reports 79 logical pages over 8 locales = 397 docs entries. Adding a section adds no
page and drops none, and the claim is measured rather than asserted: the gate's oracle
inputs are the
content/docs/**/*.mdxpath set plus each file's frontmattertitle:,and that (path, title) set is byte-identical between
b0b159band5c7c4a1— 397pairs on both sides,
diffexit 0.apps/docs/lib/i18n.tsis untouched, andgit diff --diff-filter=ADRover the range is empty.Anchors resolve — checked against the built HTML, not assumed. No gate here catches
a broken in-page anchor. In
.next/server/app/en/docs/configure/users.html:id="organization-membership-tiers",id="delegated_admin-is-not-delegated-administration"and
id="place-people-in-the-org-tree-memberships"all present; the newhref="/docs/configure/users#organization-membership-tiers"appears once in the builtnotificationspage and twice inapprovals; and the outboundpermission-sets#delegated-administrationtarget exists in that page's built HTML. Theslug oracle was confirmed independently:
github-slugger@2.0.0reproduces the existing#layer-1--identitylink on this very page from its heading text.The rendered section was read back out of the built HTML: two tables, nine rows, no raw
pipes — a malformed MDX table degrades to a paragraph silently and no gate catches that
either.
Scope
No changeset (this repo has none). No
configure/permissions/restructuring;permission-sets.mdxis untouched (it was read in full, not as a snippet, because thenew section links into it). No locale siblings. No new page.
Possible follow-up, deliberately not done here because it is inside the section the card
put out of scope: the
sys_memberrow of the Layer 1 identity table inconfigure/permissions/index.mdxcould also link to the new section.Generated by Claude Code