Repository navigation
Commit fc4ac58
feat(platform-objects): Add Member opened from a team binds that team (#25670)
<!-- claude-projects-attribution: {"github_login":"os-sales"} -->
_Requested by **Sales** · [project
thread](https://claude.ai/code/project/chan_01D5bWFY3rFzgJcytD5gD4Uu?thread=cmsg_01D5bWFY3rFzgJcytD5gD4UuBKyGxNYJyVxQVGvyziBNBD)_
Fixes #25337
Clause-②: no
Metadata-protocol: none
## What changes
In Setup → Teams, Add Member lived only on the team-membership list's
toolbar, where no team is in hand, so its dialog asked the administrator
to pick the team a second time. `sys_team` now declares its own
`add_team_member` action, on the team row (`list_item`) and the team
record header (`record_header`):
- It calls the same `POST /api/v1/auth/organization/add-team-member`
endpoint as the membership-list copy, behind the same gates
(`requiresFeature: 'organization'` and `requiresMembershipReach:
'add_team_member'`).
- The team's id rides as `teamId` from the row the action is opened on
(`recordIdParam: 'teamId'`), so the dialog asks only for the user
(`userId`, through the membership row's `sys_user` lookup via
`objectOverride: 'sys_team_member'`).
- The membership-list copy (`sys_team_member.add_team_member`) is
unchanged and still asks for both.
- Translations for the new action label and success message in all four
bundles; `platform-objects` patch changeset.
This is the add-member half of the card only. Under ruling C the delete
half is not done: no disabled-reason key, no computed last-team fact,
and `allowRemovingAllTeams` stays unset.
## Outside the claim's file surface
`packages/spec/src/kernel/public-auth-features.ts` gains one row,
`'sys_team.actions.add_team_member'`, in
`PUBLIC_AUTH_FEATURES.organization.gatedInputs`, immediately after
`'sys_team.actions.remove_team'`, with an `@objectstack/spec` patch
changeset (`.changeset/25337-spec-book-team-add-member.md`). The
existing `'sys_team_member.actions.add_team_member'` row (the
membership-list action) is untouched.
This sits in the `domain:spec` lane and lands here under ruling
`6370058183` (A + C) and its confirmation `6384716955`:
`feature-gate-guard.test.ts` checks the booking in both directions, so
the row can only land in the same PR as the action. A declaration is
posted on spec seat post #6017. The spec face goes through the
CONTRACT_REVIEW_TIER review before the queue.
Serial note: open PR #25626 and the second PR under #25347 each move a
different row of the same file. Neither had landed when this PR opened
(`origin/main` at `2c523d010`; the only commit since this branch's merge
of `main` touches `.claude/skills/pm-dispatch/references/**` and
`scripts/pm/check-half-states.mjs`). Whichever lands later merges `main`
and re-runs `feature-gate-guard.test.ts`.
## Tests
All readings below are on head `67affbcd1`.
- `pnpm --filter @objectstack/platform-objects exec vitest run
--maxWorkers=2 src/feature-gate-guard.test.ts
src/identity/sys-team-add-member-action.test.ts
src/platform-objects.test.ts` → 3 files, 259 tests passed (after `pnpm
--filter '@objectstack/platform-objects^...' build`, so the guard reads
the rebuilt spec `dist/`).
- `pnpm --filter @objectstack/platform-objects test` → 95 files, 1351
tests passed.
- `pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2
src/kernel/public-auth-features.test.ts src/ui/action.test.ts` → 2
files, 177 tests passed.
- `pnpm --filter @objectstack/platform-objects --filter
@objectstack/spec run typecheck` → exit 0.
- ESLint (`--no-inline-config`) on the eight changed source files → exit
0.
### Ablation: the guard turns red without the row
The guard reads `@objectstack/spec/kernel` through `exports` (the built
`dist/`), so each leg rebuilt spec and proved the marker's state in
`dist/` before the run was read.
- Mutate: `scripts/ablation-replace.mjs` deleted the row (anchor 1 → 0,
blob `bc905d9641b5` → `5b8ba535bc57`); `pnpm --filter @objectstack/spec
build`; `scripts/ablation-dist-preflight.mjs @objectstack/spec
'sys_team.actions.add_team_member' --absent` → marker absent from all
232 built files. Guard run → **1 failed | 102 passed (103)**:
```
FAIL src/feature-gate-guard.test.ts > feature-gate completeness guard
(#2874) > reverse: every features.* gate in the objects is booked in the
registry > sys_team.actions.add_team_member references registered flag
organization and is booked
AssertionError: sys_team.actions.add_team_member is booked in
organization.gatedInputs: expected false to be true
```
- Restore: blob back to `bc905d9641b5` (equal to HEAD), `git diff HEAD`
empty, whole-tree `git status --porcelain` clean; spec rebuilt;
preflight (present) → marker in 30 built files, tree clean. Guard run →
**104 passed (104)** (the booked row also adds its forward-direction
case).
## Gates
`node scripts/pm/dispatch-gates.mjs --commands` derived 91 commands for
this change set; every one was run on `67affbcd1` and recorded as `cmd
:: exit N`. All 91 exit 0. Four first answered exit 3 (PREREQUISITE NOT
MET: `check:i18n`, `check:lean-entry-closure` and
`check:dual-build-cjs-loads` needed built packages, and the
`check-plugin-teardown-shape.mjs --self-test` fixture commit was outside
the shallow clone). Each was re-run after the named prerequisite was met
(the i18n closure build; fetching the pinned fixture commit) and exited
0. `node scripts/pm/dispatch-gates.mjs --ran` → "91 derived famil(ies)
accounted for — 91 run, 0 NOT-MEASURED". Local-only `node
scripts/check-dev-prereqs.mjs` → exit 0. CI owns the type-check lanes,
Test Core, Build Core and the roster families outside the derived set.
## Acceptance notes
- No new runtime path: the action is metadata only, and it reuses an
endpoint and gates that are already served.
- `packages/plugins/plugin-auth/src/public-feature-registry.test.ts`
also imports `PUBLIC_AUTH_FEATURES`, but it reads flag names and
semantics only, never `gatedInputs`. It was not run locally (its
dependency closure is unbuilt here); CI's Test Core runs it.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01JrXUZYyTV4i588KLZRxSvJ
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 24d350b commit fc4ac58
10 files changed
Lines changed: 137 additions & 0 deletions
File tree
- .changeset
- packages
- platform-objects/src
- apps/translations
- identity
- spec/src/kernel
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
869 | 869 | | |
870 | 870 | | |
871 | 871 | | |
| 872 | + | |
| 873 | + | |
| 874 | + | |
| 875 | + | |
872 | 876 | | |
873 | 877 | | |
874 | 878 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
869 | 869 | | |
870 | 870 | | |
871 | 871 | | |
| 872 | + | |
| 873 | + | |
| 874 | + | |
| 875 | + | |
872 | 876 | | |
873 | 877 | | |
874 | 878 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
869 | 869 | | |
870 | 870 | | |
871 | 871 | | |
| 872 | + | |
| 873 | + | |
| 874 | + | |
| 875 | + | |
872 | 876 | | |
873 | 877 | | |
874 | 878 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
869 | 869 | | |
870 | 870 | | |
871 | 871 | | |
| 872 | + | |
| 873 | + | |
| 874 | + | |
| 875 | + | |
872 | 876 | | |
873 | 877 | | |
874 | 878 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
78 | 78 | | |
79 | 79 | | |
80 | 80 | | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
81 | 106 | | |
82 | 107 | | |
83 | 108 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
733 | 733 | | |
734 | 734 | | |
735 | 735 | | |
| 736 | + | |
736 | 737 | | |
737 | 738 | | |
738 | 739 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
123 | 123 | | |
124 | 124 | | |
125 | 125 | | |
| 126 | + | |
126 | 127 | | |
127 | 128 | | |
128 | 129 | | |
| |||
0 commit comments