Skip to content

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

Closed

Description

@objectstack-fleet

domain:devx#2 · marchtian · session_017ihL2gLghEqeDKTbDTC7Zd

Filing gate: ① a measured gap in the view projection harvest, named as follow-up D.2 of the #29094 ruling (option A, maintainer 「同意」, ruling comment 6579342813). It does not block anything, so it is filed as p3.
Reader: domain:ui, ui/packages/core/src/utils/predicate-fields.ts and the views that build their own queries.
Dedupe (open AND closed): "harvest record.?" and "predicate-fields harvest kanban" → #28542 (open, cloud invitations page projection), #28960 (closed, docs). Neither covers these two gaps.
reach: a list or board view whose action visible / disabled reads a field the view does not show.
type: Bug

Business reason: the harvest is what keeps a sparse list row from hiding a button by accident. A predicate it does not read, or a view that does not use it, puts the author back on the has() guard without any sign that this happened.

What the code does on main

Wanted

  1. Make the regex accept record.?x and data.?x, and pin it.
  2. Read the kanban, calendar and gantt views' queries. Wherever a view that renders row actions does not take the harvest, wire it in, or file the gap. Keep the field-level-security filter, because a harvest is not a read grant.

Activity

  1. added
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    domain:uiDomain lane — seat card indexed by label:pm:seat
    on Nov 2, 2026
  2. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: p3 · pm:queue · 2026-11-02T15:00Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. added
    pm:queueReady for the PM dispatch loop
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Nov 2, 2026
  4. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 2, 2026
  5. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#3 · zhuangjianguo · session_01QsR2jV4dWohojjbTJTQq5m

    Claim: PM loop round 21 · 2026-11-02T15:31Z
    Session: session_01QsR2jTLzhrs8dyC8QCdCKg (card thread, os-dev); dispatched by seat session session_01QsR2jV4dWohojjbTJTQq5m
    Account: zhuangjianguo
    Branch: claude/project-thread-vzj2zv (platform-assigned to the card thread; it can push only this branch)
    Worktree: objectstack-issue-29409
    Domain: domain:ui
    Seat: domain:ui#3
    File surface: ui/packages/core/src/utils/predicate-fields.ts, the kanban / calendar / gantt query-building files that need the harvest (one hunk each, named in the report), their tests, and a changeset. A view whose wiring is larger than a small change, or that would change a public prop or export, is reported, not edited (stop on breach; explain in the report)
    Container & model: S–M, mode:thread, model: default tier (dispatch-gates --tier: no path-derived mandate), effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: open — recorded at review
    Thread-read: none
    Premise: holds (at origin/main 6fe99f86: predicate-fields.ts:91 RECORD_REF matches record.x / data.x only, so record.?x is not harvested; harvest consumers are plugin-grid/src/objectGridRowLoad.ts and app-shell/src/views/RecordDetailView.tsx).
    Serial constraints cleared: none. Follow-up D.2 of the #29094 ruling (6579342813), non-blocking.

  6. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#3 · zhuangjianguo · session_01QsR2jTLzhrs8dyC8QCdCKg
    os-dev-report

    {
     "issue": 29409,
     "status": "done",
     "branch": "claude/project-thread-vzj2zv",
     "pr": "https://github.com/objectstack-ai/objectstack/pull/29480",
     "session": "session_01QsR2jTLzhrs8dyC8QCdCKg",
     "premise_still_valid": true,
     "head": "5e043f9a",
     "summary": "RECORD_REF in ui/packages/core/src/utils/predicate-fields.ts now accepts an optional '?' after the record dot, so collectPredicateFieldRefs harvests the CEL optional selector record.?x / data.?x as field x beside record.x / data.x; every harvest consumer (objectGridRowLoad, ListView, RelatedList) picks it up unchanged, and the declared-field and FLS filters still apply. Item 2: kanban, calendar and gantt send no $select (whole-row fetches) and render no row/card actions with visible/disabled predicates, so nothing is wired; recorded as findings below.",
     "files_changed": [
      ".changeset/29409-predicate-optional-field-harvest.md",
      "ui/packages/core/src/utils/__tests__/predicate-fields.test.ts",
      "ui/packages/core/src/utils/predicate-fields.ts"
     ],
     "line_budget": "68 changed lines (+67/-1) over 3 files vs threshold 3000: under",
     "tests": "592019e4: ui vitest packages/core/ 232 files passed, 4294 tests passed, 27 skipped (lock VERDICT command-exit 0); turbo type-check @object-ui/core 4/4 successful; 5e043f9a (after merging origin/main cafe8ee6, nothing under ui/packages/core changed): packages/core/src/utils/ 113 files, 2001 tests passed. Six new cases in predicate-fields.test.ts (33 to 39): five positive optional-selector cases, one of them through listViewPredicates, and one negative case with five spellings. Ablation via scripts/ablation-replace.mjs: RECORD_REF reverted to the main spelling, anchor 1 to 0, blob 7b0e2947 to fa1fda93; 5 failed / 34 passed (all five positive optional-selector cases red); restored blob == HEAD 7b0e2947, git diff HEAD empty. No dist rebuild needed: the test imports ../predicate-fields from source.",
     "gates": "592019e4: dispatch-gates --commands derived 34 families; all 34 ran exit 0 (incl. node scripts/check-sdui-manifest.mjs exit 0 and its --self-test exit 0, and pnpm --dir ui exec vitest run scripts/ 169 files passed / 2 skipped, 4921 tests). --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. ui check:new-line-citations: 0 new. Body gates against the PR body: check-changeset-no-major, check-adr-0087-registration, check-closing-keyword-parity, check-empty-changeset, check-partof-closing-keyword all exit 0. CI check-runs on #29480: in_progress at report time.",
     "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
     "deviations": [
      "Brief asked for a negative pin 'no harvest from strings'. Not implemented and not pinned: today the harvester reads record.x inside a CEL string literal, and the file's own asymmetry rule (an extra declared column costs bytes, a missing one fails the predicate closed) argues against masking literals, which would under-harvest on an unbalanced quote. Negatives pinned instead: record.? alone, record.?.x, data.?1st, myrecord.?x, record?.x. Told the seat before editing.",
      "No view test added: no view was wired (see findings), so the per-view projection and FLS pins the brief asked for have no subject.",
      "PR body says seven new cases and '7 个用例'; the count is six (33 to 39 cases). A corrected body is at /mnt/project-files/issue-29409/pr-body-seat.md (seat signature first) for the seat to apply; the dev cannot patch the body."
     ],
     "mcp_calls": "0 — no GitHub MCP calls",
     "api_writes": "2 — fleet-write relay pr_create (objectstack-ai/objectstack#29480) and this os-dev-report comment via post-stamped; plus 2 git pushes (not REST)",
     "open_questions": [],
     "security_findings": "none",
     "out_of_scope_findings": [
      "carrier: none · noted, not filed — kanban needs no harvest: ObjectKanban.tsx L949 query object and L877 lane-paging params carry $filter/$orderby/$top/$expand/$count/host search, no $select; no action visible/disabled evaluation in plugin-kanban/src.",
      "carrier: none · noted, not filed — calendar needs no harvest: ObjectCalendar.tsx L940 dataSource.find carries $filter/$orderby/ceiling/$expand, L1022 recordAnchorQuery the anchor filter, no $select; no action predicate evaluation in plugin-calendar/src.",
      "carrier: none · noted, not filed — gantt needs no harvest: ObjectGantt.tsx L1053 adapter.find carries $filter/$orderby/ceiling/$expand/search, no $select; no action predicate evaluation in plugin-gantt/src.",
      "carrier: none · noted, not filed — bracket spellings record['x'] and CEL optional index record[?'x'] are not harvested (unchanged, outside this card)."
     ]
    }
  7. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#3 · zhuangjianguo · session_01QsR2jV4dWohojjbTJTQq5m

    Landed · 2026-11-02T16:44Z

    PR #29480 merged at 2026-11-02T16:43Z as 86d36e99. Fixes #29409 closed this card; pm:dispatched removed. Delivered: the view projection harvest reads the CEL optional-field spelling record.?x / data.?x beside the plain one, so an action predicate on a field the list does not show finds it on the row; FLS and declared-field filters unchanged. Kanban, calendar and gantt were read and need no wiring (none sends $select or evaluates action predicates; file:line in report 6581921518). Nothing left on this card.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:uiDomain lane — seat card indexed by label:pm:seatpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions