Repository navigation
chore(objectui): move the console pin to 088e0f705520 (objectui#12175 PR-5, #12174 Q3b) (#15204 B2) - #22967
Conversation
…: position-ref / permission-ref; #12174 Q3b) (#15204 B2) Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49
…e SDUI and lockstep records at 088e0f7 (#15204 B2) Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49
📓 Docs Drift CheckThis PR changes 2 package(s): 2 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 6 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 140 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 de3991c1c0b4e2c135b6d29f7502ecd2c12946ee && git checkout de3991c1c0b4e2c135b6d29f7502ecd2c12946ee
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin a2240c4dcfc3a19f058cb0b3a4f15a351908acde 37800400315831108300e98352be75c72087be79 && git checkout -B drift-repro a2240c4dcfc3a19f058cb0b3a4f15a351908acde && git merge --no-ff 37800400315831108300e98352be75c72087be79
node scripts/docs-audit/affected-docs.mjs --json a2240c4dcfc3a19f058cb0b3a4f15a351908acde
|
|
Seat note: What red on
Why it is not this PR's: the diff (the console pin, the SDUI manifest and lockstep records, and the pin-citation re-measure) touches neither package. This is the class #22949 anchors, now ruled C2 for both timing steps plus an absolute floor (6119186511). The fix: the Generated by Claude Code |
`--check-drift` takes the run's event (`--event`), required. On `schedule`, the profile scripts/test-shard-timings.json is measured on, a DRIFT exits 1 as before; on every other event it prints the same text, raises one `::warning::` annotation and exits 0. A missing or empty event is refused. Claude-Session: https://claude.ai/code/session_012yK1ddAdAqfzwigRHZq3r2 Co-authored-by: Claude <noreply@anthropic.com>
…one, with a 20s floor The ceiling check takes the run's event (`--event`, required). On `schedule`, the profile the ceilings were measured on, a package over its ceiling reds the step as before; on every other event the same table prints, each package over its ceiling is a `::warning::` annotation, and the step exits 0. Refusals stay red on every event. A package whose effective ceiling is under CEILING_FLOOR_SECONDS (20s) is never red and prints "below floor"; the header records the floor's reading. ci.yml passes `--event "$GITHUB_EVENT_NAME"` to both timing steps, which keep no `if:` and no `continue-on-error`. Claude-Session: https://claude.ai/code/session_012yK1ddAdAqfzwigRHZq3r2 Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: PR #22967 (card #15204 B2: the console pin hop objectui ① Derived judgments1. The pin and its gate — holds. 2. The SDUI artefacts — hold. 3. The spec source edits — comments and strings only; no accept-set change. A mechanical filter over the diff (every 4. The citations —
5. The three edited tests — comment-only, no assertion moved. 6. CI on the head. 42 check-runs: 38 7. The base. The merge base is ② Semver level
③ Boundary flags
Implemented-by: VERDICT: FAIL Generated by Claude Code |
… changed — the en/zh/de packs and data-objectstack's index.ts (#15204 B2) The calendar record's packs and the curated-public-blocks record's data-objectstack/src/index.ts changed on the hop (objectui#12175); every cited line held or moved byte-identical. The pin-citations changeset says so. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49
Contract reviewServed-tier: PR #22967 (card #15204 B2: the console pin hop objectui ① Derived judgments1. FAIL point 1, the calendar record ( 2. FAIL point 2, the §4b curated-public-blocks record ( 3. FAIL point 3, the changeset and the body — now true. 4. The re-sweep — no third false hop sentence. At the head, the 5. The port (b) — exact. 6. Nothing else moved (c). 7. CI on the head (d) — 42 check-runs, all complete at 08:20Z: 38 8. The base. ② Semver levelUnchanged from ③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
Seat ACCEPT: #22967 (the console pin hop objectui
|
…e anchors (objectui#12200) (objectstack-ai#12219) Fixes objectstack-ai#12200 Clause-②: no The `position-ref` grant picker (`@object-ui/fields`, `RegistryRefField`) stops offering the `everyone` and `guest` audience anchors. A grant cannot name one: every authenticated or anonymous principal holds an anchor implicitly (ADR-0090 D5/D9), and the server refuses a `sys_user_position` row that names one. The on-record measurement is objectstack-ai/objectstack#22967's browser check (comment 6120504736): 16 positions listed, `everyone` among them. ## What changes - `position-ref` leaves out exactly the spec's `AUDIENCE_ANCHOR_POSITIONS`, read from `@objectstack/spec` and never copied, so an anchor the spec adds is left out with no change here. - A row that already stores an anchor still shows it, by its label beside its name, as its own option. It is not flagged "not found", because the registry does list it. When the row holds another value, no anchor is offered. Read-only shows the same label. - A registry that lists nothing but anchors gives the typed-name box, the LOADED-but-empty arm, now judged on what a grant can name. - `permission-ref` is unchanged: a permission set named like an anchor is listed and written as before. - There is no new prop, widget option, type member or i18n string. There is one `@object-ui/fields` patch changeset. ## H1: the mark, measured - `@objectstack/spec` exports `AUDIENCE_ANCHOR_POSITIONS` from both its root entry and `./identity`. The declaration is `declare const AUDIENCE_ANCHOR_POSITIONS: readonly ["everyone", "guest"];`. - `@object-ui/fields` declares `^17.6.0`; the lockfile installs **17.7.0**. The 17.7.0 `dist/identity/index.d.ts` re-exports it (`b as AUDIENCE_ANCHOR_POSITIONS`). A runtime import of `@objectstack/spec/identity` answers `["everyone","guest"]`. - The range floor, the **17.6.0** registry tarball, exports it from `dist/index.d.mts` and `dist/identity/index.d.ts` too. - The registry marks no item itself. `PositionSchema` has 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. - On the server, the grant refusal is `plugin-security`'s `delegated-admin-gate.ts` invariant ("audience anchor is implicit — it cannot be assigned via sys_user_position"), on objectstack `main` and on objectstack-ai/objectstack#22939's head. That gate keeps its own `new Set(['everyone', 'guest'])` and does not import the constant (see Acceptance notes). The catalog-activation gate in `packages/runtime` does import it. ## H2: which import, measured three ways `RegistryRefField.tsx` IS in the console's eager closure. The console's chunk grouping puts `packages/fields` into the eager `ui-components` chunk (the gate's chunk-membership line), and the widget's own string `fields.registryRef.loadFailed` sits in `ui-components-*.js`, which `eager-closure.json` lists. `@objectstack/spec/identity` is a lazy chunk of its own (`identity-*.js`, not in the eager list). | route | eager closure, gzip bytes vs base | `ui-components` vs its ceiling | `check:eager-closure` | `check:spec-floors`, `@object-ui/fields` | |---|---|---|---|---| | base `9646e2e` | | 281.5 KB / 282.2 KB | exit 0 | not built | | static `import … from '@objectstack/spec/identity'` (counterfactual, restored) | +6953 | 288.3 KB, over by 6.1 KB | exit 1 | not run | | lazy `import('@objectstack/spec/identity')` (commit `8bd8a14`) | +174 | 281.7 KB | exit 0 | `opaque-subpath` finding, exit 1 | | static import from the root `@objectstack/spec` (this PR, `aa16a9c`) | −5 (noise) | 281.6 KB | exit 0 | judged clean (308 pairs judged, against 307 for the lazy build) | Why `check:spec-floors` decides it: `changeset:publish` runs `scripts/check-spec-range-floors.mjs` before `changeset publish`, and so does the nightly `spec-range-floors.yml`. The gate reads symbol names from static imports only. A dynamic `import()` 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/auth` imports `BUILTIN_MEMBERSHIP_ROLES`. It keeps the suggested shape: a `Set` built from `AUDIENCE_ANCHOR_POSITIONS`, keyed on `registryType === 'position'`, one small helper (`nonGrantableNames`) beside the widget. The anchor set is known on the first render, so no catalog arm changes shape. Commit `aa16a9c` says why the lazy commit was replaced. ## H3: every `position-ref` field - objectstack `main` `6a40a09ed`: none. `git grep -c position-ref` answers 0; the control, `widget: '…-ref'` on the same tree, finds two `object-ref` declarations. - objectstack-ai/objectstack#22939 head `7de0f00c9`: exactly one, **`sys_user_position.position`** (`plugin-security`, `sys-user-position.object.ts`), beside `permission-ref` on `sys_user_permission_set.permission_set`. The server refuses an anchor there, so no field declares `position-ref` where an anchor is a valid value. - objectui: no object field declares it; only the docs examples do. ## Tests, at `aa16a9c` - New `RegistryRefField.audienceAnchors-12200.test.tsx` has 5 pins: the anchors are left out, an anchors-only registry gives the text box, a stored `everyone` shows unflagged as its own option (H4), a read-only stored anchor shows its label, and `permission-ref` lists and writes a set named `everyone` (H5). - `pnpm exec vitest run` over the six files that render the widget, run as one command: `Test Files 6 passed (6)`, `Tests 311 passed (311)`. The files are the two `RegistryRefField` suites, `widget-aria-invalid-registry-e2e`, `widget-dom-leak-e2e`, `plugin-form`'s `objectFormRegistryNameWidget-7611` and `components`' `form-data-source-wiring`. - `pnpm --filter @object-ui/fields type-check` exits 0. `tsconfig.test.json` lists the new test file. - Reverse verification ran on the committed fix. Each mutation went through `ablation-replace.mjs`, and each restore was proven by blob == HEAD with an empty `git diff HEAD`: - the filter off: 3 failed / 12 passed; - the stored anchor's own option off: 1 failed / 14 passed; - a partial list (`[AUDIENCE_ANCHOR_POSITIONS[0]]`): 3 failed / 12 passed. - Gates, run after the last commit: `check:eager-closure` 0, `check:phantom-deps` 0, `check:vi-mock-specifiers` 0, `check:vi-mock-inherit` 0, `check:vi-mock-override-shape` 0, `check:spec-symbols` 0, `check:esm-specifiers` 0, `check-changeset-presence.mjs` 0, `check:changeset-claims` 0, `check:pending-changeset-literals` 0, `check:control-bytes` 0, `check:new-line-citations` 0. - `check:spec-floors` exits 1 locally, and every one of its 15 findings is `no-artifact` for a package this tree did not build. `@object-ui/fields` was built and has no finding. A Node ESM import of the built `@object-ui/fields` dist loads. - ESLint over the two changed sources: 2 files, 0 errors, 2 `no-explicit-any` warnings (test casts, as in the 7611 suite). Type-aware linting is not configured, so the result for untouched files cannot move. ## Acceptance notes - **Docs.** `content/docs/guide/fields.md` and `packages/fields/README.md` describe `position-ref` as listing "the `position` registry" and do not mention the exclusion. They are outside this claim's file surface; one sentence in each would cover it. - **The server keeps a second copy of the list.** `delegated-admin-gate.ts`'s `ANCHOR_POSITIONS` is a literal `['everyone', 'guest']`, not the spec constant. The values agree today. Noted, not filed. - **`check:spec-floors` reads no dynamic `import()`.** A symbol taken that way is never judged against the floor. app-shell's lazy `/identity` imports (`audienceAnchorsOf`, `clientValidation`) pass only because `FlowReferenceField.tsx` imports that subpath statically. Noted, not filed. - **Headroom.** `ui-components` has 0.7 KB of per-chunk headroom before and after this PR. The next growth of `@object-ui/fields` meets that ceiling. - **Browser.** No re-check was run after this change; it needs objectstack-ai/objectstack#22939's server. Dev run for objectui#12200, seat `domain:ui#1`, session `https://claude.ai/code/session_016djJF12Qt14ejKR5Vjt4sK`. --- _Generated by [Claude Code](https://claude.ai/code/session_016djJF12Qt14ejKR5Vjt4sK)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
Part of #15204
Clause-②: no
The console pin hop
e5311165a8d6→088e0f705520(objectuimain; the merge of objectui#12175). It is the follow-up #22939 named: #22939 declareswidget: 'position-ref'/'permission-ref'on the two grant name fields of Setup's user page, and this pin brings the console that registers those widgets. Until it lands, those fields render as text inputs. #22900 waits for this PR and #22939.Tier: no governed surface (
GOVERNED_SURFACESinscripts/pm/check-governed-merges.mjs). 20 files plus #22973's ported CI files (.github/workflows/ci.yml,scripts/check-test-suite-ceilings.mjs,scripts/partition-test-shards.mjs).The hop: 3 objectui commits, all on objectui
main088e0f705, objectui#12175 (objectui#7611 PR-5): a record-form field names one registry item by name (position-reflistsGET /meta/position,permission-reflistsGET /meta/permission, and each stores the chosen name);83b9fade2, objectui#12174 (objectui#7611 Q3b): a position approver is read through the spec's registry binding{ source: 'registry', type };2498a0753, objectui#12110: the rich-text editor draws no hint lines.The pin round, as #22874's
Console Pin Gate steps, run locally (each exited 0):
turbo run build --filter=@objectstack/client....scripts/build-console.shat the pin.check:console-sha: "Console dist matches the objectui pin (objectui@088e0f705520)".check:console-injection --require-stamp.Artefacts that travel with the pin:
scripts/bump-objectui.shgenerated.changeset/console-088e0f705520.md:@objectstack/consoleminor, the level feat(spec,metadata-protocol)!: rename the type registry's allowOrgOverride to allowEnvironmentOverlay, on the registry and on GET /meta/types #22874's pin move used. It has 3 releasing entries, 0 breaking, so there is no ADR-0087 placeholder, and it carriesClause-②: no.check:objectui-changesetpasses.node scripts/gen-sdui-manifest-node.mjs:sdui.manifest.jsonis byte-identical across the hop (107 components), andscripts/sdui-manifest.record.jsonis re-recorded at the pin.check-sdui-manifestpasses.pnpm gen:sdui-lockstepre-recordspackages/sdui-parser/objectui-lockstep.jsonat088e0f705520.check:sdui-locksteppasses, so the save gate's parser and the renderer's copy agree and no port is owed.form.tsx(+3, registering the two widget hints):spanLadderForheld at:275-302, and its call site moved:3326→:3329unchanged, so theFormField.spandescribe's claim holds (re-pointed, withcontent/docs/references/ui/view.mdxregenerated);data-objectstack/src/index.ts(+33 at:5335, the adapter'slistMetadataItems): below both reads the curated-public-blocks record cites, soserializeOrderBy869-895and thetranslateFilterArrayarm5066-5077are unmoved;en/zh/depacks (fields.registryRefkeys, +4 each): the calendar record'scalendar.configRequiredstrings moved +4 and did not change;git diff --quiet, checked file by file), and each gains a hop sentence saying so. The first version of this PR said two of the three changed files were byte-identical; the contract review caught it, and378004003corrects both records and the changeset;git grep -o -F, which reproduces everye5311165a8d6figure exactly. The corpus is 8519 files, and every retired name still reads 0;check:objectui-pin-citations --verify-anchors: 55 asserting citations match088e0f705, and the 13 quoted anchors verify against objectui at the pin;.changeset/objectui-pin-citations-088e0f705520.md:@objectstack/specpatch,Clause-②: no.Browser check, against this branch's built dist
examples/app-showcasewas booted--freshwith this branch's console dist and #22939's object metadata temporarily merged in, uncommitted; #22939 is not onmainyet. As the admin on Setup's user page:registry-ref-position/registry-ref-permission), listing 16 positions and 17 permission sets;auditorandmcp_agent_data_read, then pressing Create, wrote both grant rows (verified through the data API);everyoneis still listed among the positions (the open objectui finding: the server refuses it as a grant target).Verification (local, at this head)
turbo run buildgreen;content/docs/protocol-upgrade/moved aside: that generated guide reds four tree-scan pins in any checkout where the docs app was built, as recorded on feat(plugin-security,platform-objects): grant forms pick a position or permission set by name from the catalog (#15204 B2) #22939;dispatch-gates --ran: 125 derived families, all recorded with exit 0.Acceptance notes
Test Corered on6ef50e894only on the suite-duration ceiling step (service-analytics,knowledge-ragflow), which is ci: merge-queueTest Corereds on the new suite-duration ceiling —@objectstack/cloud-connectionmeasured 177.5 s and 200.3 s vs its 163.89 s ceiling, in two groups of PRs that do not touch it (live since1bd612bd6) #22949's class and not this diff's. This branch now carries ci: Test Core's two timing gates exit-grade onschedulealone (C2), with a 20s ceiling floor #22973's two commits, cherry-picked in order (e6c7a6ce6→598bb69c1,ef3d0764b→55535f501); both scripts'--self-tests pass.position-refpicker lists theeveryoneaudience anchor.🤖 Generated with Claude Code
https://claude.ai/code/session_013XKtmoR5QCUSTMjiQ3os49