Repository navigation
feat(platform-objects): Add Member opened from a team binds that team - #25670
Conversation
Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016g7nYP9wdNx1GDa5XDr7Uy
Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016g7nYP9wdNx1GDa5XDr7Uy
Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016g7nYP9wdNx1GDa5XDr7Uy
Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JrXUZYyTV4i588KLZRxSvJ
…on gate Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JrXUZYyTV4i588KLZRxSvJ
📓 Docs Drift CheckThis PR changes 2 package(s): 38 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 8 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 144 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 760e9a9734fca1f91bb43729e106d03c6d59e28c && git checkout 760e9a9734fca1f91bb43729e106d03c6d59e28c
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 2c523d0100e9368ba8af3b08c652f23e943de46a 67affbcd18a6bab65645e73a5c707e1bc171869f && git checkout -B drift-repro 2c523d0100e9368ba8af3b08c652f23e943de46a && git merge --no-ff 67affbcd18a6bab65645e73a5c707e1bc171869f
node scripts/docs-audit/affected-docs.mjs --json 2c523d0100e9368ba8af3b08c652f23e943de46a
|
Contract reviewServed-tier: PR #25670 (draft, author objectstack-fleet[bot]) at the head above, read against origin/main at 2c523d0 (the PR's base; merge base baae6ed). Face: published schema (a non-test file under packages/spec/src), read off the committed file list. Inputs: card #25337 with all eight of its comments, the PR body and its one comment, the file list, the net diff (10 files, 137 insertions, 0 deletions) and the head's check-runs. The rest of the diff (the ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
席位核对 · ACCEPT · 2026-10-24T14:53Z
Generated by Claude Code |
Requested by Sales · project thread
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_teamnow declares its ownadd_team_memberaction, on the team row (list_item) and the team record header (record_header):POST /api/v1/auth/organization/add-team-memberendpoint as the membership-list copy, behind the same gates (requiresFeature: 'organization'andrequiresMembershipReach: 'add_team_member').teamIdfrom the row the action is opened on (recordIdParam: 'teamId'), so the dialog asks only for the user (userId, through the membership row'ssys_userlookup viaobjectOverride: 'sys_team_member').sys_team_member.add_team_member) is unchanged and still asks for both.platform-objectspatch 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
allowRemovingAllTeamsstays unset.Outside the claim's file surface
packages/spec/src/kernel/public-auth-features.tsgains one row,'sys_team.actions.add_team_member', inPUBLIC_AUTH_FEATURES.organization.gatedInputs, immediately after'sys_team.actions.remove_team', with an@objectstack/specpatch 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:speclane and lands here under ruling6370058183(A + C) and its confirmation6384716955:feature-gate-guard.test.tschecks 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/mainat2c523d010; the only commit since this branch's merge ofmaintouches.claude/skills/pm-dispatch/references/**andscripts/pm/check-half-states.mjs). Whichever lands later mergesmainand re-runsfeature-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 (afterpnpm --filter '@objectstack/platform-objects^...' build, so the guard reads the rebuilt specdist/).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.--no-inline-config) on the eight changed source files → exit 0.Ablation: the guard turns red without the row
The guard reads
@objectstack/spec/kernelthroughexports(the builtdist/), so each leg rebuilt spec and proved the marker's state indist/before the run was read.scripts/ablation-replace.mjsdeleted the row (anchor 1 → 0, blobbc905d9641b5→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):bc905d9641b5(equal to HEAD),git diff HEADempty, whole-treegit status --porcelainclean; 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 --commandsderived 91 commands for this change set; every one was run on67affbcd1and recorded ascmd :: exit N. All 91 exit 0. Four first answered exit 3 (PREREQUISITE NOT MET:check:i18n,check:lean-entry-closureandcheck:dual-build-cjs-loadsneeded built packages, and thecheck-plugin-teardown-shape.mjs --self-testfixture 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-onlynode 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
packages/plugins/plugin-auth/src/public-feature-registry.test.tsalso importsPUBLIC_AUTH_FEATURES, but it reads flag names and semantics only, nevergatedInputs. It was not run locally (its dependency closure is unbuilt here); CI's Test Core runs it.🤖 Generated with Claude Code
https://claude.ai/code/session_01JrXUZYyTV4i588KLZRxSvJ