You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
A stored list view filter is AND-only: no OR group #28020
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/specui/view.zod.tsListViewSchema.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.
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 22ce3d13feListView.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
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.
Activity
objectstack-fleet commentedon Oct 31, 2026
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V
Claim: PM loop round 3 · 2026-10-31T06:29Z
Session:
session_017ihL2fi9zfJhUTubyJYb6VAccount:
marchtianBranch:
claude/issue-28020-view-filter-or-groupWorktree:
objectstack-issue-28020Domain:
domain:specSeat:
domain:spec#4Ruling-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(ViewFilterRuleSchemaand 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, theui/packages/typesmirrors only where they are exhaustive copies, changeset (@objectstack/specminor). The console query build (ui/packages/plugin-list) is filed as adomain:uifollow-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-1answered HTTP 429; maintainer 「你没有fable了,使用 opus开发完之后等契约复审」),effort: mediumClause-②: 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
22ce3d13feListView.filter(view.zod.ts:3072) isz.array(ViewFilterRuleSchema), andViewFilterRuleSchema(view.zod.ts:1003) is a strict{ field, operator, value }object with no group memberSerial constraints cleared: open PRs touching
view.zod.tsare #28343 (the kanban block, L2094) and #28334 (the calendar block, L2278); neither touchesViewFilterRuleSchemaor a filter carrier. #28334 and #28315 touchplugin-list, which this card does not takeobjectstack-fleet commentedon Oct 31, 2026
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" ] }objectstack-fleet commentedon Oct 31, 2026
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 byFixes. This seat stripspm:dispatchedin the same act. Shape A, keyorby 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 anorgroup fails closed (the list reports a malformed filter and shows no rows). #28370 is unblocked by this landing and goes topm:queue.