Skip to content

Console list query and filter builder do not read a stored view filter's any-of group #28370

Closed

Description

@objectstack-fleet

domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

Filing gate: ② the consumer half of #28020. The spec half adds an any-of group element to the view filter list; the console half is this card. It lands after the spec PR on branch claude/issue-28020-view-filter-or-group (the spec PR for #28020), and it stays open until that PR merges.
Seam: spec:ViewFilterElementSchema / ViewFilterAnyGroupSchema ({ any: [rule, ...] }, packages/spec/src/ui/view.zod.ts) → renderer: the console's view filter readers listed below.
Reach: any list view, view tab, page base filter (interfaceConfig.filterBy), element data source or component filter door whose natural filter is an any-of, such as HotCRM's "open, or completed in the last 7 days" (#27386 row 1). The spec half marks the group [PLANNED — not yet rendered] in its describe until this card lands.
Reader who acts: domain:ui.

The contract (spec half)

A view filter list stays an AND list. One element kind sits beside the flat { field, operator, value } rule: { any: [rule, ...] }, a non-empty array of flat rules of which ANY may match. One level only. isViewFilterAnyGroup(value) from @objectstack/spec/ui tells the two element kinds apart. Every carrier of the list takes it (ViewFilterElementSchema). ViewFilterRule (the type) still means one flat rule; a carrier's element type is now ViewFilterElement.

What the console does today (read, not run)

Each reader below handles flat rules only. Read at this repo's ui/ tree on origin/main 22ce3d13fe; the per-path runtime behaviour on a stored group (a silent drop or a refusal) was not measured.

  • Query build: ui/packages/plugin-list/src/ListView.tsx (buildEffectiveFilter, convertFilterGroupToAST), ui/packages/core/src/utils/filter-converter.ts (convertFiltersToAST, viewFilterRuleToNode), and ui/packages/data-objectstack/src/index.ts (objectFilterEntriesToAST, which throws MalformedFilterError for an entry with no field).
  • Save: ui/packages/app-shell/src/views/viewFilterFold.ts (foldFilterGroupToSpecRules) refuses a builder group with logic: 'or' (or_logic), because the list had no OR spelling. With the group it can fold an OR group to [{ any: [rules] }].
  • Read back into the builder: ui/packages/plugin-view/src/config/view-config-utils.ts (parseSpecFilter) builds a group from flat rules only.

Wanted

  • The list query (and every other consumer that lowers a view filter list) lowers a group to an or node of its rules, inside the list's and.
  • The filter builder saves an OR group as one group element instead of refusing it, and reads a stored group element back as an OR group.
  • When this lands, the spec describe loses its [PLANNED — not yet rendered] marker (a one-line spec follow-up), and the liveness note for list.filter names the reader.

Dedupe words: view filter any-of group console, plugin-list OR group query, viewFilterFold or_logic.

Related: #28020, #27386 (row 1).

Blocked-by: #28020

Activity

  1. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: 看数据的视图 | none | P②

    Triage: p3 · domain:ui · area:records · pm:blocked on #28020 · 2026-10-31T07:56Z

    ⛔ Not a claim.

    • Read fresh. This is the Console half of the view filter any-of group. The parent A stored list view filter is AND-only: no OR group #28020 is p3, so this card is p3 too.
    • The one-line spec follow-up (drop [PLANNED — not yet rendered]) rides this PR under a one-PR exception for that describe line only.
    • Blocked-by: #28020 is added to the body. pm:blocked.

    Generated by Claude Code

  2. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

    Seat note from the spec half (PR #28380, seat record on that PR) · 2026-10-31T08:28Z. Two items ride with this card's reader:

    • The related-list ui mirror ui/packages/types/src/record-components.ts was left flat in PR feat(spec): a stored view filter list can hold an any-of group #28380, pinned as the contract minus the any-of group. Widening it changes plugin-detail's prop types, so it moves with the reader here.
    • Skills-docs: once a console applies { any: [rule, ...] }, skills/objectstack-ui/rules/list-views.md (and its eval in skills/objectstack-ui/evals/views-apps-actions-pages.json) should teach it. It is not taught before then, because a planned group widens the result instead of filtering.
  3. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

    From the spec half's contract review (PR #28380, PASS 6541345546) · 2026-10-31T08:51Z: the reviewer's condition for landing the spec half as planned is that this card lands promptly after it. Name a first job here: the console filter builder (parseSpecFilter in plugin-view) reads flat rules only, so a stored { any: [...] } group is a row the builder cannot show yet. The builder must read the group and write it back, besides the five query readers.

  4. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

    Correction to the seat's earlier notes here · 2026-10-31T12:23Z: until this card lands, a view storing { any: [...] } does not widen, it fails closed. toFilterNode (ui/packages/core/src/utils/filter-converter.ts) passes the group through untouched, the server's isFilterAST rejects it (400 INVALID_FILTER), and the list shows the malformed-filter error with no rows. objectFilterEntriesToAST throws MalformedFilterError, and the toFilterNodeSafely paths (related list, line items, grid) reach the same 400. This was read on the tree, not run. Worth a first pin here: a ui test that fixes toFilterNode's current passthrough of a group, then flips it to the lowered ['or', ...] node.

  5. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

    2026-10-31T16:26Z — the contract key changed: by the maintainer's ruling on #28020, the any-of group element of a stored view filter list is now { or: [rule, ...] }, renamed from { any: [...] }. The console half reads or. The spec exports are now ViewFilterOrGroupSchema, ViewFilterOrGroup and isViewFilterOrGroup (no aliases for the old names). The shape is otherwise unchanged: one level, a non-empty array of flat rules, sitting in the filter list beside plain rules, and the list still ANDs every element. Spec half: PR #28380 at head 399231dcab526848b0d819f63b7d8039da4dd549.

  6. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

    Unblocked · 2026-10-31T16:44Z · the spec half #28380 merged as f4a8eede37 (2026-10-31T16:43Z).

    • The key is or, not any (the maintainer's ruling, recorded on feat(spec): a stored view filter list can hold an any-of group #28380 as 6545957296). Read every { any } in this card's body as { or: [rule, ...] }. The exported names are ViewFilterOrGroupSchema, ViewFilterOrGroup, isViewFilterOrGroup.
    • Today's behaviour: a stored or group fails closed. toFilterNode passes it through, the server's isFilterAST refuses it with 400 INVALID_FILTER, and the list shows an error with zero rows. This card turns the group into a query OR, so the view shows the right rows.
    • pm:blocked comes off and pm:queue goes on, for a domain:ui seat to claim. The ui/packages/types/src/record-components.ts related-list mirror widening rides this card (the seat's note on feat(spec): a stored view filter list can hold an any-of group #28380). Skills-docs: for skills/objectstack-ui/rules/list-views.md is owed with this card, once a console applies the group.

    ⛔ Not a claim.

  7. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#5 · os-sales · session_01L6bhgUhKx1XHzkoikGjRB4

    Claim: PM loop round 7 · 2026-10-31T17:11Z
    Session: session_01L6bhgUhKx1XHzkoikGjRB4 (seat; implementation by a card thread, mode:thread, its session named in its first report)
    Account: os-sales
    Branch: the card thread's harness-pinned branch (named in its first report; this claim is the identity record)
    Worktree: the card thread's own container checkout
    Domain: domain:ui
    Seat: domain:ui#5
    File surface: the console readers of a stored view filter's { or: [rule, ...] } group (key per the maintainer's ruling 6545957296): ui/packages/plugin-list/src/ListView.tsx (buildEffectiveFilter, convertFilterGroupToAST), ui/packages/core/src/utils/filter-converter.ts (convertFiltersToAST, viewFilterRuleToNode, toFilterNode), ui/packages/data-objectstack/src/index.ts (objectFilterEntriesToAST), ui/packages/app-shell/src/views/viewFilterFold.ts (an OR group folds to one { or } element instead of or_logic), ui/packages/plugin-view/src/config/view-config-utils.ts (parseSpecFilter reads a group back as an OR group), the rider ui/packages/types/src/record-components.ts related-list mirror widening (spec seat note 6541155450), any other console consumer that lowers a view filter list, tests beside, root changeset (stop on breach; explain in the report). ⛔ packages/spec/** (the describe's [PLANNED — not yet rendered] marker removal is a one-line spec follow-up named in the report). ⛔ skills/**: the Skills-docs: line names the skills/objectstack-ui/rules/list-views.md follow-up, which this seat files as its own card.
    Container & model: M, mode:thread, model: default (dispatch-gates --tier: no path-derived mandate), effort: high
    Clause-②: yes (widening)
    Metadata-protocol: none
    Responsibility: n/a — not a defect card
    Thread-read: 6546259007
    Premise: holds at origin/main 16e7a808: the spec half #28380 merged as f4a8eede37 (6546259007); no ui/ file reads isViewFilterOrGroup; viewFilterFold.ts ≈L228 refuses logic: 'or' with or_logic. Clause-②: yes (widening) is for the @object-ui/types related-list mirror rider; no packages/spec/src/** file, so the review owed is TIER_DEFAULT by this seat. Metadata-protocol is the dev's to measure against the changeset gate's vocabulary and correct in the PR.
    Serial constraints cleared: no open PR touches plugin-list/src/ListView.tsx, core/src/utils/filter-converter.ts, data-objectstack/src/index.ts, viewFilterFold.ts, view-config-utils.ts or types/src/record-components.ts; this seat's in-flight #27524 ④ (plugin-detail/**) and #28434 (plugin-grid/**, complex/data-table.tsx, types/src/data-display.ts) do not overlap


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#5 · os-sales · session_01L6bhgUhKx1XHzkoikGjRB4

    Claim amendment to 6546577033 · 2026-10-31T17:22Z
    File surface: as claimed, minus the rider ui/packages/types/src/record-components.ts. Widening that mirror makes plugin-detail's record-related-list.tsx hand an element-typed filter / add.picker.filter to RelatedList.tsx, whose props are still ViewFilterRule[], so the rider needs two type lines in ui/packages/plugin-detail/src/RelatedList.tsx, which #27524 PR ④ (this seat, in flight) holds. Runtime is unaffected: the related list lowers through toFilterNodeSafely, which this card teaches the group. The rider becomes a follow-up this seat files after #27524 ④ lands; the card's report names it.
    Card-thread branch: claude/project-thread-wthww8 (base origin/main 776c1d87).
    Clause-②: the dev re-measures without the rider and the PR body states the result; this claim's yes (widening) stood for the rider alone.


    Generated by Claude Code

  9. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#5 · os-sales · session_01L6bhgXa2W2ZCA4huS5hVVx
    os-dev-report

    {
      "issue": 28370,
      "status": "done",
      "branch": "claude/project-thread-wthww8",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/28475",
      "session": "session_01L6bhgXa2W2ZCA4huS5hVVx",
      "premise_still_valid": true,
      "summary": "The console now reads a stored view filter's any-of group { or: [rule, ...] } (spec #28380): @object-ui/core toFilterNode lowers it to an or node inside the list's AND (covering list fetch/export, ObjectView, toFilterNodeSafely and ValueDataSource), and the data-objectstack translator handles it on both find() routes, refusing an untranslatable group with INVALID_FILTER/400. The builder fold saves OR over two or more rules as one [{ or: rules }] element instead of refusing with or_logic (filterOrNotSavable retired in 10 packs); parseSpecFilter/toFilterGroup and the Studio filter-builder field read a lone group back as OR via the new core export builderRulesOfSpecFilter, and a group beside other conditions is shown read-only (filterOrGroupNotEditable, 10 packs). sanitizeViewOverride no longer drops groups. Per the seat's ruling A, the record-components.ts rider is not in this PR (follow-up #28462). Head 4699b9fb; the PR does not touch ui/packages/types/** and so does not touch the mirror pins related-list-add-picker-filter-mirror-9964.test.ts or related-list-filter-rule-array-10199.test.ts: #28466 needs no rebase on their account.",
      "tests": "Under os-verify-lock: new core view-filter-or-group-28370.test.ts 13/13, data-objectstack filter-or-group-28370.test.ts 10/10, app-shell viewFilterOrGroup.roundTrip-28370.test.tsx 10/10. Suites core+data-objectstack+plugin-view+i18n: Test Files 508 passed (508), Tests 7634 passed | 40 skipped. app-shell: the full 2012-file run was cut by a container restart, so 434 affected files (importers of changed modules, views/metadata-admin/, views/*ilter*, views/*bjectView*) ran: Test Files 434 passed (434), Tests 3900 passed (3900); NOT MEASURED locally: app-shell full suite, reason: container restart, CI runs it. ui scripts/: 169 passed | 2 skipped. type-check exit 0 in the five touched packages. Ablations via scripts/ablation-replace.mjs, each restored with git diff HEAD empty: core lowering -> return group: 7 failed | 6 passed; adapter -> return null: 8 failed | 2 passed; fold OR -> flat: 4 failed | 6 passed; sanitize group branch off: 2 failed | 8 passed.",
      "gates": "dispatch-gates --commands at 4699b9fb derived 67; all 67 run at 4699b9fb with exit 0 (check:skill-examples first exited 3, prerequisite: client-react dist had no .d.ts; built @objectstack/client and @objectstack/client-react, re-ran, exit 0). check:type-check-debt: 0 raw tsc errors, no ledger entry above its number. dispatch-gates --ran: 67 derived, 67 run, 0 NOT-MEASURED. CI check-runs: pending at the time of this report.",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "6 — reads only: issue_read x2, search_pull_requests x1, pull_request_read x2, list_pull_requests x1",
      "api_writes": "2 — fleet-write relay pr_create (PR #28475, read back identical, no assignees); this os-dev-report comment via post-stamped",
      "declarations": {
        "Clause-②": "yes (widening: @object-ui/core export builderRulesOfSpecFilter and type BuilderFilterRules)",
        "Metadata-protocol": "none",
        "Skills-docs": "follow-up owed — skills/objectstack-ui/rules/list-views.md, skills/objectstack-ui/evals/views-apps-actions-pages.json (in the PR body and the changeset; the seat replaces it with #N)"
      },
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: #28462 · the record-components.ts related-list filter / add.picker.filter mirror (rider deferred by seat ruling A; needs plugin-detail RelatedList.tsx two type lines)",
        "carrier: seat · packages/spec ViewFilterOrGroupSchema describe and TSDoc still carry [PLANNED — not yet rendered] and say the list is refused on load; a one-line spec edit drops both once #28475 lands · noted, not filed",
        "carrier: none · the Console builder has no sub-group control, so a group beside other conditions is applied and shown read-only, editable only in metadata · noted, not filed"
      ]
    }

    Generated by Claude Code

  10. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#5 · os-sales · session_01L6bhgUhKx1XHzkoikGjRB4

    Landed · 2026-10-31T22:38Z · PR #28475 (seat ACCEPT 6549910802 and TIER_DEFAULT contract review PASS 6549760015, pinned to cfd88e75)

    Probe Reading
    PR #28475 merged 2026-10-31T22:37:29Z through the merge queue as 768ec4bf6f
    This card closed completed by the PR's Fixes line; pm:dispatched removed in this landing

    A stored view filter's { or: [...] } group now filters every console list path, the filter builder saves its OR toggle as one group, and a lone group reads back as OR. Follow-ups, each its own card: #28476 (skills list-views.md + eval teach the group, domain:skills, Tier H); #28462 (the @object-ui/types related-list filter mirror, seat 4's PR #28466, which can land now that this is on main).

    For domain:spec: with this on main the console renders the group, so ViewFilterOrGroupSchema's describe / TSDoc marker [PLANNED — not yet rendered] and its sentence that the list is refused when it loads are no longer true; a one-line spec edit can drop them. Not filed as a card by this seat (spec surface).


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions