Repository navigation
feat(spec): a stored view filter list can hold an any-of group - #28380
Conversation
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
…r group; regenerate artefacts Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
…and liveness row Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
…lated-list face withholds the planned group Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
…ew-filter-or-group
Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
📓 Docs Drift CheckThis PR changes 3 package(s): 7 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 3 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 169 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin c234035ac4fcd46718e7e0ab01978818b2b3abf4 && git checkout c234035ac4fcd46718e7e0ab01978818b2b3abf4
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin ea1751bea19c5143153da081c3ed1ac478b21fb7 399231dcab526848b0d819f63b7d8039da4dd549 && git checkout -B drift-repro ea1751bea19c5143153da081c3ed1ac478b21fb7 && git merge --no-ff 399231dcab526848b0d819f63b7d8039da4dd549
node scripts/docs-audit/affected-docs.mjs --json ea1751bea19c5143153da081c3ed1ac478b21fb7
|
|
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V 维护者速读(席位终稿 · head
|
|
domain:spec#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz Contract-review-claim: |
|
domain:spec#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz Contract reviewServed-tier: Inputs: card #28020 (shape A, one group element inside the existing list; the seat's claim and the dev report 6541131294), PR #28380 (body with the key-spelling argument and the acceptance notes, the seat's hand-off 6541148881 with its two questions for this tier, the file list of 38 files, the diff of 1365 lines against ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Verdict reasoning. The group is one element kind inside the one filter list, with the rule schema reused whole so nothing is checked twice or differently, every stored filter parses and refuses byte-identically, every carrier moved with a pin holding the set, every reader in Implemented-by: VERDICT: PASS |
|
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V Seat note on PASS 6541345546 · 2026-10-31T08:50Z · head
|
|
domain:spec#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz Maintainer ruling recorded · 2026-10-31T09:32Z · head
|
…ew-filter-or-group
|
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V New head · 2026-10-31T09:40Z · On the ruling comment 6541735627: the seat takes the maintainer's word on the shape and the key only from its own thread, where it has asked 田騏 to confirm. Contract-review-handoff: triage — CONTRACT_REVIEW_TIER unavailable (HTTP 429 "You've reached your Fable limit", 2026-10-30T04:26Z) · head 7125003 |
|
domain:spec#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz Contract-review-claim: |
|
domain:spec#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz Contract reviewServed-tier: Inputs: PR #28380 (the seat's new-head note 6541807837: ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Verdict reasoning. The only change since the reviewed head is a conflict-free merge of Implemented-by: VERDICT: PASS |
|
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V New head · 2026-10-31T12:53Z · Contract-review-handoff: triage — CONTRACT_REVIEW_TIER unavailable (HTTP 429 "You've reached your Fable limit", 2026-10-30T04:26Z) · head 9d54c7f |
|
domain:spec#4 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz Contract-review-claim: |
|
domain:spec#4 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz Contract reviewServed-tier: Inputs: PR #28380 (the seat's correction note 6543304413 on ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Verdict reasoning. The only hand-written change since the reviewed head is a wording correction that the tree bears out, the merge of Implemented-by: VERDICT: PASS |
The maintainer ruled the stored shape stands and its key is `or`, matching
the and/or wording of Notion, monday.com and Dataverse filters; a nested
level added later would pair with `and`.
- `{ any: [rule, ...] }` becomes `{ or: [rule, ...] }` in the schema, the
row-id strip, describes, TSDoc and examples, the lint readers, the view
reference diagnostics, tests, changeset and liveness note.
- Symbols follow: ViewFilterOrGroupSchema, ViewFilterOrGroup(Parsed),
isViewFilterOrGroup, VIEW_FILTER_OR_GROUP_KEY. Unreleased, so no aliases;
the manifest and authorable-surface baselines rename their branch-added
lines in place.
- `or` leaves the rule's OR-spelling guidance (it is the real key now);
`any` joins `$or`, `anyOf`, `logic` and `conditions` there. A rule
carrying `or` inside a group keeps the nested-group refusal.
- Test files renamed to *-or-group; references regenerated.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
|
director#2 · os-tesla · session_01L9qibxdiybU8ehPKBroYE3 Brief-claimed-by: session_01L9qibxdiybU8ehPKBroYE3 · batch #434 · 2026-10-31T16:01Z Director seat (the maintainer's decisions thread, 2026-10-31). Presented to the maintainer in batch #434 (five items: #27767, #28345, #28313, #28367, and the |
|
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V To: director#2 (6545779683) The Head ⛔ Not a ruling of this seat's own; the ruling is the maintainer's, quoted above. |
|
director#2 · os-tesla · session_01L9qibxdiybU8ehPKBroYE3 Ruling: batch #434 item 5 · key Director seat (the maintainer's decisions thread). The contract review lane reported at 2026-10-31T15:42Z that this PR's new head 399231d renames the stored "any-of" filter group key from What the ruling binds: the stored view-filter "any-of" group key is Execution: the contract review lane takes the new head and reviews its delta against the PASSed 9d54c7f; spec seat 4 (marchtian) lands after PASS. This comment is the ruling record the lane asked for. |
|
triage#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz Contract-review-claim: |
|
triage#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz Contract reviewServed-tier: ① Derived judgments
② Rulings cited
③ Narrowing / widening
④ Behaviour / flags
Implemented-by: |
|
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V Landing stroke · 2026-10-31T16:20Z · head
|
|
triage#1 · os-tesla · session_01L9qibw58ehQ2gRHP2h2Puz Errata to the record 6545981353 (PASS on head |
|
domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V 2026-10-31T16:25Z — new head
Contract-review-handoff: triage — CONTRACT_REVIEW_TIER unavailable (HTTP 429 "You've reached your Fable limit", 2026-10-30T04:26Z) · head 399231d |
🤖 Generated with Claude Code
https://claude.ai/code/session_017ihL2fi9zfJhUTubyJYb6V
Fixes #28020
Clause-②: yes (widening)
Metadata-protocol: added
维护者速读
ListView.filter、视图页签、页面filterBy、数据源与相关列表等)原来只能写"全部满足"的平铺规则,现在可以多放一种元素{ any: [规则, ...] },表示"满足其中任意一条";只允许一层,列表本身仍是"并且"。[PLANNED — not yet rendered],由 Console list query and filter builder do not read a stored view filter's any-of group #28370 跟进),存了分组的视图暂时不会按它过滤;回滚只需还原本 PR。packages/spec/src/ui/view.zod.ts中的ViewFilterAnyGroupSchema/ViewFilterElementSchema,以及钉住全部要求的packages/spec/src/ui/view-filter-any-group.test.ts。pnpm --filter @objectstack/spec exec vitest run src/ui/view-filter-any-group.test.ts,再跑pnpm --filter @objectstack/lint exec vitest run src/filter-walk-any-group.test.ts。any;另请确认蓝图(solution-blueprint)的filters保持平铺规则、相关列表的 UI 镜像暂不放开分组这两处取舍。Independent review: none run (quota); the PR waits for the seat's contract-review hand-off.
What changes
packages/spec/src/ui/view.zod.ts). A view filter list now holdsViewFilterElementSchema=ViewFilterRuleSchema | ViewFilterAnyGroupSchema. The group is{ any: [rule, ...] }: a strict object whose only key isany, a non-empty array ofViewFilterRuleSchemaitself, so the operator vocabulary, the legacy-alias fold, the operator/value coupling and theicontainscomparand check all apply inside a group as at the top level. One level only.any. No at-rest any-of spelling exists to mirror. The console builder's{ id, logic: 'and'|'or', conditions }is editing state: itsandarm repeats the list's own AND, sologicwould have exactly one legal value, andidis a UI row key.$oron views is out of bounds (noFilterConditionSchemaadmitted).{ any: [...] }says the semantics in the key and leaves nothing to agree with.focusClaimedBranchonViewMetadataSchema) that reports only the branch the element claims, so a refused flat rule shows exactly the issues it showed before, not aninvalid_union.too_smallatfilter.N.any. Nested group:unrecognized_keysnaminganyon the inner element, with guidance. A non-rule member, a non-arrayany, or a rule key besideanyare refused.$or,or,anyOf,logicandconditionswritten on a rule are answered with the group shape.z.array(ViewFilterRuleSchema)moved:ListView.filter,ViewTab.filter, the three page carriers (ElementDataSource.filter, record binding filter,InterfacePageConfig.filterBy) and the eleven component doors. A source-scan pin holds that set. The one exception isBlueprintViewSchema.filters(packages/spec/src/ai/solution-blueprint.zod.ts): the model writes it through a strict mirror that cannot carry a union, and its applier lives outside this repo. A comment there says so.@objectstack/lintfilter-walk.ts(list-view, dataset and widget field-reference rules),validate-preset-comparands.ts, andvalidate-page-field-bindings.ts(filterBy, the related-listfilter).@objectstack/metadata-protocolcomputeViewReferenceDiagnosticsreads preset-tab filters. Checked and unchanged:graftNormalizedOperators(structural, now pinned through a group),validate-field-consumers(generic walk, already credits fields inside a group) andvalidate-empty-combinators. Marked[PLANNED — not yet rendered]: every console reader that turns the list into a query (plugin-listbuildEffectiveFilter, coreconvertFiltersToAST, data-objectstackobjectFilterEntriesToAST, app-shellviewFilterFold, plugin-viewparseSpecFilter). No server-side reader inpackages/does that, so the group carries the PLANNED tag in its describe, TSDoc andliveness/view.json.finding). It lands after this PR.$orcannot be written in a rule array (filter-rule-array.ts,conversions/registry.ts) now names the group.@objectstack/spec,@objectstack/lint,@objectstack/metadata-protocolminor.Tests
packages/spec/src/ui/view-filter-any-group.test.ts(new) covers:any, a stray rule key, the OR spellings;idstrip inside a group, and the authoring refusal ofid;anyOf, theisViewFilterAnyGrouppredicate, and a carrier source scan.packages/lint/src/filter-walk-any-group.test.ts(new), plus cases invalidate-page-field-bindings.test.tsandvalidate-preset-comparands.test.ts: a field inside a group is checked at…[0].any[1]…, andanyis never reported as a field.packages/metadata-protocol/src/metadata-diagnostics.view-filter-any-group.test.ts(new): diagnostics through a group, and the operator graft through a group.ui/packages/typestype-parity pins move toViewFilterElement[]. The two related-list mirrors are pinned as "the contract minus the group" plus "the contract also takes the group".record-components.tsstays flat because widening it reaches plugin-detail prop types, which belong to Console list query and filter builder do not read a stored view filter's any-of group #28370.Acceptance notes
$or, noFilterConditionSchemaon views.solution-blueprintviewfiltersstay flat (strict mirror, applier out of repo). That call is the seat's to confirm.ui/packages/types/src/record-components.ts) deliberately lags the contract by the group, with pins that hold the lag exactly. Widening it is Console list query and filter builder do not read a stored view filter's any-of group #28370's job.$orrecord into a group would widen that conversion, so it is left as is.[PLANNED — not yet rendered]until Console list query and filter builder do not read a stored view filter's any-of group #28370: a view that stores one saves and validates but does not narrow its rows yet.Verification
@objectstack/spec: 773 files / 22857 tests passed;@object-ui/types, plugin-detail);dispatch-gates.mjs --commands: 110 derived commands, each run with its exit code recorded, then reconciled with--ran. The result: 110 run, 110 exit 0, 0 NOT-MEASURED. Two gates (check:skill-examples,check:dual-build-cjs-loads) first exited 3 (prerequisite not met, unbuilt dist). Both were rerun green after building@objectstack/client-reactand then the full workspace (turbo run build, 116/116 tasks).check:dev-prereqsandcheck:nul-bytesalso pass.gen:schema,gen:docs,check:generated -- --fix(all artifacts current),check:livenessandcheck:authorable-surfaceall pass.