Skip to content

fix(core): harvest the CEL optional record.?x spelling into the view projection - #29480

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-vzj2zv
Nov 2, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-vzj2zv

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Steedos · project thread

Fixes #29409

Clause-②: no
Metadata-protocol: none

The two lines are copied from the claim (comment 6581111452).

维护者速读

  • 改了什么:列表视图把谓词读到的字段补进 $select(字段采集)。采集正则原先只认 record.x / data.x,现在也认 CEL 可选字段写法 record.?x / data.?x。
  • 为什么改:skills(objectstack-formula): "every predicate reads a record total over declared fields" contradicts the canonical sparse action-binding rule (declared-fields.ts, #4953), so agents drop the has() guard a list-row action needs #29094 裁决(选项 A)后续 D.2。作者在稀疏行上写 record.?status.orValue('') 时,status 不进投影,行上永远没有这个键,按钮按"字段为空"处理,没有任何迹象指向投影。
  • 风险与回滚:只改一行正则;采集名仍要过"对象已声明或平台列"和字段级读权限两道过滤,采集不是读授权。record.? 单独出现、record.?.x、JS 写法 record?.x 仍不采集(测试钉住)。回滚即撤销本 PR。
  • 先看:ui/packages/core/src/utils/predicate-fields.ts 的 RECORD_REF;测试 predicate-fields.test.ts 新增的 7 个用例。
  • 两分钟验证:pnpm --dir ui exec vitest run packages/core/src/utils/__tests__/predicate-fields.test.ts,预期 39 个用例通过(正则还原为 main 时其中 5 个转红)。
  • 需要你做的:无,席位落地。

What changes

  • RECORD_REF (@object-ui/core, utils/predicate-fields.ts), the one regex behind collectPredicateFieldRefs, accepts an optional ? between the record dot and the field name, so the CEL optional-field selector record.?x / data.?x is harvested as the field x, beside the plain spelling. Every harvest consumer (the grid row load, the list view, the related list) reads through this function, so all of them pick it up with no change of their own.
  • Unchanged: a harvested name still reaches $select only when the object declares it or it is a platform column, and only when the principal may read it. A selector that names no field (record.? alone, record.?.x, record.?1x), a longer identifier ending in record and the JavaScript spelling record?.x contribute nothing.

Tests

ui/packages/core/src/utils/__tests__/predicate-fields.test.ts, seven new cases:

  • record.?x and data.?x are harvested; an optional selector inside the { dialect, source } envelope is harvested; the optional and plain spellings of one field dedupe in first-seen order.
  • Through listViewPredicates: an optional operand on a row action visible, an object action disabled and a CRUD visibleWhen override is harvested.
  • Negatives: record.? == null, record.?.status, data.?1st, myrecord.?status and record?.status harvest nothing.
  • Ablation: with RECORD_REF restored to the main spelling (through scripts/ablation-replace.mjs; anchor 1 to 0, restored to the HEAD blob, git diff HEAD empty), the five positive optional-selector cases go red and the 34 others stay green.

Acceptance notes

  • Kanban, calendar and gantt need no wiring. The card asked whether these views take the harvest. None of the three sends a $select: each fetches whole rows (the board's query and its lane-paging params, the calendar's range query and its record-anchor query, the gantt's ceiling query carry filter, order, limit, expand and search only), so a predicate operand already arrives unless field-level security strips it server-side. None of the three renders row or card actions with visible / disabled predicates either (no action-predicate evaluation in their sources). No view file is edited.
  • String literals are not masked. The harvester reads record.x inside a CEL string literal today, and this PR keeps that for the optional spelling too: the file's own rule is that an extra declared column costs bytes while a missing one fails the predicate closed, and masking literals would under-harvest on an unbalanced quote.
  • The bracket spelling record['x'] and the optional index record[?'x'] are not harvested, as before; not in this card's scope.

Verification

Head 5e043f9a. The fix is commit 592019e4 (based on origin/main 5f7d554c); 5e043f9a merges origin/main cafe8ee6 (none of this PR's files and nothing under ui/packages/core/ changed; clean). The branch's delta against main is the three files above. Readings name their head; the final head's are CI's check-runs.

Tests
  • 592019e4: pnpm --dir ui exec vitest run packages/core/ at --maxWorkers=2 under the verification lock: 232 files passed, 4294 tests passed, 27 skipped.
  • 592019e4: turbo run type-check --filter=@object-ui/core (tsc --noEmit and the test tsconfig): 4 of 4 tasks successful.
  • 5e043f9a: packages/core/src/utils/ (113 files, the touched test included): 113 passed, 2001 tests passed.
Gates
  • 592019e4: node scripts/pm/dispatch-gates.mjs --commands derived 34 families for this diff; all 34 ran with exit 0, pnpm --dir ui exec vitest run scripts/ among them (169 files passed, 2 skipped; 4921 tests passed). --ran reconciled 34 derived, 34 run, 0 NOT-MEASURED.
  • node scripts/check-sdui-manifest.mjs: exit 0 (no registry change).
  • pnpm check:new-line-citations (under ui/): 0 new citations.
  • The changeset, ADR-0087 and closing-keyword gates ran against this body.
  • The CI-only type-check lanes and the whole-tree families are CI's; their check-runs on this PR are the reading.

Generated by Claude Code

…projection

collectPredicateFieldRefs read only record.x / data.x, so a predicate
written with the CEL optional selector left its operand out of $select.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsR2jTLzhrs8dyC8QCdCKg
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Nov 2, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:ui#3 · zhuangjianguo · session_01QsR2jV4dWohojjbTJTQq5m

席位核对 · ACCEPT · 2026-11-02T16:25Z

Head-sha: 5e043f9acce6642fc64160fd64cebb665c5f67aa

  • Shape: draft → main, Fixes #29409 in the body only. 3 files, +67 / −1 (68 lines ≤ 3000). No governed path: check-governed-merges --pr 29480 reports NOT governed. Clause-②: no and Metadata-protocol: none are line-initial in the body and the changeset, as claimed (6581111452). The changeset is patch for @object-ui/core.
  • Contract review: none owed (Clause-②: no; no export, prop or key change; a private regex widened).
  • File surface: inside the claim: predicate-fields.ts (the RECORD_REF regex and its JSDoc), its test, the changeset. No kanban, calendar or gantt file is touched.
  • Read in the diff: RECORD_REF becomes /\b(?:record|data)\.\??([A-Za-z_][A-Za-z0-9_]*)/g, so record.?status and data.?status harvest status beside the plain spelling; record.? alone and record.?.x match no name, and the JavaScript record?.x fails at \., so they still yield nothing. The declared-field and FLS filters after the harvest are unchanged.
  • Kanban / calendar / gantt (card item 2): read, not wired. None sends a $select (each fetches whole rows) and none evaluates row or card action visible / disabled predicates; file:line per view is in the report (6581921518). Accepted as the answer to item 2; nothing to file.
  • Accepted deviation: no "no harvest from strings" pin. The harvester reads record.x inside a CEL string literal today, and over-harvest is the file's safe direction (an extra projected column costs bytes; a missing one fails the predicate closed); masking literals risks under-harvest on an unbalanced quote. Raised before editing.
  • Tests (dev): predicate-fields.test.ts 33 → 39 cases (six new; the body's 维护者速读 and Tests lines say seven, a miscount the dev flagged; the count here is the right one). Ablation (regex reverted) reds the 5 positive cases, restored to the HEAD blob. core suite 232 files green; core type-check 4 / 4; derived gates 34 of 34, --ran reconciled; body gates exit 0.
  • Gates (check-runs on this head): 44 success, 11 skipped, 0 failed or pending. mergeable_state is clean.
  • Landing: ordinary queue landing, pr_ready then automerge_enable. Fixes #29409 closes the card on merge.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 2, 2026 16:25
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge November 2, 2026 16:26
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 2, 2026
Merged via the queue into main with commit 86d36e9 Nov 2, 2026
56 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-vzj2zv branch November 2, 2026 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s tests tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ui predicate harvest: record.?x (CEL optional) is not harvested, and kanban/calendar/gantt queries may not take the harvest at all

1 participant