You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Setup: changing a member's role silently auto-grants a permission set; the result never says a set was granted (#27521 row 14) #27862
Filing gate: ② a wrong or confusing state shown to the user. Split from #27521 row 14 by the seat; the parent's acceptance says each row is taken as its own card or answered.
Business reason
Who: every administrator changing a user's role. What happens: the role change grants a permission set as a side effect (e.g. organization_admin_no_bypass on the user's Permission Sets tab), but the result says nothing about it, so the administrator later finds a set on the user that nobody visibly assigned. Reach: every administrator changing a role.
Mechanism
The auto-grant runs server-side on the sys_member lifecycle (packages/plugins/plugin-security/src/security-plugin-start-hooks.ts, "Auto-grant organization_admin on sys_member lifecycle", line 438 on main; the variant choice in auto-org-admin-grant.ts); the role change's result returned to the console carries no line naming the granted set.
The ui half (labels for these cells) is the sibling card split from the same row.
Read in the 18.3.0 RC browser walkthrough at c4c515ad; the source line is confirmed on main (not re-driven).
Wanted
The role change that auto-grants a set says so in its result, naming the set by its label.
Acceptance
Changing a user's role that triggers an auto-grant returns a result naming the granted set's label.
A role change that grants nothing shows no such line.
Claim: PM loop round 2 · 2026-10-30T10:26Z
Session: session_016WV4czy9koaxQiZdkGdPYY (card thread; seat session_016WV4czuTWNgKR22fKv7jia)
Account: os-elon-musk
Branch: claude/project-thread-rvombf (the card thread's platform-assigned branch — the recorded platform exception; amended by the seat when the thread reported it)
Worktree: objectstack-issue-27862
Domain: domain:server
Seat: domain:server#3
File surface: packages/plugins/plugin-auth/src (the global after-hook on update-member-role, a new module beside it, tests), packages/platform-objects/src/identity (the two sys_member actions' outcome copy) and its generated translations, .changeset/*. Amended 10:41Z on the thread's re-measure: the answer is plugin-auth's (the after-hook where #27843 stamps outcome) and the toast copy is platform-objects'; plugin-security is untouched. ⛔ What is granted does not change. ⛔ Nothing in packages/spec or ui/.
Container & model: S, mode:thread, model: opus (TIER_DEFAULT), effort: medium
Clause-②: yes (widening: update-member-role's success answer gains outcome: 'permission_set_granted' and grantedPermissionSet; the two sys_member actions gain outcomeMessages. Amended 12:10Z from PR #28086's diff, on the #27843 / PR #27902 precedent, which declared the same shape yes (widening); a TIER_DEFAULT contract-review record by the lane seat is owed before the queue)
Metadata-protocol: none
Responsibility: the role-change answer naming the permission set the change granted (#27356 row), stamped by plugin-auth's after-hook (the #27843 shape).
Thread-read: 6515406909
Premise: unmeasured (a HotCRM 18.2.0 observation; the dev re-measures on main first)
Serial constraints cleared: no open PR touches this surface at claim time (checked against the open PR list). Re-checked 10:41Z for the amended surface: no open PR touches plugin-auth/src or platform-objects/src/identity.
Dispatch-note: p3. Dispatched on the maintainer's 2026-10-30 10:19Z message in the project ("明明有这么多任务啊", pointing at the open pm:queue + domain:server list), which the seat reads as releasing the 「低优先级的先不考虑」 hold for this queue.
{
"issue": 27862,
"status": "done",
"branch": "claude/project-thread-rvombf",
"pr": "https://github.com/objectstack-ai/objectstack/pull/28086",
"session": "session_016WV4czy9koaxQiZdkGdPYY",
"premise_still_valid": true,
"summary": "Re-measured on main 5aee2065: update-member-role answered the bare member row while plugin-security's sys_member middleware auto-granted organization_admin(_no_bypass) in the same request. plugin-auth's global before hook now reads the pair's org-admin grants and the after hook reads them again; a set held after and not before is named on the answer as outcome 'permission_set_granted' plus grantedPermissionSet {name, label} (label from the security catalog), the #27843 shape. sys_member update_member_role and transfer_ownership declare outcomeMessages naming the label, translated in zh-CN/ja-JP/es-ES. Reads only; plugin-security not in the diff, so what is granted is unchanged. File surface amended by the seat to plugin-auth + platform-objects (security-plugin.ts could not reach the answer).",
"tests": "plugin-auth role-change-granted-set.test.ts -t 27862: 9 passed (real AuthManager + better-auth route; grant written by plugin-security reconcileOrgAdminGrant). plugin-auth test: Test Files 205 passed, Tests 3904 passed | 10 skipped; typecheck exit 0. platform-objects test at head a574295a: Test Files 100 passed, Tests 1432 passed (transfer-ownership-action-copy en pin updated for the new outcomeMessages key); typecheck exit 0. Ablation 1: after-hook stamp call removed -> Tests 3 failed | 6 passed, restored (git diff HEAD empty). Ablation 2: before-snapshot ignored -> admin->owner red (1 failed | 8 passed), restored, blob == HEAD ba71c8e10d19.",
"gates": "dispatch-gates --commands: 65 derived; all 65 run with exit codes; --ran: 65 run, 0 NOT-MEASURED (derived zero, none exit 3). check:i18n / check:dual-build-cjs-loads / check-plugin-teardown-shape --self-test first exited 3 (prerequisite: build output, shallow clone), re-run after building the closure / fetching 621a4876: exit 0. Test-file-reading families re-run at head a574295a: all exit 0; derived list identical at both heads. pnpm lint narrowed: eslint --no-inline-config over the 9 changed .ts files, exit 0; repo-wide lint is CI's. CI check-runs: in_progress at report time.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
"mcp_calls": "2 — mcp__github__issue_read x2 (get, get_comments); no write tool",
"api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, #28086); relay comment (this report, POST /repos/objectstack-ai/objectstack/issues/27862/comments)",
"open_questions": [],
"out_of_scope_findings": []
}
Activity
objectstack-fleet commentedon Oct 30, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 真挡得住的权限 | none | P②
Triage: p3 ·
domain:server·area:access· first touch (retriage) · 2026-10-30T05:02Z⛔ Not a claim. This first touch was owed: a filer's labels with no triage audit, and that is triage's miss.
plugin-security start hooks), so the lane stands. The role-change result names the permission set it granted. ⛔ No change to what is granted.pm:retriageremoved.Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:server#3 · os-elon-musk · session_016WV4czuTWNgKR22fKv7jia
Claim: PM loop round 2 · 2026-10-30T10:26Z
Session:
session_016WV4czy9koaxQiZdkGdPYY(card thread; seatsession_016WV4czuTWNgKR22fKv7jia)Account:
os-elon-muskBranch:
claude/project-thread-rvombf(the card thread's platform-assigned branch — the recorded platform exception; amended by the seat when the thread reported it)Worktree:
objectstack-issue-27862Domain:
domain:serverSeat:
domain:server#3File surface:
packages/plugins/plugin-auth/src(the global after-hook onupdate-member-role, a new module beside it, tests),packages/platform-objects/src/identity(the twosys_memberactions' outcome copy) and its generated translations,.changeset/*. Amended 10:41Z on the thread's re-measure: the answer is plugin-auth's (the after-hook where #27843 stampsoutcome) and the toast copy is platform-objects';plugin-securityis untouched. ⛔ What is granted does not change. ⛔ Nothing inpackages/specorui/.Container & model:
S,mode:thread,model: opus (TIER_DEFAULT),effort: mediumClause-②: yes (widening: update-member-role's success answer gains
outcome: 'permission_set_granted'andgrantedPermissionSet; the twosys_memberactions gainoutcomeMessages. Amended 12:10Z from PR #28086's diff, on the #27843 / PR #27902 precedent, which declared the same shapeyes (widening); aTIER_DEFAULTcontract-review record by the lane seat is owed before the queue)Metadata-protocol: none
Responsibility: the role-change answer naming the permission set the change granted (#27356 row), stamped by
plugin-auth's after-hook (the #27843 shape).Thread-read: 6515406909
Premise: unmeasured (a HotCRM 18.2.0 observation; the dev re-measures on
mainfirst)Serial constraints cleared: no open PR touches this surface at claim time (checked against the open PR list). Re-checked 10:41Z for the amended surface: no open PR touches
plugin-auth/srcorplatform-objects/src/identity.Dispatch-note: p3. Dispatched on the maintainer's 2026-10-30 10:19Z message in the project ("明明有这么多任务啊", pointing at the open
pm:queue+domain:serverlist), which the seat reads as releasing the 「低优先级的先不考虑」 hold for this queue.objectstack-fleet commentedon Oct 30, 2026
domain:server#3 · os-elon-musk · session_016WV4czy9koaxQiZdkGdPYY
os-dev-report
{ "issue": 27862, "status": "done", "branch": "claude/project-thread-rvombf", "pr": "https://github.com/objectstack-ai/objectstack/pull/28086", "session": "session_016WV4czy9koaxQiZdkGdPYY", "premise_still_valid": true, "summary": "Re-measured on main 5aee2065: update-member-role answered the bare member row while plugin-security's sys_member middleware auto-granted organization_admin(_no_bypass) in the same request. plugin-auth's global before hook now reads the pair's org-admin grants and the after hook reads them again; a set held after and not before is named on the answer as outcome 'permission_set_granted' plus grantedPermissionSet {name, label} (label from the security catalog), the #27843 shape. sys_member update_member_role and transfer_ownership declare outcomeMessages naming the label, translated in zh-CN/ja-JP/es-ES. Reads only; plugin-security not in the diff, so what is granted is unchanged. File surface amended by the seat to plugin-auth + platform-objects (security-plugin.ts could not reach the answer).", "tests": "plugin-auth role-change-granted-set.test.ts -t 27862: 9 passed (real AuthManager + better-auth route; grant written by plugin-security reconcileOrgAdminGrant). plugin-auth test: Test Files 205 passed, Tests 3904 passed | 10 skipped; typecheck exit 0. platform-objects test at head a574295a: Test Files 100 passed, Tests 1432 passed (transfer-ownership-action-copy en pin updated for the new outcomeMessages key); typecheck exit 0. Ablation 1: after-hook stamp call removed -> Tests 3 failed | 6 passed, restored (git diff HEAD empty). Ablation 2: before-snapshot ignored -> admin->owner red (1 failed | 8 passed), restored, blob == HEAD ba71c8e10d19.", "gates": "dispatch-gates --commands: 65 derived; all 65 run with exit codes; --ran: 65 run, 0 NOT-MEASURED (derived zero, none exit 3). check:i18n / check:dual-build-cjs-loads / check-plugin-teardown-shape --self-test first exited 3 (prerequisite: build output, shallow clone), re-run after building the closure / fetching 621a4876: exit 0. Test-file-reading families re-run at head a574295a: all exit 0; derived list identical at both heads. pnpm lint narrowed: eslint --no-inline-config over the 9 changed .ts files, exit 0; repo-wide lint is CI's. CI check-runs: in_progress at report time.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "2 — mcp__github__issue_read x2 (get, get_comments); no write tool", "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, #28086); relay comment (this report, POST /repos/objectstack-ai/objectstack/issues/27862/comments)", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:server#3 · os-elon-musk · session_016WV4czuTWNgKR22fKv7jia
ACCEPT → PR #28086 comment 6522879117 · 2026-10-30T12:30Z · contract review PASS 6522494596 (Clause-② yes (widening); the PR body's
noline is corrected there) · ready + auto-merge armed through the relay.