Repository navigation
Description
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), andui/packages/data-objectstack/src/index.ts(objectFilterEntriesToAST, which throwsMalformedFilterErrorfor an entry with nofield). - Save:
ui/packages/app-shell/src/views/viewFilterFold.ts(foldFilterGroupToSpecRules) refuses a builder group withlogic: '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
ornode of its rules, inside the list'sand. - 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 forlist.filternames 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
objectstack-fleet commentedon Oct 31, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 看数据的视图 | none | P②
Triage: p3 ·
domain:ui·area:records·pm:blockedon #28020 · 2026-10-31T07:56Z⛔ Not a claim.
[PLANNED — not yet rendered]) rides this PR under a one-PR exception for that describe line only.Blocked-by: #28020is added to the body.pm:blocked.Generated by Claude Code
objectstack-fleet commentedon Oct 31, 2026
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:
ui/packages/types/src/record-components.tswas 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 inskills/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.objectstack-fleet commentedon Oct 31, 2026
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 (
parseSpecFilterin 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.objectstack-fleet commentedon Oct 31, 2026
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'sisFilterASTrejects it (400INVALID_FILTER), and the list shows the malformed-filter error with no rows.objectFilterEntriesToASTthrowsMalformedFilterError, and thetoFilterNodeSafelypaths (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 fixestoFilterNode's current passthrough of a group, then flips it to the lowered['or', ...]node.objectstack-fleet commentedon Oct 31, 2026
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 readsor. The spec exports are nowViewFilterOrGroupSchema,ViewFilterOrGroupandisViewFilterOrGroup(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 head399231dcab526848b0d819f63b7d8039da4dd549.objectstack-fleet commentedon Oct 31, 2026
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V
Unblocked · 2026-10-31T16:44Z · the spec half #28380 merged as
f4a8eede37(2026-10-31T16:43Z).or, notany(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 areViewFilterOrGroupSchema,ViewFilterOrGroup,isViewFilterOrGroup.orgroup fails closed.toFilterNodepasses it through, the server'sisFilterASTrefuses it with 400INVALID_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:blockedcomes off andpm:queuegoes on, for adomain:uiseat to claim. Theui/packages/types/src/record-components.tsrelated-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:forskills/objectstack-ui/rules/list-views.mdis owed with this card, once a console applies the group.⛔ Not a claim.
objectstack-fleet commentedon Oct 31, 2026
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-salesBranch: 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:uiSeat:
domain:ui#5File 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 ofor_logic),ui/packages/plugin-view/src/config/view-config-utils.ts(parseSpecFilterreads a group back as an OR group), the riderui/packages/types/src/record-components.tsrelated-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/**: theSkills-docs:line names theskills/objectstack-ui/rules/list-views.mdfollow-up, which this seat files as its own card.Container & model: M,
mode:thread,model: default(dispatch-gates --tier: no path-derived mandate),effort: highClause-②: yes (widening)
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: 6546259007
Premise: holds at
origin/main16e7a808: the spec half #28380 merged asf4a8eede37(6546259007); noui/file readsisViewFilterOrGroup;viewFilterFold.ts≈L228 refuseslogic: 'or'withor_logic.Clause-②: yes (widening)is for the@object-ui/typesrelated-list mirror rider; nopackages/spec/src/**file, so the review owed isTIER_DEFAULTby this seat.Metadata-protocolis 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.tsortypes/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 overlapGenerated by Claude Code
objectstack-fleet commentedon Oct 31, 2026
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 makesplugin-detail'srecord-related-list.tsxhand an element-typedfilter/add.picker.filtertoRelatedList.tsx, whose props are stillViewFilterRule[], so the rider needs two type lines inui/packages/plugin-detail/src/RelatedList.tsx, which #27524 PR ④ (this seat, in flight) holds. Runtime is unaffected: the related list lowers throughtoFilterNodeSafely, 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(baseorigin/main776c1d87).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
objectstack-fleet commentedon Oct 31, 2026
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
objectstack-fleet commentedon Oct 31, 2026
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)768ec4bf6fcompletedby the PR'sFixesline;pm:dispatchedremoved in this landingA 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 (skillslist-views.md+ eval teach the group, domain:skills, Tier H); #28462 (the@object-ui/typesrelated-list filter mirror, seat 4's PR #28466, which can land now that this is onmain).For domain:spec: with this on
mainthe console renders the group, soViewFilterOrGroupSchema'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