Recording a consequence of #8095's narrowing that the ruling did not decide either way. Measured, not inferred.
What changed and what it left behind
#8095 ruled that sys_invitation read goes to owner/admin, plus a row-scope carve-out for the addressee. The implementation states the admin admission as an RLS policy in organization_admin domained by positions to the two built-in org-administration identities:
positions: [BUILTIN_IDENTITY_ORG_OWNER, BUILTIN_IDENTITY_ORG_ADMIN] // 'org_owner', 'org_admin'
delegated_admin normalizes to neither. mapMembershipRole (packages/spec/src/identity/eval-user.zod.ts) maps only owner / admin / member, and unknown values pass through unchanged — so the role reaches current_user.positions as the literal delegated_admin, matching no listed identity. It also does not receive organization_admin from the auto-grant: auto-org-admin-grant.ts tests roles.includes('owner') || roles.includes('admin') against the comma-split list, and ['delegated_admin'] contains neither as an element.
Net effect: a delegated_admin reads only invitations addressed to their own email.
Measured
Stock showcase boot, single posture, four personas against GET /api/v1/data/sys_invitation with two invitations in the org:
owner 200 total: 2 (both rows, with role + inviter_id)
member 200 total: 0
invitee 200 total: 1 (their own row)
delegated_admin 200 total: 0
Why it may matter
delegated_admin exists precisely as the invitation-issuing principal that is not an org admin (ADR-0105 D8 / #3697: better-auth grants invitation: ["create"] to owner/admin only, and under a wall-enforcing posture those two are auto-elevated to tenant admins, so the delegated grade is the one caller the scope-bounded issuance path has). It can create invitations it then cannot list. better-auth's own list-invitations route is owner/admin-gated too, so there is no second path back.
Also note docs/qa/platform-checklist/areas/identity-auth.json (the ADR-0105 D8 item) has steps phrased as "as the delegated_admin ... capture the created sys_invitation row via the data API" and "immediately read sys_invitation via the API and verify NO row was left behind". Those reads now return nothing for that persona. The item's preferred lane — the pinned packages/qa/dogfood/test/delegated-admin-invite.dogfood.test.ts — is unaffected, because it reads through ql.find under a system context. Left alone rather than edited: whether the checklist wording or the permission changes depends on the decision below.
The decision
Either:
No option is being taken here; #8095's PR ships A by default (the status quo of the ruling as written).
Filed from the #8095 implementation. Not assigned.
Recording a consequence of #8095's narrowing that the ruling did not decide either way. Measured, not inferred.
What changed and what it left behind
#8095 ruled that
sys_invitationread goes toowner/admin, plus a row-scope carve-out for the addressee. The implementation states the admin admission as an RLS policy inorganization_admindomained bypositionsto the two built-in org-administration identities:delegated_adminnormalizes to neither.mapMembershipRole(packages/spec/src/identity/eval-user.zod.ts) maps onlyowner/admin/member, and unknown values pass through unchanged — so the role reachescurrent_user.positionsas the literaldelegated_admin, matching no listed identity. It also does not receiveorganization_adminfrom the auto-grant:auto-org-admin-grant.tstestsroles.includes('owner') || roles.includes('admin')against the comma-split list, and['delegated_admin']contains neither as an element.Net effect: a
delegated_adminreads only invitations addressed to their own email.Measured
Stock
showcaseboot,singleposture, four personas againstGET /api/v1/data/sys_invitationwith two invitations in the org:Why it may matter
delegated_adminexists precisely as the invitation-issuing principal that is not an org admin (ADR-0105 D8 / #3697: better-auth grantsinvitation: ["create"]to owner/admin only, and under a wall-enforcing posture those two are auto-elevated to tenant admins, so the delegated grade is the one caller the scope-bounded issuance path has). It can create invitations it then cannot list. better-auth's ownlist-invitationsroute is owner/admin-gated too, so there is no second path back.Also note
docs/qa/platform-checklist/areas/identity-auth.json(the ADR-0105 D8 item) has steps phrased as "as the delegated_admin ... capture the created sys_invitation row via the data API" and "immediately read sys_invitation via the API and verify NO row was left behind". Those reads now return nothing for that persona. The item's preferred lane — the pinnedpackages/qa/dogfood/test/delegated-admin-invite.dogfood.test.ts— is unaffected, because it reads throughql.findunder a system context. Left alone rather than edited: whether the checklist wording or the permission changes depends on the decision below.The decision
Either:
delegated_adminissues invitations without reviewing the ledger; the checklist steps get re-phrased to read as owner/admin. Cheapest, and consistent with a literal reading of the [finding]org_membercan read every sys_invitation row in the org — other people's emails, granted roles, inviter — intended? #8095 ruling.delegated_adminto the admin-side admission (one entry in thepositionsdomain ofsys_invitation_org_admin). Gives the issuing grade visibility of what it can issue. Widens the ledger's audience by one role beyond what [finding]org_membercan read every sys_invitation row in the org — other people's emails, granted roles, inviter — intended? #8095 ruled, which is why it is not being done unilaterally.delegated_adminsee the invitations they themselves issued (inviter_id == current_user.id), not the whole ledger. Matches the "scope-bounded issuance" shape of ADR-0105 D8 more closely than B, at the cost of a third policy.No option is being taken here; #8095's PR ships A by default (the status quo of the ruling as written).
Filed from the #8095 implementation. Not assigned.