docs(approvals): unblock main — drop duplicated role warning, generalize approver literal#3120
Closed
os-zhuang wants to merge 1 commit into
Closed
docs(approvals): unblock main — drop duplicated role warning, generalize approver literal#3120os-zhuang wants to merge 1 commit into
os-zhuang wants to merge 1 commit into
Conversation
…teral (#3113 lint fix) `lint.yml` has been red on main since #3113: the reserved-word ratchet (ADR-0090 D3) caught content/docs/automation/approvals.mdx growing 5 → 9 occurrences of "role". Every open PR inherits the failure. The four new occurrences are NOT a fifth legitimate boundary needing a baseline bump — three of them are a near-verbatim duplicate of the callout 80 lines earlier, and the fourth is an over-narrow API description: - The lifecycle Steps repeated the "type: 'role' is not a position" warning that "3. The approval node" already carries (and carries better — it names the `approval-role-not-membership-tier` lint rule). Kept the fact the lifecycle section actually needs (an unresolved approver list parks the run forever) and cross-referenced the authoritative warning instead. - `approverId` was documented as accepting `role:<r>`. The runtime falls back to a generic `` `${a.type}:${a.value}` `` literal for EVERY approver type (approval-service.ts expandApprovers), and the REST layer only splits on commas — it never validates the prefix. `<type>:<value>` is the accurate contract; `role:<r>` described one arbitrary instance of it. Net: same information, one authoritative home, no accuracy lost, and the baseline stays at 5 rather than freezing 4 avoidable occurrences. Deliberately NOT rewording the surviving 5: `role` there is the better-auth org-membership tier (`sys_member.role`), which is D3's single documented exception. It is live, not deprecated — spec `ApproverType` still enumerates 'role' alongside 'position' (approval.zod.ts, asserted in approval.test.ts) and `expandRoleUsers` resolves it against `sys_member.role`. Renaming a third-party identifier we do not own would make the docs wrong. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
Author
This was referenced Jul 17, 2026
xuyushun441-sys
pushed a commit
that referenced
this pull request
Jul 17, 2026
…l` (#3133) `ApproverType.role` was the last platform surface projecting the word ADR-0090 D3 reserved. Renaming it also unbreaks `lint.yml` on main: the role-word ratchet has been red since #3113 (approvals.mdx 5 → 9), and the docs stop needing the word once the type is spelled correctly. D3's exception does not cover this enum. It protects better-auth's own `sys_member.role` COLUMN — third-party schema we cannot rename. `ApproverType` is ours: an authoring surface, i.e. the *projection*, which D3 says is spelled `org_membership_level` and labelled "organization membership", never "role". The sentence licensing the leak is itself false. ADR-0090 D3:203 claims `sys_member.role` is "already relabelled `org_membership_level` in the platform projection (ADR-0057 D7)" — but `org_membership_level` appeared nowhere in the codebase (one comment in position.zod.ts), and ADR-0057 D7:335 lists that relabel under "Deferred (evidence-gated, P4)". The projection never landed, so the word reached authors. The name manufactured a silent failure ("hotcrm class"): every sibling surface renamed to `position` (`sys_role`, `ShareRecipientType.role`, `ctx.roles[]`), so `{ type: 'role', value: 'sales_manager' }` reads as a position's legacy spelling. It resolves against the membership tier, finds no member row, falls back to an inert `role:sales_manager` literal, and the request waits forever. Repo-wide, `type: 'role'` had ZERO real callers — only lint tests and the docs warning that exists to undo the confusion the name creates. - spec: `ApproverType` gains `org_membership_level`; `role` kept as a deprecated alias for one window so a published 15.x flow keeps loading. `DEPRECATED_APPROVER_TYPES` + `canonicalApproverType()` are the single source for the mapping (runtime and lint both read it). - plugin-approvals: resolves on the canonical type, warns on the deprecated spelling, `expandRoleUsers` → `expandMembershipTierUsers`. The `type:value` fallback literal deliberately keeps the AUTHORED spelling — 15.x wrote `role:<v>` into `sys_approval_approver` / `pending_approvers`, and canonicalising it here would orphan every stored slot. - lint: `approval-role-not-membership-tier` → `approval-approver-not-membership-tier` (the rule id carried the word too), plus `approval-approver-type-deprecated`. Mutually exclusive: a bad VALUE wins, because prescribing `org_membership_level` for a position name is wrong advice — the fix there is `position`. - docs/skill/reference + role-word baseline ratcheted DOWN (approvals.mdx 5 → 1, automation SKILL.md 3 → 1); api-surface snapshot regenerated (0 breaking, 2 added). Studio still offers "Role" and its picker calls `client.list('role')` on a metadata type D3 deleted — that picker is already dead, and the dropdown is objectui's own hardcoded copy of this enum. Tracked as objectui follow-up in degrades to free text (strictly better than a picker that lists nothing). Closes #3133. Supersedes #3120 and #3122, which only deleted the duplicated docs callout without touching the name that causes the confusion. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
xuyushun441-sys
pushed a commit
that referenced
this pull request
Jul 17, 2026
…l` (#3133) `ApproverType.role` was the last platform surface projecting the word ADR-0090 D3 reserved. Renaming it also unbreaks `lint.yml` on main: the role-word ratchet has been red since #3113 (approvals.mdx 5 → 9), and the docs stop needing the word once the type is spelled correctly. D3's exception does not cover this enum. It protects better-auth's own `sys_member.role` COLUMN — third-party schema we cannot rename. `ApproverType` is ours: an authoring surface, i.e. the *projection*, which D3 says is spelled `org_membership_level` and labelled "organization membership", never "role". The sentence licensing the leak is itself false. ADR-0090 D3:203 claims `sys_member.role` is "already relabelled `org_membership_level` in the platform projection (ADR-0057 D7)" — but `org_membership_level` appeared nowhere in the codebase (one comment in position.zod.ts), and ADR-0057 D7:335 lists that relabel under "Deferred (evidence-gated, P4)". The projection never landed, so the word reached authors. The name manufactured a silent failure ("hotcrm class"): every sibling surface renamed to `position` (`sys_role`, `ShareRecipientType.role`, `ctx.roles[]`), so `{ type: 'role', value: 'sales_manager' }` reads as a position's legacy spelling. It resolves against the membership tier, finds no member row, falls back to an inert `role:sales_manager` literal, and the request waits forever. Repo-wide, `type: 'role'` had ZERO real callers — only lint tests and the docs warning that exists to undo the confusion the name creates. - spec: `ApproverType` gains `org_membership_level`; `role` kept as a deprecated alias for one window so a published 15.x flow keeps loading. `DEPRECATED_APPROVER_TYPES` + `canonicalApproverType()` are the single source for the mapping (runtime and lint both read it). - plugin-approvals: resolves on the canonical type, warns on the deprecated spelling, `expandRoleUsers` → `expandMembershipTierUsers`. The `type:value` fallback literal deliberately keeps the AUTHORED spelling — 15.x wrote `role:<v>` into `sys_approval_approver` / `pending_approvers`, and canonicalising it here would orphan every stored slot. - lint: `approval-role-not-membership-tier` → `approval-approver-not-membership-tier` (the rule id carried the word too), plus `approval-approver-type-deprecated`. Mutually exclusive: a bad VALUE wins, because prescribing `org_membership_level` for a position name is wrong advice — the fix there is `position`. - docs/skill/reference + role-word baseline ratcheted DOWN (approvals.mdx 5 → 1, automation SKILL.md 3 → 1); api-surface snapshot regenerated (0 breaking, 2 added). Studio still offers "Role" and its picker calls `client.list('role')` on a metadata type D3 deleted — that picker is already dead, and the dropdown is objectui's own hardcoded copy of this enum. Tracked as objectui follow-up in degrades to free text (strictly better than a picker that lists nothing). Closes #3133. Supersedes #3120 and #3122, which only deleted the duplicated docs callout without touching the name that causes the confusion. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
os-zhuang
added a commit
that referenced
this pull request
Jul 17, 2026
…l` (#3137) Closes #3133. Renames the last platform surface projecting the ADR-0090 D3 reserved word: `ApproverType.role` → `org_membership_level`, with `role` kept as a deprecated alias for one window (resolves identically, warns). Publishes `xEnumDeprecated` on the node configSchema so Studio drops the deprecated spelling from the approver-type picker. Supersedes #3120/#3122. objectui half: objectstack-ai/objectui#2643 (merged). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
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.
Why
lint.ymlhas been red onmainsince #3113 — the Reserved-word ("role") docs ratchet step fails, so every open PR inherits it (e.g. #3116). Reproduces from a cleanorigin/main:#3113 added four occurrences to
content/docs/automation/approvals.mdxwithout ratcheting the baseline.The decision: reword, not a baseline bump
Both obvious framings turned out to be wrong, so the evidence is worth stating.
"
roleis deprecated, so reword it away" — false.roleis live and load-bearing:packages/spec/src/automation/approval.zod.tsstill enumerates'role'alongside'position'inApproverType— they coexist and mean different things; neither is a migration half.packages/spec/src/automation/approval.test.tsexplicitly asserts'role'parses.expandRoleUsersresolves it againstsys_member.roleat runtime.rolehere is the better-auth org-membership tier (sys_member.role:owner/admin/member) — precisely ADR-0090 D3's single documented exception ("third-party schema we do not own"). #2738 (216fa9a) did not deprecate it; it addedpositionbeside it and documentedroleas "the membership tier it actually is"."They're legitimate, so bump the baseline 5 → 9" — legitimate, but not necessary. Three of the four are a near-verbatim duplicate of the callout 80 lines earlier, and that earlier one is better (it names the
approval-role-not-membership-tierlint rule). The fourth was an over-narrow API description. The baseline is for occurrences that can't be removed without losing accuracy — these can.What changed
approverId: it was documented as acceptingrole:<r>. The runtime falls back to a generic`${a.type}:${a.value}`literal for every approver type (expandApprovers), andrest-server.tsonly splits on commas — it never validates the prefix.<type>:<value>is the real contract;role:<r>described one arbitrary instance of it.Net: same information, one authoritative home, no accuracy lost, and the reserved-word surface shrinks back to 5 instead of freezing 4 avoidable occurrences. The surviving 5 are the one better-auth boundary callout — deliberately untouched, since renaming a third-party identifier we don't own would make the docs wrong.
Verification
scripts/role-word-baseline.jsonis unmodified — the diff is one file. The siblinglint.ymldoc gates also pass locally:check:doc-authoring→199 files cleancheck:release-notes→OKNotes for the reviewer
skip-changeset.fix/role-word-approvals(no PR opened). It reaches a similar conclusion but cross-references a broken anchor (#the-approval-node; the heading is### 3. The approval node). If that agent is still active, close whichever of these lands second.🤖 Generated with Claude Code