Uh oh!
There was an error while loading. Please reload this page.
fix(app-shell+kanban+list): row-predicate CEL authoring advertises runtime-bound roots; kanban binds host scope (#2571 follow-up) - #2603
Merged
Conversation
…ntime-bound roots; kanban binds host scope (#2571 follow-up) The view designer's conditional-formatting editor (ConditionalFormattingEditor, hosted by ViewVariantInspector) linted/completed with the engine-default 'flattened' advertisement, whose autocomplete offers roots the ADR-0058 row-predicate runtime never binds (previous / input / os / vars) — accepting one authors a condition that silently never matches — while omitting the roots that ARE bound (features / app / data / ctx). Auditing the runtime first (as #2571 did for field rules): evalRowPredicate binds the row's fields BARE, under record.*, and under data.*, plus the host shell's global predicate scope (current_user / user / ctx / app / features — ExpressionProvider, #1583/ADR-0068). Therefore: - lint stays scope='flattened' — a bare `status == 'overdue'` DOES match at runtime for row predicates, so scope='record' would false-flag valid conditions; only the advertised roots change (new ROW_PREDICATE_ROOTS); - kanban cards now bind the ambient predicate scope (usePredicateScope) in both boards, closing the grid/kanban verdict gap for features.* / current_user.* conditions (ObjectGrid rows already bound it); - ListView's exported evaluateConditionalFormatting accepts the optional host scope for parity. Tests: bare-field condition lints clean (real engine); the roots override advertises `features` and withholds `vars`; a ROW_PREDICATE_ROOTS ↔ evalRowPredicate contract test keeps the advertised catalog honest against the evaluator; kanban boards style a features-gated card only inside PredicateScopeProvider and fail soft outside it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
Uh oh!
There was an error while loading. Please reload this page.
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.
Problem
#2571 added
scope/rootstoCelPredicateFieldand wired the field conditional rules editors toscope="record". The remaining CEL call site —ConditionalFormattingEditor(hosted byViewVariantInspector) — still authored row-predicateconditions with the engine-default advertisement, which has two traps:previous/input/os/vars, but the ADR-0058 row-predicate evaluator (evalRowPredicate— list rows, grid rows, kanban cards) binds none of them. Accepting one of those suggestions authors a condition that lints clean and silently never matches.features/app/data/ctx).Runtime audit (why NOT
scope="record")The task hypothesis was that these predicates evaluate with the record bound only under the
recordnamespace. Auditing@object-ui/core'sevalRowPredicateshows otherwise: it binds the row bare (status), underrecord.*, and underdata.*(documented as the three authoring conventions), plus the host's global predicate scope (current_user/user/ctx/app/features—ExpressionProvider, #1583/ADR-0068), and@objectstack/formula'sbuildScopemerges the extra scope top-level. So a barestatus == 'overdue'does match at runtime, andscope="record"(bare ref ⇒ hard lint error) would false-flag valid, documented predicates. Lint therefore stays'flattened'; only the advertised roots are pinned to the runtime-bound set (ROW_PREDICATE_ROOTS).Runtime gap closed alongside
Grid rows already bound the ambient predicate scope (
ObjectGrid→usePredicateScope), but kanban cards did not — afeatures.*/current_user.*formatting condition worked on the grid and silently never matched on kanban, contradicting the "identical verdict" comments in both boards. BothKanbanEnhancedandKanbanImplnow bindusePredicateScope();ListView's exportedevaluateConditionalFormattingaccepts the optional host scope for parity. Without this, advertising the global roots in the editor would have re-created the same authoring trap on kanban.Changes
ConditionalFormattingEditor: passscope="flattened"+roots={ROW_PREDICATE_ROOTS}(record,current_user,user,features,app,data,ctx) toCelPredicateField.KanbanEnhanced/KanbanImpl: bind the ambient predicate scope in card conditional formatting.ListView.evaluateConditionalFormatting: optionalscopeparam.Tests
scope="record").record.<field>still errors with did-you-mean.features, withholdsvarseven when the engine advertises it.ROW_PREDICATE_ROOTSentry resolves throughevalRowPredicatewith an ExpressionProvider-shaped scope;previous/input/os/varsprovably don't (and must stay unadvertised).PredicateScopeProvider, fail soft outside; bare-field conditions keep working.vitest: 225 tests green across the touched files;tsc --noEmitclean for app-shell / plugin-kanban / plugin-list (after workspace build). Pure bug fix — no changeset per AGENTS.md §9.🤖 Generated with Claude Code