Skip to content

fix(components): action:bar / action:group / action:menu members evaluate properties.params like a top-level action:button (objectui#10290) - #10786

Merged
objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-10290-member-params-evaluated
Sep 27, 2026
Merged

objectstack-fleet[bot] merged 5 commits into
mainfrom
claude/issue-10290-member-params-evaluated

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #10290
Clause-②: yes (widening)

What changed

  • action:bar evaluates an inline member's properties where it composes the member for action:button / action:icon (withEvaluatedProperties in static-params.ts). An overflow member goes to the bar's action:menu as authored, and that renderer evaluates it when it runs it, so no value is evaluated twice.
  • action:group and action:menu read an item's properties.params, evaluated with the same evaluator (readMemberStaticParamValues), and forward it as ActionDef.params. An item that carries an ActionParam[] list forwards both channels, as action:button does. A node-level object params keeps its objectui#10462 handling: dropped with one development warning; the type: 'api' window is unchanged when the item carries no properties.params; when it carries both, properties.params is forwarded and the node-level object is dropped without a warning.
  • @object-ui/react: the memo's per-key rule, its scope builder and its properties loop move from the memo closure to module scope in SchemaRenderer.tsx (evaluateConfigValueWith, configEvaluationScope, evaluateConfigBagWith). The memo calls them; its behaviour is unchanged. New exports: useConfigBagEvaluator() (hooks/useConfigBagEvaluator.ts) and its plain half evaluateConfigBagInScope() (SchemaRenderer.tsx). File-surface widening, declared: the route needs these exports.
  • Changeset .changeset/10290-container-member-params-evaluated.md: @object-ui/components patch, @object-ui/react minor (Clause-② widening: two new public exports; the fixed group releases at that minor).

H1: premise, measured on base 17b323e5ca

Instrument: a one-off probe (not committed) that printed each handler's params, then the committed pin file run at the base in a detached control worktree. The page is a record page bound through RecordContextProvider to { id: 'rec_1' }. The member is authored properties.params: { objectName: 'account', recordId: '${record.id}' }, and the handler is navigate_edit.

path params the handler received template evaluated
CONTROL: top-level action:button through SchemaRenderer { objectName: 'account', recordId: 'rec_1' } yes
action:bar inline member { objectName: 'account', recordId: '${record.id}' } no, raw
action:bar member, component: 'action:group' same raw object no, raw
action:bar member, component: 'action:menu' (overflow) undefined values dropped
action:bar member spilled past maxVisible undefined values dropped
action:group, inline display undefined values dropped
action:group, dropdown display undefined values dropped
action:menu undefined values dropped

The component: 'action:icon' bar row was added to the pin after the probe. It is red on base in the pin run below.

So PR objectui#10460 evaluates on none of the three containers, and the premise holds. The overflow, group and menu paths did not read properties.params at all.

H2: the evaluator and the route

  • The evaluator. Inside SchemaRenderer's evaluatedSchema memo, evaluateConfigValue(key, value) does the work. A params bag goes through mapParamsLeaves (utils/paramsBag.ts) with a visitor that calls evaluator.evaluate on each string leaf. Any other value goes through ExpressionEvaluator.evaluate per value, with a CEL envelope preserved and a data object passed through. evaluator is new ExpressionEvaluator(scope) from @object-ui/core. Its scope is the ambient predicate scope, plus current_user (an alias of user), plus record (the RecordContext row, only when one is bound), plus page (page variables). None of this was exported before this PR.
  • Route (a) taken: each container calls that rule with that scope.
  • Route (b) not viable. Dropdown items (the action:group dropdown, action:menu, and the bar overflow) are DropdownMenuItem leaves, not registry nodes, so SchemaRenderer cannot mount them. For inline members, (b) would also run the properties hoist on each member, a second run of the node visibility and enablement gate, and the data-obj-* and style plumbing. That is a wider behaviour change than the card asks for.
  • Scope each container has at hand. Four sources: the host's data row prop (what the members' visible / disabled predicates bind as record), the RecordContext row, page variables and the ambient predicate scope. The last three are the contexts SchemaRenderer reads, and the containers render under the same providers. useConfigBagEvaluator reads exactly the memo's three inputs. So a member's templates bind the RecordContext row, as a top-level action:button's do. The data prop is not bound into the template scope, and SchemaRenderer does not bind it either.
  • Why the hook lives in hooks/ and not in SchemaRenderer.tsx. Measured: a hook declared in SchemaRenderer.tsx puts that file under the React Compiler lint. The lint then reports three pre-existing render-time performance.now() / Date.now() debug probes as react-hooks/purity errors (0 without the hook, 3 with it).

H3: visible / disabled on these paths

Measured on base with a one-off probe on the same 7 paths plus the control. The predicates were record.id == 'rec_1' (true on the page), record.id == 'rec_2' (false), disabled: record.id == 'rec_1', and the template form ${record.id == 'rec_1'}.

  • With the host's data row passed (as DetailView passes data={data}): all 8 rows evaluate correctly. True renders, false is absent, disabled-true is disabled, and the template form renders. This is identical to the control. These gates are evaluated already, and nothing was widened.
  • Without a data row (RecordContext only): record is unbound on the predicate tier, which binds record from the data prop through usePredicateRecordContext. The predicates fault: fail-closed (absent) on the action:button / action:menu leaves, fail-soft (shown) on the action:group leaves. The control top-level action:button does the same. This is not container-specific. It is recorded under Acceptance notes, with no card.

Pins and ablation

New file packages/components/src/renderers/action/__tests__/action-container-member-params-10290.test.tsx, 17 tests:

  • CONTROL: a top-level action:button through SchemaRenderer resolves ${record.id}. Green on base and head.
  • 8 paths × "the handler receives properties.params with ${record.id} resolved". The paths are: bar inline, bar action:icon, bar group-placed, bar menu-placed, bar spilled past maxVisible, group inline, group dropdown, and menu.
  • 8 paths × "a node-level params OBJECT is still not a values channel, and says so once" (ruling A).

Red on base, green on head:

  • base 17b323e5ca (control worktree, same test file): Tests 8 failed | 9 passed (17). The 8 failures are exactly the 8 "resolved" rows. The control and the 8 node-level rows are green.
  • head e8b96c0161: Tests 17 passed (17).

Ablation: one leg, through objectstack scripts/ablation-replace.mjs in WRAP mode, on the committed head. In packages/react/src/hooks/useConfigBagEvaluator.ts, the anchor evaluateConfigBagInScope(bag, predicateScope, boundRecord, pageVariables); became bag; /* ABLATION-10290 */, so the hook hands the bag back unevaluated.

  • Predicted: the 8 resolved rows go red, and the control and node-level rows stay green.
  • Observed: anchor 1 → 0, blob 8b01c529 → f4c00a8f, and Tests 8 failed | 9 passed (17).
  • Restore: blob == HEAD 8b01c529, and git diff HEAD is empty.
  • No build leg: the suite resolves @object-ui/react through the root vitest.config.mts alias to packages/react/src, so the mutated source is what ran.

Gates

At head e8b96c0161 unless noted.

  • vitest union (repo root): packages/components/src/renderers/action/, packages/react/, and the scripts tests for check-action-forward-parity (plus its closing-keyword test), check-doc-expression-carriage and check-component-surface-parity. Result: Test Files 130 passed (130), Tests 1883 passed (1883), lock VERDICT command-exit 0.
  • type-check (tsc --noEmit && tsc -p tsconfig.test.json) for @object-ui/react and @object-ui/components: Done / Done at a60555f057, after pnpm --filter @object-ui/react build. The only later commit is changeset text.
    • The components test tsconfig includes the new pin file (--listFilesOnly count 1).
    • dist/hooks/useConfigBagEvaluator.d.ts is the only declaration of the hook in dist, so the green components type-check read the rebuilt .d.ts.
  • eslint on the 8 changed .ts / .tsx files, with inline config on (as eslint . runs per package): 0 errors, 48 warnings.
    • Population: the root eslint.config.js has files: ['**/*.{ts,tsx}'], and there is no package-level config in packages/react or packages/components.
    • File count: 8, from --format json.
    • No type-aware linting is configured (no parserOptions.project or projectService), so this diff cannot move a verdict on an untouched file.
    • The same 5 pre-existing files at base: 0 errors, 49 warnings. SchemaRenderer.tsx has 2 fewer no-explicit-any and 1 more react-refresh/only-export-components (for the new plain export).
  • Green:
    • check:action-forward-parity, check:new-line-citations (0 new), check:control-bytes, check:handler-key-reads, check:self-import.
    • check:unreferenced-sources, check:phantom-deps, check:unused-deps, check:side-effects-array, check:component-surface-parity (report-only).
    • check:changeset-claims (report-only). The four pending changesets it names for SchemaRenderer.tsx were read, and none is falsified.
    • check:pending-changeset-literals, check:test-path-roots, check:vi-mock-specifiers, check-changeset-presence.mjs, check-changeset-no-major.mjs, check-doc-expression-carriage.mjs.
  • NOT MEASURED: check:eager-closure. Reason: exit 2, PREREQUISITE NOT MET. There is no apps/console/dist/eager-closure.json, which needs a console build. Declared to CI.
  • CI's runs: repo-wide pnpm lint and the full pnpm test.

Serial

  • PR objectui#8941, head bb7d5e71, was fetched into a private ref. git merge-tree --write-tree of HEAD against it exits 0 with no conflicts. It touches action-bar.tsx, and the merge is clean.
  • origin/main at bf14b646 (5 commits past the base): merge-tree exits 0. None of those commits touch this PR's files, so there is no merge commit.

Acceptance notes

  • Docs. content/docs/guide/record-edit-modes.md teaches properties.params on a top-level action:button only. The same authoring now works on a container member. The guide was not edited, because it is outside this order's file surface. If it is extended, it needs one caveat: the development-build unevaluated-expression diagnostic runs in the SchemaRenderer memo, so an unresolvable template on a container member reaches the handler raw without that report. Carrier: none named.
  • Boundary. element:button's inline action and page:header's actions still read no properties.params. They are objectui#10462 surfaces, not containers.
  • Boundary. Take an action:bar member of type: 'api' with an object params. The overflow action:menu reads it (the objectstack#5777 window, entry semantics), and the inline path ignores it (action:button semantics). This dates from objectui#10460 and objectui#10462, and is not changed here.
  • Observation (H3). The predicate tier binds record from the host's data prop, and the template tier binds it from RecordContext. On a host that provides RecordContext but no data, a record.* predicate faults while a record.* template resolves. This predates this PR and is identical on a top-level action:button. It was not measured on a real host page.
  • The two new @object-ui/react exports are declared minor (Clause-② widening).

Session: https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN


Generated by Claude Code

…like a top-level action:button (objectui#10290)

A member of action:bar, action:group or action:menu is drawn by its
container and never passes through SchemaRenderer, so the evaluation that
resolves `${record.id}` inside properties.params never ran for it. The bar's
inline members reached the handler with the raw template, and overflow,
group and menu items did not forward properties.params at all.

Each container now evaluates its members' properties with the
SchemaRenderer memo's own per-key rule and scope, exported from
@object-ui/react as useConfigBagEvaluator(). action:bar evaluates an inline
member where it composes it; action:group and action:menu evaluate an item
when they run it, so an overflow member is evaluated once. A node-level
params object is still not read as values.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN
…559 on UIActionSchema)

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN
…r exports its plain half (objectui#10290)

A hook declared in SchemaRenderer.tsx puts that file under the React
Compiler lint, which then reports three pre-existing render-time
performance.now() / Date.now() debug probes as react-hooks/purity errors
(measured: 0 errors without the hook, 3 with it). The hook moves to
hooks/useConfigBagEvaluator.ts; SchemaRenderer.tsx exports the plain
evaluateConfigBagInScope() it calls, which applies the memo's own per-key
rule and scope. The scope builder's predicate scope is typed unknown
instead of any. The pin test's schema cast names BaseSchema.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN
…luator (objectui#10290)

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN
@github-actions

github-actions Bot commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

changeset-claim-re-read

⚠️ 4 pending changeset(s) describe a file this change touches

Their bodies publish verbatim into the CHANGELOG at the next release, so this is a request to re-read them against your diff — addressed here because you are the one seat that can answer it without re-deriving anything.

⛔ Nothing here blocks, and nothing here is a verdict on your change. This gate exits 0, is not a required context, and judges name resolution, never meaning: it asked whether a pending body names a file you touched. "Is this sentence still true?" is the one question it will not answer, and the one you are being asked to answer.

.changeset/5926-empty-action-visible-when.md

  • names packages/react/src/SchemaRenderer.tsx → packages/react/src/SchemaRenderer.tsx — edited by this change

    visibleWhen is not a per-block concern in this platform. It is enforced once, generically, in packages/react/src/SchemaRenderer.tsx: shouldHide tests visibleWhen ahead of the hoisted visible (objectui#5454), sets _hidden, and the _hidden early return fires before the registry dispatches. A block renderer cannot ignore the gate, because it never sees the node.

.changeset/7319-dead-schemarenderer-retired.md

  • names packages/react/src/SchemaRenderer.tsx → packages/react/src/SchemaRenderer.tsx — edited by this change

    packages/components/src/SchemaRenderer.tsx was a 28-line component carrying the same export name as the real renderer in packages/react/src/SchemaRenderer.tsx. Nothing reached it: it is absent from the package barrel, no file in the repo imports it by any form, and the package's exports map has no subpath that resolves to it.

.changeset/7415-action-type-input-rename.md

  • names SchemaRenderer.tsx → packages/react/src/SchemaRenderer.tsx — edited by this change

    Census of the authored corpus, measured before the rename, not assumed. Across 4,797 files in examples/, apps/console/, content/docs/ and packages/: zero authored nodes set the input. 517 JSON files (433 of them the schema catalog) contain 2,410 type-bearing nodes and no action:button / action:icon node at all — control: 127 plain button nodes on the same walk. 207 parsed fenced JSON blocks in md/mdx carry 5 action:button nodes, all of them { type, label, icon?, action } — the discriminator plus the action channel, none setting an execution type — control: 28 plain button nodes, and the count independently matches the corpus census already recorded in SchemaRenderer.tsx ("action:button (5 nodes)"). No docs page documents the input; no catalog entry uses the components. So the rename breaks no authored document in this repo.

.changeset/9959-refused-data-prop-warn-reset.md

  • names SchemaRenderer.tsx → packages/react/src/SchemaRenderer.tsx — edited by this change

    The dedupe Set behind the objectui#9571 / objectui#9758 diagnostic — "the authored data key was NOT passed to the component as a React prop" — lived in SchemaRenderer.tsx with nothing able to clear it, while every other dev diagnostic in this package's utils/ directory pairs its Set with an exported test-only reset. propsBagDiagnostic.ts states the consequence in its own reset's docblock: the second test to assert the same warning reads the first test's dedupe entry and sees silence, "a green run that checked nothing". The absence direction is the dangerous one — a test asserting this warning did NOT fire for a type#id an earlier test already warned for is green whatever the renderer does, and it reports that green as coverage.

Read the paragraph, not the line: both false halves of the objectui#8617 claim sat in one paragraph, and correcting either alone would have left it asserting the same wrong thing.

If a claim did go false, correct the body. That is precedented and prose-only, frontmatter untouched; check-changeset-overwrite.mjs will report the correction as its own case 2 ("correcting a declaration on purpose … legitimate"), which is the intended shape — one gate asks for the read, the other records the write.

Not covered, stated so nobody reads this as more: a born-false claim that spells no line address at all (objectui#9495 coordinated one by ORDINAL — "a grep finds that member first" — and deciding that means reading what the sentence means), a claim spelled as a symbol or a package rather than a backticked file name, and a file named ambiguously.

Compared the checked-out tree with 29b45f6a0 (merge-base with origin/main): 8 file(s) changed outside .changeset/, read against 1588 pending declaration(s) that publish a body (2176 pending in total). · run

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3068.5 KB 3104.5 KB
Main entry chunk (gzip) 148.3 KB 350 KB
Entry file index-BQkwOhhq.js —
Status PASS —

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

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.57KB 6.15KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.17KB 10.58KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.52KB 3.45KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 555.39KB 132.79KB
core (index.js) 9.57KB 3.81KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 223.93KB 62.31KB
fields (index.js) 259.29KB 65.66KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.28KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 51.65KB 14.69KB
plugin-charts (index.js) 82.37KB 22.57KB
plugin-chatbot (index.js) 198.40KB 47.22KB
plugin-dashboard (index.js) 134.11KB 35.62KB
plugin-designer (index.js) 216.25KB 44.39KB
plugin-detail (index.js) 233.23KB 61.74KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 158.35KB 40.47KB
plugin-gantt (index.js) 169.75KB 41.96KB
plugin-grid (index.js) 218.12KB 59.72KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 114.70KB 28.42KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.55KB 11.99KB
plugin-timeline (index.js) 30.91KB 9.05KB
plugin-tree (index.js) 10.58KB 3.72KB
plugin-view (index.js) 87.83KB 22.01KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 119.16KB 39.05KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 7.50KB 3.05KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.16KB 2.71KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 18.27KB 6.20KB
types (ai.js) 4.11KB 2.06KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

…ening)

Contract review on e8b96c0 (FAIL, text/semver only) found that two new
`@object-ui/react` exports (`useConfigBagEvaluator`, `evaluateConfigBagInScope`)
widen the published surface, so the bump must be `minor`, not `patch`. The
changeset's paragraphs 2-4 are replaced with the review's corrected text (fixes
the self-contradictory api-window sentence, the "returns the memo's own
evaluation" overstatement, and the false "SchemaRenderer applies the same rule
through it" claim), and a new paragraph declares the minor as Clause-②
widening.

`static-params.ts` gets two comment-only fixes: the group/menu parenthetical
now says the `properties.params` channel is read off the authored object (no
declared `properties` key on `UIActionSchema`), not off a declared key; and
Zone 1's docblock now says a container member is evaluated by its container
with the same rule and scope, since it never passes through `SchemaRenderer`.
No code line changed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014mXUNuFomfj24w7s1pZzhN
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: e8b96c0161780a3bbf6f0d4f3cbfd51f90de6400

① Derived judgments

Everything below comes from reading the code. No probe was run: nothing needed execution to settle.

  • One evaluator, not two: holds.
    • configEvaluationScope, evaluateConfigValueWith and evaluateConfigBagWith are line-for-line the base memo's code:
      • the scope has the same spread order: predicateScope, then current_user from predicateScope?.user, then record only when the row is a non-array object, then page;
      • the per-key rule is the same ternary: params bag, data object, preservePredicateEnvelope;
      • the loop is the same { ...bag } plus per-entry overwrite.
    • The memo now calls all three: new ExpressionEvaluator(configEvaluationScope(...)), evaluateConfigValue delegates to evaluateConfigValueWith, and newSchema.properties = evaluateConfigBagWith(evaluator, rawPropertiesBag). The node-level params leg and rawPropertiesBag (used by the objectui#5756 diagnostic) are unchanged.
    • Ordinary SchemaRenderer nodes see no behaviour change.
    • evaluateConfigBagInScope builds a fresh evaluator from those same pieces. SchemaRenderer itself never calls it (this falsifies a changeset sentence; see ②).
  • Double evaluation: none on any path.
    • Bar inline members: action:button, action:icon, and group-placed members routed to action:button. The bar evaluates them once in renderMember. Neither action-button.tsx nor action-icon.tsx evaluates again; they only read readStaticParamValues. No SchemaRenderer sits between them.
    • Bar overflow (menu-placed, spilled, and systemActions): combinedOverflow is passed raw, and action:menu evaluates it once, at run time.
    • action:group inline and dropdown, and action:menu: evaluated once, in handleExecute.
    • A bar node's own actions array is not walked by the memo, which is shallow, and no host found pre-evaluates members.
    • The "evaluated once" claim is true but not pinned. No test uses a row value that itself contains ${…}.
  • Scope parity: holds.
    • The hook reads exactly usePredicateScope(), useRecordContext()?.data and usePageVariables().variables, the same three the memo reads.
    • SchemaRenderer renders no provider between itself and its renderer, so a container reads the same contexts a member's own SchemaRenderer would.
    • current_user is bound the same way, the CEL envelope is kept, and a data object passes through, all through the shared rule.
  • Ruling A: code holds; one text gap.
    • A node-level object params is still ignored with exactly one warning on every path:
      • bar inline, through readStaticParamValues;
      • group, menu and bar overflow, through readActionEntryParamValues, still called on the non-array branch.
    • The pins check this on all 8 paths.
    • New silent case: a type: 'api' group/menu item that carries both a node-level object and properties.params. properties.params now wins, and the objectstack#5777 payload is dropped with no warning. The PR body says the api window is "unchanged" in the same bullet where it says properties.params wins over it; that is self-contradictory (wording fix in ②).
    • Docblock rewrite: the new sentence is true in behaviour at head.
      • Group/menu items read properties.params.
      • element:button reads only readActionEntryParamValues; elements.tsx:248 confirms it.
      • page:header never reads properties.params: containers.tsx:1851 dispatches the action itself and never mounts action:menu.
    • It is not consistent with Zone 1, the file-top docblock. Zone 1 justifies properties.params as "the node's already-declared config bag", but UIActionSchema (packages/types/src/ui-action.ts:568) declares no properties and has no index signature. That is why commit 570de551d2 had to loosen withEvaluatedProperties to T extends object (TS2559).
    • So on a container member the channel is read off the authored JSON, not off a declared key. A TS author of ActionGroupSchema.actions gets a type error (TS2353) writing it without a cast.
    • The PM claim's own Clause-②: no rationale ("already-declared properties.params") is false for members.
    • Ruling A ("no new value-bag key is declared") rules out declaring it here, so this is a wording duty, not a code blocker.
    • Replacement parenthetical in static-params.ts: "(An action:group / action:menu item is also a container member, so its static values are read from properties.params and evaluated by the container through {@link readMemberStaticParamValues} (objectui#10290). UIActionSchema declares no properties, so on a container member this bag is read off the authored object, not off a declared key. element:button's inline action and page:header's actions do not read properties.params.)"
    • Also recommended: Zone 1's "SchemaRenderer template-evaluates every string leaf of that bag" should add "; a container member, which never passes through SchemaRenderer, is evaluated by its container with the same rule and scope (useConfigBagEvaluator, objectui#10290)".
  • React rules: clean.
    • useConfigBagEvaluator() is called unconditionally, before every early return, in all three containers.
    • Inside the hook, three hooks are called unconditionally.
    • handleExecute deps [execute, evaluateBag] are correct.
    • The hook returns a fresh function each render, so handleExecute and the ActionAutoTrigger run also churn every render. useAutoTriggerOnce is guarded by refs, so correctness does not rest on identity (AGENTS.md [WIP] Enhance every detail of the designer #10). The cost is small.
    • The hook lives in hooks/ to keep SchemaRenderer.tsx out of the compiler purity lint (the dev's measured reason). The hooks/index-to-SchemaRenderer import cycle is safe: the binding is hoisted and used only at call time.
  • Pins: sound, with gaps.
    • All 8 container paths are covered, and the control (a top-level action:button through SchemaRenderer, green on base) is real.
    • The 8 "resolved" rows assert recordId: 'rec_1' and are not tautological. The quoted ablation reddening exactly those 8 fits the source.
    • The 8 node-level rows are regression guards that are green on base, not fix pins.
    • Not pinned:
      • evaluation happens once;
      • group/menu with an array params forward params: staticValues too (a new key on that branch; toEqual ignores undefined);
      • properties.params wins over the api window.
    • These are non-blocking; recommend adding the first.

② Semver level

  • The exports reach the entry.
    • packages/react/src/index.ts:9 has export * from './SchemaRenderer.js', which carries evaluateConfigBagInScope.
    • :11 has export * from './hooks/index.js', and hooks/index.ts:48 has export * from './useConfigBagEvaluator.js'.
    • package.json exports is "." only, so both are public API.
  • '@object-ui/react': patch is wrong. Clause-② is yes (widening).
    • Two new public exports widen the published surface. Per AGENTS.md, yes takes at least minor.
    • The repo precedent says the same: .changeset/10288-config-bag-data-object-source.md and 7867-action-params-templates.md are both '@object-ui/react': minor with a "Declared as a minor (Clause-②)" sentence.
    • CI cannot catch this. "Changeset Bump Policy" only refuses major.
    • Because of the fixed group, the whole group releases at this minor.
  • Keeping it internal is not feasible.
    • @object-ui/components can import only through the "." entry, so useConfigBagEvaluator must be public.
    • Route (b) would avoid new exports, but dropdown items are DropdownMenuItem leaves, so (b) is not viable there.
    • evaluateConfigBagInScope has no consumer outside the hook. It could be kept off the entry by moving it and its helpers into a module index.ts does not re-export. That narrowing is optional; one export remains either way, so minor stands.
  • The changeset, sentence by sentence. The first paragraph is accurate. Four sentences are wrong or overstated:
    • "reach the handler exactly as a top-level action:button's do": overstated. The unevaluated-expression diagnostic does not run for container members (the dev's own out-of-scope note).
    • "A node-level params object is still not read as values": imprecise. Group/menu items of type: 'api' still forward it (objectstack#5777 window).
    • "It returns the SchemaRenderer memo's own properties evaluation": loose. It returns a function.
    • "exported beside SchemaRenderer, which applies the same rule through it": false. SchemaRenderer never calls evaluateConfigBagInScope.
  • Replacement changeset (the frontmatter plus paragraphs 2 to 4; paragraph 1 is kept):
    ---
    '@object-ui/components': patch
    '@object-ui/react': minor
    ---
    
    • Paragraph 2: "Each container now evaluates its members' properties with the evaluator and scope SchemaRenderer uses: action:bar where it composes an inline member, and action:group / action:menu when they run an item. A container member's static values therefore reach the handler as a top-level action:button's do, with one difference: the development-build unevaluated-expression diagnostic runs in the SchemaRenderer memo, so it does not report an unresolvable template on a container member. An item that carries an ActionParam[] input list forwards both, as action:button does. A node-level params object is still not read as values (objectui#10289). The one exception is unchanged from objectui#10462: an action:group / action:menu item of type: 'api' still forwards it as the request payload (objectstack#5777 window), unless the item also carries a properties.params bag, which now takes precedence."
    • Paragraph 3: "@object-ui/react exports useConfigBagEvaluator() for this. It returns a function that applies the SchemaRenderer memo's properties evaluation (the same per-key rule and the same record / current_user / page scope) to a config bag rendered without SchemaRenderer. It is not a second template engine. Its plain half, evaluateConfigBagInScope(), is exported beside SchemaRenderer. Both are built from the module-scope scope builder and per-key rule that the memo itself calls."
    • Paragraph 4: "Declared as a minor (Clause-②, widening): @object-ui/react gains two public exports, useConfigBagEvaluator and evaluateConfigBagInScope. Nothing is removed or renamed."
  • PR body.
    • Clause-②: no becomes Clause-②: yes (widening).
    • The changeset bullet becomes: "@object-ui/components patch, @object-ui/react minor (Clause-② widening: two new public exports; the fixed group releases at that minor)."
    • The api clause in bullet 2 becomes: "the type: 'api' window is unchanged when the item carries no properties.params; when it carries both, properties.params is forwarded and the node-level object is dropped without a warning."
    • The last Acceptance note becomes: "The two new @object-ui/react exports are declared minor (Clause-② widening)."
    • The rest of the body matches the diff: H1/H2 as claims, the pin counts, and the Serial section, which I re-derived.
  • The claim 5856277993. Its Clause-②: no is a false declaration and must be corrected by the dispatch seat. Its file surface (components plus one changeset) was widened to packages/react; the PR declares this.

③ Boundary flags

  • CI on e8b96c0161: 43 check runs, 40 success, 3 skipped, 0 failed. The combined status is success.
    • Success: Test, Test (shard 1/8 to 8/8), Test (dist pins), Live E2E (informational), Docs Route Eager Closure Check, Governed Surface Queue Guard, Bundle Analysis, Skill Eval Token Check, Build Docs, Changeset Fixed Group Check, Spec Main Shape Gate, Action Ref Convention, Type Check, Skill Guide Path Check, Lint, Doc Fence Language Check, Changeset Bump Policy, Changeset Declaration, Doc Snippet Type Check, Shell Escape Residue Scan, Build and E2E, Inert vi.mock Specifier Check, Changeset Claim Re-read, Control Byte Scan, Changeset Overwrite Report, Line Citation Gate, Skill Example Check, Doc Component Type Check, Pre-Install Import Graph Check, label, README Export Check, Internal Docs Link Check, Doc Example Id Check.
    • Skipped: Test (coverage), Test (coverage shard matrix), dependabot.
  • git merge-tree --write-tree:
    • against main bf14b646: exit 0, no conflicts;
    • against PR objectui#8941 head bb7d5e71: exit 0, tree ce1f7145.
  • Open PRs touching these files: only chore(deps): lucide-react 1.31.0 -> 1.43.0, with the one retired spelling repaired #8941 (action-bar.tsx), which merges cleanly. The other 9 open PRs touch none of them.
  • Governed predicate: 0 of 9 paths hit. NOT governed; 533 changed lines, under the human-merge threshold.
  • State: draft is true. The assignee is os-elon-musk. The labels are package: react, package: components, tests.
    • With Clause-② now yes, the dispatch seat owes the needs:contract-review label.
    • The fix moves the head, so a fresh same-form PASS is needed at the new head. This is not a pure regeneration.

Implemented-by: claude/issue-10290-member-params-evaluated
Reviewed-by: session_014mXUNuFomfj24w7s1pZzhN

VERDICT: FAIL

What stops it landing:

  1. The changeset declares '@object-ui/react': patch and the PR says Clause-②: no, but two new public exports make this a widening. The fix is minor and Clause-②: yes (widening), using the replacement text in ②.
  2. Four changeset sentences are false or overstated, most importantly "which applies the same rule through it". Replace them as given in ②.
  3. The claim 5856277993's Clause-②: no must be corrected, and needs:contract-review applied.

The code (one evaluator, scope parity, no double evaluation, ruling A warnings, React rules) passes. The static-params.ts Zone 1 inconsistency and the three unpinned claims are should-fix, with the text given in ①.

@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Eager closure (gzip, 329 chunks) 3068.5 KB 3104.5 KB
Main entry chunk (gzip) 148.3 KB 350 KB
Entry file index-CF_vvRrZ.js —
Status PASS —

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

Package Size Gzipped
app-shell (consoleActionDispatch.js) 0.20KB 0.19KB
app-shell (index.js) 16.57KB 6.15KB
app-shell (runtime-config.js) 20.68KB 7.36KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 10.06KB 3.86KB
auth (ActiveOrganizationStorage.js) 27.95KB 10.04KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 2.07KB 1.00KB
auth (AuthProvider.js) 40.17KB 10.58KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.15KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.65KB 2.22KB
auth (SocialSignInButtons.js) 9.61KB 3.89KB
auth (UserMenu.js) 3.39KB 1.21KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 40.21KB 10.80KB
auth (createAuthenticatedFetch.js) 8.52KB 3.45KB
auth (index.js) 3.63KB 1.64KB
auth (invitation-status.js) 1.22KB 0.70KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 5.30KB 1.02KB
auth (useWorkspaceAdminStatus.js) 11.08KB 4.58KB
collaboration (CommentThread.js) 27.13KB 7.95KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.68KB 0.73KB
collaboration (useCollaborationTranslation.js) 6.05KB 2.52KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 555.40KB 132.79KB
core (index.js) 9.57KB 3.81KB
create-plugin (index.js) 27.94KB 9.51KB
data-objectstack (index.js) 223.93KB 62.31KB
fields (index.js) 259.29KB 65.67KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (builtinAggregateLabels.js) 0.86KB 0.49KB
i18n (currency.js) 2.59KB 1.22KB
i18n (fallbackInterpolation.js) 6.25KB 2.77KB
i18n (i18n.js) 8.87KB 3.64KB
i18n (index.js) 5.24KB 2.27KB
i18n (pickLocalized.js) 9.86KB 3.95KB
i18n (provider.js) 39.40KB 12.91KB
i18n (translateFn.js) 0.20KB 0.18KB
i18n (useDisplayLocale.js) 3.52KB 1.76KB
i18n (useObjectLabel.js) 34.34KB 9.17KB
i18n (useSafeTranslation.js) 5.60KB 2.33KB
layout (index.js) 39.28KB 11.09KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.75KB
mobile (index.js) 1.99KB 0.87KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 6.62KB 2.45KB
mobile (useResponsive.js) 0.72KB 0.42KB
mobile (useSpecGesture.js) 5.52KB 2.10KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 13.52KB 4.88KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 6.24KB 2.16KB
permissions (discardProofCache.js) 1.04KB 0.55KB
permissions (evaluator.js) 8.33KB 3.07KB
permissions (index.js) 0.93KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.53KB
permissions (usePermissions.js) 4.83KB 2.27KB
plugin-ai (index.js) 16.01KB 3.93KB
plugin-calendar (index.js) 51.65KB 14.69KB
plugin-charts (index.js) 82.37KB 22.57KB
plugin-chatbot (index.js) 198.40KB 47.22KB
plugin-dashboard (index.js) 134.11KB 35.62KB
plugin-designer (index.js) 216.25KB 44.39KB
plugin-detail (index.js) 233.23KB 61.74KB
plugin-editor (index.js) 2.23KB 1.05KB
plugin-form (index.js) 158.35KB 40.47KB
plugin-gantt (index.js) 169.75KB 41.96KB
plugin-grid (index.js) 218.12KB 59.72KB
plugin-kanban (index.js) 48.43KB 15.11KB
plugin-list (index.js) 114.70KB 28.42KB
plugin-map (index.js) 22.90KB 7.62KB
plugin-markdown (index.js) 13.88KB 4.80KB
plugin-report (index.js) 43.55KB 11.99KB
plugin-timeline (index.js) 30.91KB 9.05KB
plugin-tree (index.js) 10.58KB 3.72KB
plugin-view (index.js) 87.83KB 22.01KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.66KB 3.50KB
providers (index.js) 0.45KB 0.23KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.62KB 2.34KB
react (LazyPluginLoader.js) 4.47KB 1.63KB
react (SchemaRenderer.js) 119.16KB 39.05KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 4.03KB 1.86KB
react (schema-input.js) 4.25KB 2.04KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (body-dialect.js) 4.78KB 2.09KB
sdui-parser (codegen.js) 7.50KB 3.05KB
sdui-parser (dashboard-widget-options.js) 3.08KB 1.30KB
sdui-parser (index.js) 6.16KB 2.71KB
sdui-parser (input-type.js) 2.84KB 1.40KB
sdui-parser (kanban-quick-add.js) 3.89KB 1.87KB
sdui-parser (parse.js) 25.28KB 7.80KB
sdui-parser (provenance.js) 3.66KB 1.82KB
sdui-parser (types.js) 0.28KB 0.23KB
sdui-parser (validate.js) 18.27KB 6.20KB
types (ai.js) 4.11KB 2.06KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 1.00KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 2.93KB 1.49KB
types (crud.js) 0.20KB 0.18KB
types (dashboard-filter-alias.js) 6.23KB 2.74KB
types (data-display.js) 3.75KB 1.85KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.85KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (expression.js) 0.20KB 0.18KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-inflight.js) 8.87KB 3.73KB
types (http-retry.js) 4.32KB 2.02KB
types (icon-key-migration.js) 4.26KB 1.63KB
types (index.js) 4.74KB 2.25KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 5.00KB 2.39KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 2.52KB 1.31KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (select-option.js) 0.20KB 0.19KB
types (spec-report.js) 5.05KB 1.93KB
types (spec-ui-namespace.js) 0.20KB 0.19KB
types (strict-authoring-face.js) 17.15KB 6.32KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 6.28KB 2.87KB
types (ui-action.js) 8.11KB 3.32KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 3931a9dba4d23bc15ee75192c1743d9e34695efc

A narrow round-2 review, run in-seat by the dispatching seat, of the delta e8b96c0161..3931a9dba4 (one commit), against the round-1 FAIL record 5856863202. Every other judgment in that record stands: one evaluator, no double evaluation, scope parity, ruling A's warnings and the React rules. No executable line moved.

① Derived judgments

  • The delta is prose and comments only. Two files, +31 / −16. In packages/components/src/renderers/action/static-params.ts, no changed line falls outside a comment; the seat grepped the diff and found 0 such lines.
  • Item 1 is resolved. The changeset frontmatter now reads '@object-ui/components': patch and '@object-ui/react': minor. Paragraph 4 declares the Clause-② widening: two new public exports, useConfigBagEvaluator and evaluateConfigBagInScope, with nothing removed or renamed.
  • Item 2 is resolved. Paragraphs 2 and 3 are the review's replacement text:
    • the development-build diagnostic difference is stated;
    • both channels are forwarded when an item carries an ActionParam[] list;
    • the type: 'api' window holds unless properties.params is present, in which case properties.params wins;
    • the hook "returns a function";
    • both exports are built from the module-scope pieces the memo calls. The false "SchemaRenderer applies the same rule through it" is gone.
  • The should-fix is taken. static-params.ts now says that on a container member the properties.params bag is read off the authored object, because UIActionSchema declares no properties. Zone 1 names the container evaluation path (useConfigBagEvaluator).
  • Item 3 (the claim and the label) was done by the seat. Claim 5856277993's Clause-② line is amended to yes (widening), and needs:contract-review is applied to the card. The label clears at landing.
  • Not carried: the three unpinned claims the review listed as non-blocking (single evaluation, array-params forwarding, properties.params over the api window). They are recorded in the ACCEPT.

② Semver level

@object-ui/react is minor (Clause-② widening). @object-ui/components is patch. There is no major: check-changeset-no-major exited 0, per the dev's reading.

③ Boundary flags

  • CI on 3931a9dba4: 43 check runs; 40 success, 3 skipped, 0 failure, 0 pending.
  • git merge-tree --write-tree against main 29b45f6a0c is clean, tree 3fd3c0febe, per the dev's reading. Against PR objectui#8941 it was clean at round 1, and action-bar.tsx is unchanged since.
  • NOT GOVERNED.
  • The PR is a draft, assigned to os-elon-musk.

Implemented-by: claude/issue-10290-member-params-evaluated
Reviewed-by: session_014mXUNuFomfj24w7s1pZzhN

VERDICT: PASS

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review September 27, 2026 15:23
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Sep 27, 2026
Merged via the queue into main with commit 6cf5999 Sep 27, 2026
45 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-10290-member-params-evaluated branch September 27, 2026 15:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants