Repository navigation
fix(fields): the position-ref grant picker stops offering the audience anchors (objectui#12200) - #12219
Merged
objectstack-fleet[bot] merged 4 commits intoOct 12, 2026
Conversation
…e anchors (objectui#12200)
`position-ref` listed every position the registry serves, the `everyone`
and `guest` audience anchors included, and the server refuses a
`sys_user_position` row that names an anchor (ADR-0090 D5/D9). The picker
now leaves out the spec's own `AUDIENCE_ANCHOR_POSITIONS`, read through a
lazy `import('@objectstack/spec/identity')`: the console builds this widget
into its eager `ui-components` chunk and that module is a lazy chunk of
its own. The catalog is LOADED only once the anchor list has settled too,
and a failure to read it is the FAILED arm, never an unfiltered list.
A stored anchor still shows, by its label beside its name, as its own
option and unflagged, since the registry does list it. `permission-ref`
filters nothing and does not wait on the import.
Claude-Session: https://claude.ai/code/session_016djJF12Qt14ejKR5Vjt4sK
Co-authored-by: Claude <noreply@anthropic.com>
…-ui/fields patch (objectui#12200) Claude-Session: https://claude.ai/code/session_016djJF12Qt14ejKR5Vjt4sK Co-authored-by: Claude <noreply@anthropic.com>
…t entry (objectui#12200)
The lazy `import('@objectstack/spec/identity')` kept the eager closure
flat, but `check:spec-floors`, which `changeset:publish` runs first,
judges the `@objectstack/spec` floor from static imports only: it reported
`@object-ui/fields` as reaching that subpath only where it cannot read a
symbol (`opaque-subpath`), a finding on the publish lane. A static
`/identity` import puts that module's chunk into the eager `ui-components`
chunk and over its per-chunk ceiling. The root entry's constant is the one
`@object-ui/auth` already loads eagerly, so a static import from there
costs the eager closure next to nothing, and the floor is judged.
The anchor set is now known on the first render, so the catalog arms are
back to their pre-change shape: no LOADING hold and no FAILED arm for the
anchor list. The 7611 suite's module-scope import of the identity subpath
goes with it.
Claude-Session: https://claude.ai/code/session_016djJF12Qt14ejKR5Vjt4sK
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
|
…objectui#12200) The fields guide and the @object-ui/fields README described the position-ref picker as listing the whole position registry. One sentence in each now says that it leaves out the spec's AUDIENCE_ANCHOR_POSITIONS (everyone, guest), because the server refuses an anchor as a grant target, and that a stored anchor still shows as its own option. Claude-Session: https://claude.ai/code/session_016djJF12Qt14ejKR5Vjt4sK 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
|
objectstack-fleet
Bot
deleted the
claude/issue-12200-position-picker-anchors
branch
October 12, 2026 10:20
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.
Fixes #12200
Clause-②: no
The
position-refgrant picker (@object-ui/fields,RegistryRefField) stops offering theeveryoneandguestaudience anchors. A grant cannot name one: every authenticated or anonymous principal holds an anchor implicitly (ADR-0090 D5/D9), and the server refuses asys_user_positionrow that names one. The on-record measurement is objectstack-ai/objectstack#22967's browser check (comment 6120504736): 16 positions listed,everyoneamong them.What changes
position-refleaves out exactly the spec'sAUDIENCE_ANCHOR_POSITIONS, read from@objectstack/specand never copied, so an anchor the spec adds is left out with no change here.permission-refis unchanged: a permission set named like an anchor is listed and written as before.@object-ui/fieldspatch changeset.H1: the mark, measured
@objectstack/specexportsAUDIENCE_ANCHOR_POSITIONSfrom both its root entry and./identity. The declaration isdeclare const AUDIENCE_ANCHOR_POSITIONS: readonly ["everyone", "guest"];.@object-ui/fieldsdeclares^17.6.0; the lockfile installs 17.7.0. The 17.7.0dist/identity/index.d.tsre-exports it (b as AUDIENCE_ANCHOR_POSITIONS). A runtime import of@objectstack/spec/identityanswers["everyone","guest"].dist/index.d.mtsanddist/identity/index.d.tstoo.PositionSchemahas no anchor key, and the meta read gives{ name, label }headers. The spec constant IS the mark, so no name is hard-coded here and no server-side companion is owed.plugin-security'sdelegated-admin-gate.tsinvariant ("audience anchor is implicit — it cannot be assigned via sys_user_position"), on objectstackmainand on feat(plugin-security,platform-objects): grant forms pick a position or permission set by name from the catalog (#15204 B2) objectstack#22939's head. That gate keeps its ownnew Set(['everyone', 'guest'])and does not import the constant (see Acceptance notes). The catalog-activation gate inpackages/runtimedoes import it.H2: which import, measured three ways
RegistryRefField.tsxIS in the console's eager closure. The console's chunk grouping putspackages/fieldsinto the eagerui-componentschunk (the gate's chunk-membership line), and the widget's own stringfields.registryRef.loadFailedsits inui-components-*.js, whicheager-closure.jsonlists.@objectstack/spec/identityis a lazy chunk of its own (identity-*.js, not in the eager list).ui-componentsvs its ceilingcheck:eager-closurecheck:spec-floors,@object-ui/fields9646e2eimport … from '@objectstack/spec/identity'(counterfactual, restored)import('@objectstack/spec/identity')(commit8bd8a14)opaque-subpathfinding, exit 1@objectstack/spec(this PR,aa16a9c)Why
check:spec-floorsdecides it:changeset:publishrunsscripts/check-spec-range-floors.mjsbeforechangeset publish, and so does the nightlyspec-range-floors.yml. The gate reads symbol names from static imports only. A dynamicimport()leaves the subpath unjudged, and the gate reports that as a finding, so the lazy route would have reddened the publish lane.So the PR takes a third route that the dispatch's static-or-lazy framing did not name. It imports statically from the root entry, as
@object-ui/authimportsBUILTIN_MEMBERSHIP_ROLES. It keeps the suggested shape: aSetbuilt fromAUDIENCE_ANCHOR_POSITIONS, keyed onregistryType === 'position', one small helper (nonGrantableNames) beside the widget. The anchor set is known on the first render, so no catalog arm changes shape. Commitaa16a9csays why the lazy commit was replaced.H3: every
position-reffieldmain6a40a09ed: none.git grep -c position-refanswers 0; the control,widget: '…-ref'on the same tree, finds twoobject-refdeclarations.7de0f00c9: exactly one,sys_user_position.position(plugin-security,sys-user-position.object.ts), besidepermission-refonsys_user_permission_set.permission_set. The server refuses an anchor there, so no field declaresposition-refwhere an anchor is a valid value.Tests, at
aa16a9cRegistryRefField.audienceAnchors-12200.test.tsxhas 5 pins: the anchors are left out, an anchors-only registry gives the text box, a storedeveryoneshows unflagged as its own option (H4), a read-only stored anchor shows its label, andpermission-reflists and writes a set namedeveryone(H5).pnpm exec vitest runover the six files that render the widget, run as one command:Test Files 6 passed (6),Tests 311 passed (311). The files are the twoRegistryRefFieldsuites,widget-aria-invalid-registry-e2e,widget-dom-leak-e2e,plugin-form'sobjectFormRegistryNameWidget-7611andcomponents'form-data-source-wiring.pnpm --filter @object-ui/fields type-checkexits 0.tsconfig.test.jsonlists the new test file.ablation-replace.mjs, and each restore was proven by blob == HEAD with an emptygit diff HEAD:[AUDIENCE_ANCHOR_POSITIONS[0]]): 3 failed / 12 passed.check:eager-closure0,check:phantom-deps0,check:vi-mock-specifiers0,check:vi-mock-inherit0,check:vi-mock-override-shape0,check:spec-symbols0,check:esm-specifiers0,check-changeset-presence.mjs0,check:changeset-claims0,check:pending-changeset-literals0,check:control-bytes0,check:new-line-citations0.check:spec-floorsexits 1 locally, and every one of its 15 findings isno-artifactfor a package this tree did not build.@object-ui/fieldswas built and has no finding. A Node ESM import of the built@object-ui/fieldsdist loads.no-explicit-anywarnings (test casts, as in the 7611 suite). Type-aware linting is not configured, so the result for untouched files cannot move.Acceptance notes
content/docs/guide/fields.mdandpackages/fields/README.mddescribeposition-refas listing "thepositionregistry" and do not mention the exclusion. They are outside this claim's file surface; one sentence in each would cover it.delegated-admin-gate.ts'sANCHOR_POSITIONSis a literal['everyone', 'guest'], not the spec constant. The values agree today. Noted, not filed.check:spec-floorsreads no dynamicimport(). A symbol taken that way is never judged against the floor. app-shell's lazy/identityimports (audienceAnchorsOf,clientValidation) pass only becauseFlowReferenceField.tsximports that subpath statically. Noted, not filed.ui-componentshas 0.7 KB of per-chunk headroom before and after this PR. The next growth of@object-ui/fieldsmeets that ceiling.Dev run for objectui#12200, seat
domain:ui#1, sessionhttps://claude.ai/code/session_016djJF12Qt14ejKR5Vjt4sK.Generated by Claude Code