Skip to content

A stored list view filter is AND-only: no OR group #28020

Closed

Description

@objectstack-fleet

domain:ui#3 · os-bill · session_01Utp6CaJoinvGQSbHeDaWBe

Filing gate: ③ triage-directed. The order on #27386 said: take what is ui-only, card the rest. The card thread measured each row on origin/main (report 6518223407, out_of_scope_findings). Rows 2 and 4 are taken in PR #28017.
Reach: any list view whose natural filter is an any-of, such as HotCRM's "open, or completed in the last 7 days" (#27386 row 1).
Reader who acts: domain:spec first (a decision on the stored shape), then domain:ui (the list query build).
Duplicate search: search_issues "list view stored filter OR group any-of ViewFilterRule" → #19751, #24129 and #20456, all closed and about other parts of the view filter, not OR groups.

Observed

A list view's filter is an array of flat ViewFilterRuleSchema rules (field, operator, value) joined by AND. The $or grouping exists only in FilterConditionSchema, which the view's filter key does not take. So an any-of cannot be authored on a view, although the console filter builder already offers groups.

Wanted

  • Spec: decide the stored shape: either a filter-condition tree on views, or a group member on the rule list. Landing: packages/spec ui/view.zod.ts ListViewSchema.filter and ViewFilterRuleSchema.
  • Console: ui/packages/plugin-list's query build reads it.

Dedupe words: view filter OR group, ViewFilterRule or, list view filter any-of.

Related: #27386 (row 1).


Generated by Claude Code

Activity

  1. added
    enhancementNew feature or request
    pm:queueReady for the PM dispatch loop
    domain:specDomain lane — seat card indexed by label:pm:seat
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Oct 30, 2026
  2. added
    pm:queueReady for the PM dispatch loop
    and removed
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    on Oct 31, 2026
  3. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

    Claim: PM loop round 3 · 2026-10-31T06:29Z
    Session: session_017ihL2fi9zfJhUTubyJYb6V
    Account: marchtian
    Branch: claude/issue-28020-view-filter-or-group
    Worktree: objectstack-issue-28020
    Domain: domain:spec
    Seat: domain:spec#4
    Ruling-ref: maintainer 「可以开始派发 p3」 (2026-10-30T12:23Z) and 「当前任务处理完,合并后改为并发1」 (2026-10-31T05:08Z); the card's filing gate ③ (triage-directed, order on #27386, report 6518223407). The stored-shape fork the card names is put to the maintainer; this claim builds the seat's recommended shape (A below) and the PR does not land before the maintainer rules on it.
    File surface: packages/spec/src/ui/view.zod.ts (ViewFilterRuleSchema and its carriers gain one group element beside the flat rule: shape A, an any-of group of flat rules inside the existing AND list, so the list stays the one filter vocabulary on every carrier and every stored filter parses unchanged), packages/spec/src/ui/filter-rule-array.ts, the readers that walk a rule array (packages/lint/src/filter-walk.ts, validate-field-consumers.ts, packages/metadata-protocol/src/protocol.ts, packages/spec/src/conversions/registry.ts) only where a group element would be misread, describes, tests, regenerated spec artefacts and reference docs, the ui/packages/types mirrors only where they are exhaustive copies, changeset (@objectstack/spec minor). The console query build (ui/packages/plugin-list) is filed as a domain:ui follow-up card by this PR's dev, not taken here (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: TIER_DEFAULT (opus) — the quota-exhaustion exemption (claude-fable-5-1 answered HTTP 429; maintainer 「你没有fable了,使用 opus开发完之后等契约复审」), effort: medium
    Clause-②: yes (widening)
    Metadata-protocol: added
    Responsibility: a stored list view filter is AND-only, so an any-of view ("open, or completed in the last 7 days") cannot be authored | an any-of group element in the view filter rule list, judged at parse like a rule | every list view, tab, related list, page base filter and picker filter whose natural filter is an any-of (HotCRM, #27386 row 1)
    Thread-read: none
    Premise: holds — on 22ce3d13fe ListView.filter (view.zod.ts:3072) is z.array(ViewFilterRuleSchema), and ViewFilterRuleSchema (view.zod.ts:1003) is a strict { field, operator, value } object with no group member
    Serial constraints cleared: open PRs touching view.zod.ts are #28343 (the kanban block, L2094) and #28334 (the calendar block, L2278); neither touches ViewFilterRuleSchema or a filter carrier. #28334 and #28315 touch plugin-list, which this card does not take

  4. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Oct 31, 2026
  5. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V
    os-dev-report

    {
     "issue": 28020,
     "status": "done",
     "pr": 28380,
     "head_sha": "68b811655830245edb343e45ed08b7b2590d131a",
     "branch": "claude/issue-28020-view-filter-or-group",
     "gates": {
      "derived_at": "68b8116558",
      "derived": 110,
      "run": 110,
      "exit_0": 110,
      "not_measured": 0,
      "unrun": 0,
      "ran_verdict_exit": 0,
      "first_run_exit_3": [
       {
        "command": "pnpm --filter @objectstack/spec run check:skill-examples",
        "cause": "packages/client-react/dist absent",
        "rerun_exit": 0,
        "after": "pnpm --filter @objectstack/client-react... build"
       },
       {
        "command": "pnpm check:dual-build-cjs-loads",
        "cause": "34 package dist/ absent",
        "rerun_exit": 0,
        "after": "turbo run build --filter=!@objectstack/docs (116/116)"
       }
      ],
      "local_only": {
       "check:dev-prereqs": 0,
       "check:nul-bytes": 0
      },
      "tests_post_merge": {
       "@objectstack/spec": {
        "files": 773,
        "tests": 22857,
        "failed": 0
       },
       "@objectstack/lint (targeted)": {
        "files": 4,
        "tests": 263,
        "failed": 0
       },
       "@objectstack/metadata-protocol (targeted)": {
        "files": 1,
        "tests": 3,
        "failed": 0
       }
      },
      "tests_pre_merge": {
       "@objectstack/lint": {
        "files": 183,
        "tests": 7693,
        "failed": 0,
        "typecheck": 0
       },
       "@objectstack/metadata-protocol": {
        "files": 285,
        "failed": 0,
        "typecheck": 0
       },
       "ui type-check (spec dependents)": "green after pin moves",
       "ui pin tests": {
        "files": 6,
        "tests": 184,
        "failed": 0
       }
      },
      "regen": {
       "gen:schema": 0,
       "gen:docs": 0,
       "check:generated --fix": 0,
       "check:liveness": 0,
       "check:authorable-surface": 0
      }
     },
     "line_budget": {
      "stated": null,
      "total": {
       "files": 38,
       "added": 1243,
       "removed": 122
      },
      "handwritten_excl_generated": {
       "added": 881,
       "removed": 46
      },
      "tests": {
       "added": 491,
       "removed": 14
      }
     },
     "deviations": [
      {
       "what": "ui/packages/types/src/__tests__ type-parity pins edited (6 files)",
       "why": "widening ViewFilterRuleSchema carriers flips Equal<> pins; mirror source record-components.ts left flat"
      },
      {
       "what": "os-regen-merge.sh step 3 finished by hand",
       "why": "its commit refused on stale docs after merge 669502d4fc; rebuilt spec, gen:docs, check:generated --fix, committed 68b8116558"
      },
      {
       "what": "full ui type-check ran pre-merge only",
       "why": "post-merge reran spec/lint/metadata-protocol tests and the 110 gates; ui pin files untouched by the merge"
      },
      {
       "what": "BlueprintViewSchema.filters not widened",
       "why": "strict mirror cannot carry a union; applier is outside the repo"
      },
      {
       "what": "origin/main advanced 7 commits after the head; not re-merged",
       "why": "git merge-tree clean; packages/spec/src/ui/view.zod.ts and packages/lint/src/validate-list-view-field-refs.ts touched upstream"
      }
     ],
     "key_spelling": {
      "key": "any",
      "mirrored_existing": false
     },
     "readers": {
      "updated": [
       "packages/lint/src/filter-walk.ts",
       "packages/lint/src/validate-preset-comparands.ts",
       "packages/lint/src/validate-page-field-bindings.ts",
       "packages/metadata-protocol/src/metadata-diagnostics.ts"
      ],
      "unchanged_verified": [
       "packages/metadata-protocol/src/protocol.ts#graftNormalizedOperators",
       "packages/lint/src/validate-field-consumers.ts",
       "packages/lint/src/validate-empty-combinators.ts"
      ],
      "planned_not_rendered": {
       "follow_up": 28370,
       "readers": [
        "ui/packages/plugin-list ListView buildEffectiveFilter",
        "ui/packages/core filter-converter convertFiltersToAST",
        "ui/packages/data-objectstack objectFilterEntriesToAST",
        "ui/packages/app-shell viewFilterFold",
        "ui/packages/plugin-view parseSpecFilter"
       ]
      }
     },
     "files_changed": [
      ".changeset/28020-view-filter-any-group.md",
      "content/docs/references/api/protocol.mdx",
      "content/docs/references/data/object.mdx",
      "content/docs/references/index.mdx",
      "content/docs/references/ui/component.mdx",
      "content/docs/references/ui/page.mdx",
      "content/docs/references/ui/view.mdx",
      "docs/audits/2026-07-unknown-key-strictness-ledger.counts/ui.md",
      "packages/lint/src/filter-walk-any-group.test.ts",
      "packages/lint/src/filter-walk.ts",
      "packages/lint/src/validate-page-field-bindings.test.ts",
      "packages/lint/src/validate-page-field-bindings.ts",
      "packages/lint/src/validate-preset-comparands.test.ts",
      "packages/lint/src/validate-preset-comparands.ts",
      "packages/metadata-protocol/src/metadata-diagnostics.ts",
      "packages/metadata-protocol/src/metadata-diagnostics.view-filter-any-group.test.ts",
      "packages/spec/api-surface/ui.json",
      "packages/spec/authorable-surface/ui.json",
      "packages/spec/declaration-map/ui.json",
      "packages/spec/dropped-refinements.baseline.json",
      "packages/spec/export-origins/ui.json",
      "packages/spec/json-schema.manifest/ui.json",
      "packages/spec/liveness/view.json",
      "packages/spec/src/ai/solution-blueprint.zod.ts",
      "packages/spec/src/conversions/registry.ts",
      "packages/spec/src/ui/component.zod.ts",
      "packages/spec/src/ui/filter-rule-array-guidance.test.ts",
      "packages/spec/src/ui/filter-rule-array.ts",
      "packages/spec/src/ui/page.test.ts",
      "packages/spec/src/ui/page.zod.ts",
      "packages/spec/src/ui/view-filter-any-group.test.ts",
      "packages/spec/src/ui/view.zod.ts",
      "ui/packages/types/src/__tests__/gantt-flat-config-declared-keys.test.ts",
      "ui/packages/types/src/__tests__/grid-default-filters-gantt-map-filter-round10-6152.test.ts",
      "ui/packages/types/src/__tests__/grid-kanban-calendar-members-round8-6152.test.ts",
      "ui/packages/types/src/__tests__/kanban-calendar-filter-sort-8174.test.ts",
      "ui/packages/types/src/__tests__/related-list-add-picker-filter-mirror-9964.test.ts",
      "ui/packages/types/src/__tests__/related-list-filter-rule-array-10199.test.ts"
     ],
     "mcp_calls": 0,
     "api_writes": [
      {
       "op": "issue_create",
       "via": "scripts/pm/issue-create.mjs",
       "target": 28370
      },
      {
       "op": "pr_create",
       "via": "scripts/pm/fleet-write/dispatch.mjs",
       "target": 28380,
       "readback": "8186/8186 bytes identical"
      },
      {
       "op": "comment",
       "via": "scripts/pm/post-stamped.mjs",
       "target": 28020
      }
     ],
     "out_of_scope_findings": [
      {
       "class": "consumer-gap",
       "reach": "objectstack-ai/objectstack ui/packages (console list query and filter builder)",
       "evidence": "#28370: no console reader applies { any: [...] }; filed as the consumer half"
      },
      {
       "class": "conversion-widening",
       "reach": "packages/spec/src/conversions/registry.ts",
       "evidence": "a stored $or record is not converted to an any-of group; doing so widens the conversion"
      },
      {
       "class": "mirror-lag",
       "reach": "ui/packages/types/src/record-components.ts + plugin-detail props",
       "evidence": "related-list mirror stays flat ViewFilterRule[]; pinned as Exclude<contract element, ViewFilterAnyGroup>"
      }
     ],
     "seat_decisions": [
      "ratify stored shape { any: [rule, ...] } one level and key name any (maintainer)",
      "BlueprintViewSchema.filters stays flat rules",
      "related-list ui mirror stays flat until #28370 vs widening with plugin-detail props"
     ]
    }
  6. objectstack-fleet commented on Oct 31, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

    Landed · 2026-10-31T16:43Z · PR #28380 merged by the queue at 2026-10-31T16:43Z as f4a8eede37; the card closed by Fixes. This seat strips pm:dispatched in the same act. Shape A, key or by the maintainer's ruling (decision card 2026-10-31T14:23:54Z, recorded again 6545957296): a view filter list may hold { or: [rule, ...] } beside plain rules, one level, never empty. Contract review: PASS 6541345546, delta PASSes 6542065823, 6543859741 and 6545981353 on the landed head. Until the console half #28370 lands, a view that stores an or group fails closed (the list reports a malformed filter and shows no rows). #28370 is unblocked by this landing and goes to pm:queue.

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

Metadata

Metadata

Assignees

Labels

domain:specDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions