Uh oh!
There was an error while loading. Please reload this page.
fix(plugin-list): harvest row-action predicate fields from the object's userActions only - #5434
Merged
os-support-ai merged 1 commit intoAug 20, 2026
Conversation
…'s userActions only The `$select` predicate harvest read `userActions` view-first, so a spec-legal view-level toolbar block shadowed the object's CRUD-predicate block and dropped its operands from the projection (objectui#3501's fail-closed CEL fault). On the app-shell path the left operand is always an object literal, so the object block was never reached at all. Sibling of objectui#5426, which fixed the same shape in plugin-grid; both read sites now carry the same comment and the same measured reason. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RV6yuVCxymHYE16PL9vQkE
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
os-support-ai
marked this pull request as ready for review
August 20, 2026 18:14
Uh oh!
There was an error while loading. Please reload this page.
os-support-ai
deleted the
claude/issue-5398-listview-userActions-collision
branch
August 20, 2026 18:14
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 freeto 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#5398
The sibling read site of the one objectui#5426 fixed in
plugin-grid, per the maintainer ruling of 2026-08-20 on objectui#5240 (Q2=B). Held serial rather than batched for one reason: both read sites end up with one shape and one stated reason, not two spellings of one fix. This PR copies objectui#5426's diff — comment structure, pin structure, ablation shape — and adds only what is genuinely different about this instance.What was wrong
userActionsnames two different blocks, andListView's$selectharvest read them as one.userActionsis toolbar policy — the spec'sUserActionsConfigSchema:sort,search,filter,refresh,rowHeight,addRecordForm,editInline,buttons. It rejectseditby name.userActionsis the CRUD-predicate block —edit/delete/createcarryingvisibleWhen/disabledWhen(objectui#2614). It is the only shapelistViewPredicatescan read: its loop skips every non-object value.The harvest that decides which fields the server is asked for read the key view-first, at
packages/plugin-list/src/ListView.tsx:So a perfectly legal toolbar block shadowed the object's CRUD predicates. Every value in it is a boolean, the harvest collected zero predicates, the predicate's operand left the projection, CEL faulted on the absent key, failed closed, and the row Edit/Delete button disappeared for everyone with nothing pointing at the projection — objectui#3501's failure shape, reached with a success receipt at every step.
Why this instance was worse than the grid's — verified, not inherited
The card claimed the app-shell path makes the shadowing total. Re-measured on this branch rather than taken on trust, and it holds — in a slightly stronger form than the card stated.
packages/app-shell/src/views/ObjectView.tsxbuilds theuserActionsit hands toListViewas an object literal of two spreads:That literal is on
fullSchema, which is handed straight toListView schema={fullSchema}in the same file. It is not merely unconditional — it is never nullish even when both spreads are empty: the worst case is{}, which??does not fall through. So on the app-shell path the object's CRUD block was never consumed at all, whether or not any author ever wrote toolbar policy. The grid's instance needed an authored toolbar block to misfire; this one misfired on every list the app shell renders.A third producer is in
plugin-list's own dependency reach:normalizeListViewSchemamanufactures a view-leveluserActionsout of a legacyshow*view that never wrote the key. "Nobody authors this" was never available as a reason here either.Re-measured against
@objectstack/spec@17.0.0(same probes as objectui#5426, same results):UserActionsConfigSchema.shapekeyssort, search, filter, refresh, rowHeight, addRecordForm, editInline, buttonsUserActionsConfigSchema.safeParse({edit:{visibleWhen}})success: false,unrecognized_keys: ["edit"](same fordelete,create)ListViewSchema.safeParse(… userActions:{sort,search,filter})success: trueListViewSchema.safeParse(… userActions:{edit:{visibleWhen}})success: false,unrecognized_keys: ["edit"]at pathuserActionsWhat changed
packages/plugin-list/src/ListView.tsx— the$selectharvest readsobjectDef.userActionsonly. The view-schema-first operand is gone.userActionsread sites in that file carry a comment naming the collision — including the surviving view-half read attoolbarFlags, which is toolbar policy and therefore correct asschema-only. That mirrors objectui#5426's Q3=B, pointed at the other half: in the grid the surviving read was the object block, here it is the view block.packages/plugin-list/src/__tests__/ListView.userActionsCollision.test.tsx— a new file pinning each clause of that comment. 12 assertions.patchchangeset on@object-ui/plugin-list.The comment states the measured reason. It does not say "non-author surface, deliberately unlisted" — the repository contradicts that, and Q1=A exists precisely to keep the falsified claim out of the census artifact.
Verification — all at
392c6e452No build artifact sits between any edit and any measurement in the vitest legs.
vitest.config.mtsaliases every@object-ui/*specifier to that package'ssrc/, and this worktree had nodist/at all while every suite and both ablation legs ran (packages/core/dist,packages/react/dist,packages/plugin-list/distall absent — checked). Source is provably what executed.@objectstack/specis the published 17.0.0 fromnode_modules; nothing local builds it. The dependency closure was built afterwards, only becausetsc --noEmitneeds the.d.tsfiles.Run from the repository root, per AGENTS.md:
The
ObjectViewslice is the downstream consumer — the producer of the always-truthy literal above.Reverse-verification (two legs, predicted before running, fix committed first)
Both legs ran against the committed fix, restored with
git checkout HEAD -- …; after the restoregit diff HEADwas empty, so the tree that produced the green numbers is byte-identical to the commit. No build step sits between either mutation and the run (src alias, nodist/).Leg 1 — restore the view-first
??. Predicted: two red, not the grid's one — the toolbar-block case and the empty-block case, because{}is truthy; the no-view-key case stays green because??legitimately falls through there. Observed:2 failed | 10 passed, exactly those two. Matches.Leg 2 — delete the
userActionsline from the harvest entirely (the "tidy finish" mutation). Predicted: three red — every projection case losesstatus. Observed:3 failed | 9 passed. Matches.Leg 2 is why the first projection case is counted at all: it is green on both legs of leg 1, so on its own it pins nothing about this fix — it pins that the read still exists, and leg 2 is what shows it can go red. Same reasoning as objectui#5426, one case wider.
Scope
plugin-listonly.packages/plugin-gridis untouched — objectui#5426 is merged and must not be re-touched.packages/app-shellis untouched: it is evidence here, not a target. The producer-side question —bridgeListViewemitting onto anobject-gridnode a keyComponentPropsMaprefuses by name — is routed through triage as its own spec-coordination card; out of scope here, and not addressed by this PR.Toolbar policy itself is untouched — it was never read through this path, and the two view-level reads that legitimately consume it (
toolbarFlags,inlineEditOffered) are unchanged apart from the collision comment.Generated by Claude Code