Repository navigation
fix(app-shell): the pre-publish capability lint reads the registry's capabilities; isolated tenant-admin assignment re-verified (#7611) - #13361
Merged
objectstack-fleet[bot] merged 4 commits intoOct 23, 2026
Conversation
…proverIdentity `position` has been registry-bound in the installed spec since 18 (objectstack#22710), so no `data` approver binding names `sys_position` and its `DISPLAY_FIELDS_BY_OBJECT` row is read by nothing. The `approverValueIsName` docblock still said `position` answers through the data arm; it now names the registry arm. `useApproverDirectory`'s header listed `sys_position` among the directory objects it reads and used it as the label-leg example; both re-worded to the registry read. Part of objectui#7611 (release record 6357827416, item 2). Claude-Session: https://claude.ai/code/session_01WvJkpohCWbizJavd86HTZz Co-authored-by: Claude <noreply@anthropic.com>
…capabilities `validateCapabilityReferences` resolves a reference against the built-in capabilities, `stack.capabilities` (the `defineCapability` declarations) and `systemPermissions` grants. The console's pseudo-stack carried the first and the last only, so a capability a package declares with `defineCapability` and no permission set grants was reported as resolving nowhere on Publish from Home. Measured live against objectstack main 830a63a: an object draft requiring `showcase.restricted_ops` raised "2 capability reference(s) resolve nowhere" beside a misspelled control; with the registry list read, only the misspelling is reported. The pseudo-stack now carries `GET /api/v1/meta/capability`. A failed read leaves the pass on its other sources, still advisory. Part of objectui#7611 (release record 6357827416, item 3). Claude-Session: https://claude.ai/code/session_01WvJkpohCWbizJavd86HTZz Co-authored-by: Claude <noreply@anthropic.com>
…s against Part of objectui#7611 (release record 6357827416, item 3). Claude-Session: https://claude.ai/code/session_01WvJkpohCWbizJavd86HTZz Co-authored-by: Claude <noreply@anthropic.com>
…changeset Claude-Session: https://claude.ai/code/session_01WvJkpohCWbizJavd86HTZz Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Contributor
Author
席位核对ACCEPT — objectui#7611 (p1, M), head Seat: domain:ui#1 · Clause-②: no
|
objectstack-fleet
Bot
deleted the
claude/issue-7611-isolated-assign-reverify
branch
October 23, 2026 12:45
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.
Requested by Sales · project thread
Fixes #7611
This closes the remainder that release record 6357827416 left on #7611. All three items are done: one is a measurement with no source change, one is a cleanup with no behaviour change, and one is a fix for a lint warning that reproduced.
Clause-②: no
Metadata-protocol: none
1. Under
isolated, a tenant admin still assigns through the Setup picker (measured, no change needed)Rig. objectstack framework built at
main830a63a6, a descendant of448374d3f8(objectstack-ai/objectstack#24136, PR objectstack-ai/objectstack#24732). The app-showcase app plus@objectstack/organizationswas booted twice withos dev --seed-admin --fresh:OS_TENANCY_POSTURE=isolatedwithOS_AUTH_MEMBERSHIP_POLICY=invite-only(port 4011). The boot banner readsTenancy: isolated.single(port 4010). The boot banner readsTenancy: single.This branch's console ran against each server. Personas were minted through
/api/v1/auth/admin/create-user, then change-password,organization/create,invite-memberandaccept-invitation. Tara Tenant owns Acme Tenant: her/me/permissionslistsorganization_adminandisPlatformAdmin: false. Mia Member and Noah Newhire are members. Playwright drove the real pages at/apps/setup/metadata/{position|permission}/<name>?scope=environment, clicked Add holder or Add user, and picked the user in theRecordPickerDialog. Every/apiresponse was recorded.isolated, tenant admin Tara:contributor, add holder MiaPOST /api/v1/data/sys_user_position{"user_id":"fnBt…","position":"contributor"}organization_id= Acme Tenant, and Mia appears in the holders list.field_ops_delegate, add holder MiaPOST /api/v1/data/sys_user_positionorganization administrator 'insert' on 'sys_user_position' rejected — position 'field_ops_delegate' carries permission set 'showcase_field_ops_delegate', which fails condition (b) of the organization boundary: it carries an adminScope…. The page shows the server's sentence.showcase_contributor, add user NoahPOST /api/v1/data/sys_user_permission_set{"user_id":"AE0q…","permission_set":"showcase_contributor"}admin_full_access, add user NoahPOST /api/v1/data/sys_user_permission_setpermission set 'admin_full_access', which is outside the organization boundary by name…showcase_contributorDELETE /api/v1/data/sys_user_permission_set/Hl81…contributorDELETE /api/v1/data/sys_user_position/Qzul…Across 393 recorded responses, none went to the retired
sys_position,sys_permission_set,sys_position_permission_setorsys_capabilityobjects.single, unchanged:contributor, add user to setshowcase_contributororganization_admin_no_bypass)manager, add user to setshowcase_executiveadmin_full_accessmanagerholderUnder
single, an org admin now assigns inside the boundary as well. That is objectstack-ai/objectstack#24136's grant, which is not specific toisolated, and the console follows the server's grant with no posture branch. The platform admin's path is the same as before.2. Dead
sys_positiondisplay entry removed (internal, no behaviour change)packages/app-shell/src/utils/approverIdentity.ts: removedsys_positionfromDISPLAY_FIELDS_BY_OBJECT. Nodatabinding names it, because the installed spec bindspositionto the registry (feat(spec)!: approver and decision-output positions are names from the metadata registry (ADR-0131 D4) objectstack#22710).approverValueIsNamedocblock now describes the registry arm and thedataarm as they are.packages/app-shell/src/hooks/useApproverDirectory.ts: comment-only. Its docblock still listed a position row among the directory objects it reads.3. The pre-publish capability lint read no registry capabilities (reproduced, fixed)
@objectstack/lint'svalidateCapabilityReferencesresolves a reference against three sources: the built-in capabilities,stack.capabilities(thedefineCapabilitydeclarations) and every permission set'ssystemPermissions.lintDraftCapabilityReferencesbuilt a pseudo-stack with nocapabilities. So a capability declared withdefineCapabilityand granted by no set was reported as resolving nowhere on every draft that required it.Measured live on the
singlerig with Publish from Home. Two object drafts were used. One requiresshowcase.restricted_ops:GET /api/v1/meta/capabilityserves it, and no permission set grants it. The other requires the misspellingshowcase.restricted_opz.restricted_ops) and one real (the typo).Fix (
packages/app-shell/src/preview/capabilityLint.ts): the pseudo-stack now carriescapabilitiesread fromclient.list('capability', {}), unwrapped and stripped the same way as the permission rows. If that read fails, the list is empty, so the lint runs on the other sources and stays advisory.Tests
capabilityLint.registryCapabilities-7611.test.tsruns the realvalidateCapabilityReferences, not a stand-in. It has four cases: the registry serves the capability; the row comes in an{ item }envelope; a CONTROL where the registry is empty and both drafts warn; and a failed capability read, which still gives two warnings and does not throw.capabilities,removed from the stack, 2 of the 4 new tests fail (Tests 2 failed | 2 passed (4)). Restoring gives blob3a9ac204= HEAD.pnpm exec vitest run packages/app-shell/src/preview packages/app-shell/src/utils/approverIdentity packages/app-shell/src/hooks/useApproverDirectory: 34 files, 252 tests passed.Gates
turbo run type-check --filter=@object-ui/app-shell(it builds the workspace dependencies first) passes: 30 of 30 tasks, exit 0.eslinton the four touched source and test files: 0 errors. There are 7no-explicit-anywarnings, all on lines this diff does not change.These checks all pass:
check-changeset-presence,check-changeset-claims,check-pending-changeset-literals,check-changeset-no-major,check-changeset-fixed,check-control-bytes,check-test-path-roots,check-vi-mock-specifiers, andcheck:new-line-citations(0 new citations).File surface
Everything is inside the claimed surface except two files, both declared here:
useApproverDirectory.ts: comment-only, the same stale position wording as item 2.content/docs/guide/console.md: one sentence naming the sources the capability lint resolves against (AGENTS.md: docs-driven).The branch is
claude/issue-7611-isolated-assign-reverify. It is based onmain2c4e5f5, andmainhas not moved since.Generated by Claude Code
🤖 Generated with Claude Code
https://claude.ai/code/session_01WvJkpohCWbizJavd86HTZz