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
dataSource.filter's "three shapes legitimately reach a renderer" note is now half true — upstream converged the authoring door on the ViewFilterRule array #8945
Filed from objectstack by the domain:spec execution seat, session_01MkQhmuuJAVDjmeWNixwDDH, 2026-09-10T06:46Z, out of the at-ACCEPT residue of objectstack PR #17257 (#15442 / #15449) and PR #17267. ⛔ Unclaimed. No domain:* label and no pm:* state: ⛔ both are the triage seat's to produce.
The shipped migration entry that caused this card names it as owed work, in its own words: "objectui cards filed by the seat, not blocked on here." This is that card.
What changed upstream
Seven filter doors in @objectstack/spec converged on z.array(ViewFilterRuleSchema) — the rule array [{ field, operator, value }, ...] — and the MongoDB-style record form and the ObjectQL AST tuple array are now refused at all seven (objectui#6206, maintainer batch adjudication 2026-08-25, verbatim 「同意」, Option B; family-wide convergence, decision batch #55, 2026-09-06, verbatim 「同意」, option A). The one that reaches this repo hardest is the binding: ElementDataSourceSchema.filter.
Prescription (record → rule array, operator objects, several-keys-AND, tuple arrays, legacy shorthands) is in the objectstack semantic entries 18.element-data-source-and-object-block-filter-rule-array, 18.element-number-filter-rule-array, 18.element-record-picker-filter-rule-array.
What this repo says today, measured at the pin 53ded82bf7a494f54e344e19099dbf00854b8694
packages/core/src/data-scope/element-data-source.ts — the ElementDataSourceConfig docblock, verbatim:
filter is typed unknown rather than the spec's FilterCondition because three shapes legitimately reach a renderer here (a MongoDB-style condition object, an ObjectQL AST node array, a spec ViewFilterRule[]) and {@link mergeFilterNodes} is the single sink that lowers all three. Narrowing the type here would only move the cast, not remove it.
⚠️After the convergence only ONE of those three is legal at the authoring door. The other two remain legal at the renderer — the upstream disposition deliberately does not rewrite metadata at rest, so a stored page carrying the record form keeps loading and keeps arriving here. ⇒ The note is not simply wrong; it now conflates two populations (what an author may write vs. what a renderer may receive) that upstream has just split apart. That is what needs re-stating.
packages/components/src/renderers/basic/record-picker.tsx — carries spec-facing filter commentary at three sites (measured at the pin: :93, :332, :348). ⚠️Do not trust a second-hand summary of what they say. A review handed to the objectstack seat described these as "documents dataSource.filter as a FilterCondition and says the spec rejects the array", and that wording did not reproduce on inspection; the same review also gave the path as packages/plugin-list/src/record-picker.tsx, which is wrong. Read the three sites; do not carry the paraphrase forward.
Registry declarations — objectui#7712 (closed) recorded that plugin-kanban and plugin-calendar registrations declare no filter input at all while both renderers read schema.filter; objectui#8220 (open, pm:queue) is the live successor for plugin-map / plugin-gantt / plugin-timeline. Both are about a missing declaration; this card is about the shape a present one should declare. Whoever takes #8220 should land the array arm rather than re-declaring the old shape.
⚠️ The author population — a number this card deliberately does NOT assert
The upstream entry's own acceptance text says: "the seventeen dataSource.filter test authors at the pin (fifteen tuple arrays, two records) become off-spec fixtures". That is the shipped claim and it is the one to start from.
⛔ The objectstack seat could not reproduce it and is not asserting a rival number. What it did, so the next person does not repeat it:
A git grep --multiline -P 'dataSource\s*:\s*\{[^}]{0,400}?filter\s*:' at the pin returned 0 files — a pattern failure, not a reading (a control git grep -l dataSource returns 765 files). [^}] cannot cross the nested object literals these bindings contain.
A line-proximity heuristic (a dataSource mention with a filter: within 8 lines) returned 103 hits across 62 files — and inspection of the sample shows it is measuring the wrong population: most hits are runtime $filter query objects (sharedUserFeeds.ts, RecordAttachmentsPanel.tsx, RecordDetailView.tsx) and re-reads of somebody else's dataSource.filter (ReportView.tsx:284), not authored binding metadata.
An earlier, broader pattern used in the objectstack lane returned 27 files. It is not comparable to the seventeen either, for the same reason.
⇒ Re-measure with a stated method and publish the method with the number. A proximity or regex probe over .ts / .tsx will not separate authored binding metadata from runtime query construction; the population is defined by what parses against ElementDataSourceSchema, so the reliable instrument is parsing the candidates, not grepping them.
Restart condition — this is not workable today
objectui consumes @objectstack/spec as a published package ("@objectstack/spec": "^17.0.0"), and the convergence is not released yet. Measured on objectstack origin/main501959b72: EvaluatedExpressionInputSchema appears 0× in packages/spec/CHANGELOG.md (lit control: EvaluatedExpressionSchema appears 4× there) and the change sits unconsumed in .changeset/flow-edge-condition-evaluated-slot.md; spec package.json reads 17.4.0.
⇒ run from this repo's root after pnpm install. Exit 0 fires the hold (the record-form filter is refused); exit 1 keeps it; ⛔ exit 9 means the instrument is dead and the run says nothing — it is ⛔ never a fire. Still the install-face probe, ⛔ not "the upstream PR merged". Restart-touch:packages/core/src/data-scope/element-data-source.ts, packages/components/src/renderers/basic/record-picker.tsx
⚠️ ⛔ Until that probe passes, nothing here is red and nothing here should move. The state label (pm:blocked vs pm:on-hold — the cross-repo rule says an unreleased upstream is pm:on-hold with an install-face Restart-when:, not pm:queue) is the triage seat's to set.
Dedup
Complete enumeration read 2026-09-10T06:46Z: objectui open domain:ui = 280 (3 pages, 100 + 100 + 80 — the third page under the cap, so the enumeration is complete, not truncated). Grepped for dataSource / filter / FilterCondition / rule array / record-picker.
Nearest neighbours, each read and judged not a duplicate:
objectstack #15442 · #15449 · PR #17257 · #15807 · PR #17267 · the three 18.*-filter-rule-array semantic entries on objectstack origin/main501959b72
⚠️Restart-when: REPAIRED — it was prose, and prose is not an exit (2026-09-19T03:02Z)
Half-state patrol row H9 named this card: 「pm:on-hold with its Restart-when: is prose naming no issue, no tracked path and no runnable command — a manual in disguise; nothing schedules the actor it waits on」. It was right. The condition was well-chosen and correct; it had no spelling any actor could run, and 〈可执行判据由分诊席每日一个低频子轮批量执行〉 is the actor that needs one.
⭐ The condition is UNCHANGED — only its spelling moved, from English into something with an exit code. ⛔ No hold was loosened, tightened or re-decided.
⭐ The controls are INSIDE the predicate, and that is the point
The old prose could only be run by a human who would notice a broken import. A command cannot notice anything — so the three controls run before the subject, and a failure exits 9 rather than falling through to a verdict. ⛔ A dead instrument can no longer be misread as a fire. That is the failure mode this hold was most exposed to: the probe imports a package that may be re-exported, renamed or moved by any upstream release, and 「⛔ 同仪器的控制词双零是仪器坏,不读作缺席」.
Measured before it was written — against the pinned @objectstack/spec@17.4.0
probe
reading
required
SUBJECT record-form filter
ACCEPTED
⇒ ⛔ the hold stands, exit 1
CONTROL minimal valid doc {object}
ACCEPTED
must be ACCEPTED
CONTROL unknown key on a $strict object
REFUSED
must be REFUSED
CONTROL missing required object
REFUSED
must be REFUSED
⇒ instrument lit: true, one-liner exit 1. The hold is correct today and the exit now fires by itself when it stops being.
⭐⭐ A correction this probe forced, recorded because the card's own wording invites it
The first cut of the control asserted an array-form filter would be ACCEPTED. It read REFUSED, and ⚠️a control failing is not a result — it means the question was wrong. Reading the declaration settled it: at this version ElementDataSourceSchema.filter is FilterCondition, which is { [key: string]: … } plus $and / $or / $not — record-shaped by design, with no array form at all. So the record form is not an accident the upstream tolerates; it is the declared shape today, and this card waits on a genuine upstream narrowing. ⛔ Had the control been skipped, that REFUSED would have read as evidence for the card.
⚠️ The key is now written bare at line start, ⛔ not backticked, for the same reason this board has two cards stuck behind a backticked Release:.
⛔ The state label is unchanged and remains the triage seat's to set. This edit repairs an exit; ⛔ it transitions nothing.
Filed from objectstack by the
domain:specexecution seat,session_01MkQhmuuJAVDjmeWNixwDDH, 2026-09-10T06:46Z, out of the at-ACCEPT residue of objectstack PR #17257 (#15442 / #15449) and PR #17267. ⛔ Unclaimed. Nodomain:*label and nopm:*state: ⛔ both are the triage seat's to produce.The shipped migration entry that caused this card names it as owed work, in its own words: "objectui cards filed by the seat, not blocked on here." This is that card.
What changed upstream
Seven
filterdoors in@objectstack/specconverged onz.array(ViewFilterRuleSchema)— the rule array[{ field, operator, value }, ...]— and the MongoDB-style record form and the ObjectQL AST tuple array are now refused at all seven (objectui#6206, maintainer batch adjudication 2026-08-25, verbatim 「同意」, Option B; family-wide convergence, decision batch #55, 2026-09-06, verbatim 「同意」, option A). The one that reaches this repo hardest is the binding:ElementDataSourceSchema.filter.Prescription (record → rule array, operator objects, several-keys-AND, tuple arrays, legacy shorthands) is in the objectstack semantic entries
18.element-data-source-and-object-block-filter-rule-array,18.element-number-filter-rule-array,18.element-record-picker-filter-rule-array.What this repo says today, measured at the pin
53ded82bf7a494f54e344e19099dbf00854b8694packages/core/src/data-scope/element-data-source.ts— theElementDataSourceConfigdocblock, verbatim:packages/components/src/renderers/basic/record-picker.tsx— carries spec-facingfiltercommentary at three sites (measured at the pin::93,:332,:348).dataSource.filteras a FilterCondition and says the spec rejects the array", and that wording did not reproduce on inspection; the same review also gave the path aspackages/plugin-list/src/record-picker.tsx, which is wrong. Read the three sites; do not carry the paraphrase forward.Registry declarations — objectui#7712 (closed) recorded that
plugin-kanbanandplugin-calendarregistrations declare nofilterinput at all while both renderers readschema.filter; objectui#8220 (open,pm:queue) is the live successor forplugin-map/plugin-gantt/plugin-timeline. Both are about a missing declaration; this card is about the shape a present one should declare. Whoever takes #8220 should land the array arm rather than re-declaring the old shape.The upstream entry's own acceptance text says: "the seventeen
dataSource.filtertest authors at the pin (fifteen tuple arrays, two records) become off-spec fixtures". That is the shipped claim and it is the one to start from.⛔ The objectstack seat could not reproduce it and is not asserting a rival number. What it did, so the next person does not repeat it:
git grep --multiline -P 'dataSource\s*:\s*\{[^}]{0,400}?filter\s*:'at the pin returned 0 files — a pattern failure, not a reading (a controlgit grep -l dataSourcereturns 765 files).[^}]cannot cross the nested object literals these bindings contain.dataSourcemention with afilter:within 8 lines) returned 103 hits across 62 files — and inspection of the sample shows it is measuring the wrong population: most hits are runtime$filterquery objects (sharedUserFeeds.ts,RecordAttachmentsPanel.tsx,RecordDetailView.tsx) and re-reads of somebody else'sdataSource.filter(ReportView.tsx:284), not authored binding metadata.⇒ Re-measure with a stated method and publish the method with the number. A proximity or regex probe over
.ts/.tsxwill not separate authored binding metadata from runtime query construction; the population is defined by what parses againstElementDataSourceSchema, so the reliable instrument is parsing the candidates, not grepping them.Restart condition — this is not workable today
objectui consumes
@objectstack/specas a published package ("@objectstack/spec": "^17.0.0"), and the convergence is not released yet. Measured on objectstackorigin/main501959b72:EvaluatedExpressionInputSchemaappears 0× inpackages/spec/CHANGELOG.md(lit control:EvaluatedExpressionSchemaappears 4× there) and the change sits unconsumed in.changeset/flow-edge-condition-evaluated-slot.md; specpackage.jsonreads17.4.0.Restart-when: node --input-type=module -e "const m=await import('@objectstack/spec/ui');const S=m.ElementDataSourceSchema;if(!S)process.exit(9);const r=v=>S.safeParse(v).success;if(!(r({object:'a'})&&!r({object:'a',nope:1})&&!r({filter:{}})))process.exit(9);process.exit(r({object:'a',filter:{status:'open'}})?1:0)"
⇒ run from this repo's root after
pnpm install. Exit 0 fires the hold (the record-form filter is refused); exit 1 keeps it; ⛔ exit 9 means the instrument is dead and the run says nothing — it is ⛔ never a fire. Still the install-face probe, ⛔ not "the upstream PR merged".Restart-touch:packages/core/src/data-scope/element-data-source.ts,packages/components/src/renderers/basic/record-picker.tsxpm:blockedvspm:on-hold— the cross-repo rule says an unreleased upstream ispm:on-holdwith an install-faceRestart-when:, notpm:queue) is the triage seat's to set.Dedup
Complete enumeration read 2026-09-10T06:46Z: objectui open
domain:ui= 280 (3 pages, 100 + 100 + 80 — the third page under the cap, so the enumeration is complete, not truncated). Grepped fordataSource/filter/FilterCondition/rule array/record-picker.Nearest neighbours, each read and judged not a duplicate:
filternorsortwhile all three renderers lower both onto the query — #7712's shape, but the spec cannot be cited here #8220 (open,pm:queue) — sixplugin-map/plugin-gantt/plugin-timelineregistrations declare neitherfilternorsortwhile all three renderers read them. Missing declaration, not wrong shape.element:numberand everydataSourcefilter on a record page can only be scoped to the VIEWER, never to the record #7297 (open,pm:blocked) — no record-context binding for filter values onelement:numberand everydataSourcefilter. About where a value comes from, not what shape the filter is.$-dialect, two acceptance sets:convertFiltersToASTaccepts lowercase aliases thatValueDataSourcerefuses by design #8568 (open,needs-user-decision) —convertFiltersToASTaccepts lowercase aliases thatValueDataSourcedoes not. A lowering-layer acceptance-set split, one layer below this.filterinput while both renderers readschema.filterand the spec declares it — the html tier reportsunknown-propon a spec-declared key (objectui#6678 class) #7712 (closed), finding:element:number.filterdeclares the arm'array', butElementNumberProps.filteraccepts only a record/object — the manifest gate clears a value spec refuses #6206 (closed),element:record_pickerregistryinputs.filterstill declarestype: 'object'and its parity pins assert the record form — flip both to theViewFilterRulearray arm once the spec that converged the entry reaches the pin (objectstack#14406) #7663 (closed),ObjectStackAdapter.aggregate()posts an un-loweredFilterArrayas the analyticswhere— every array-formelement:number/object-metricfilter answers 400 on the runtime route; lower throughparseFilterASTbefore the wire (moved from objectstack#15828, ruled 2026-09-05) #7752 (closed) — the prior rounds of this same convergence. Context, not duplicates.Source
objectstack #15442 · #15449 · PR #17257 · #15807 · PR #17267 · the three
18.*-filter-rule-arraysemantic entries on objectstackorigin/main501959b72Restart-when:REPAIRED — it was prose, and prose is not an exit (2026-09-19T03:02Z)Half-state patrol row H9 named this card: 「
pm:on-holdwith itsRestart-when:is prose naming no issue, no tracked path and no runnable command — amanualin disguise; nothing schedules the actor it waits on」. It was right. The condition was well-chosen and correct; it had no spelling any actor could run, and 〈可执行判据由分诊席每日一个低频子轮批量执行〉 is the actor that needs one.⭐ The condition is UNCHANGED — only its spelling moved, from English into something with an exit code. ⛔ No hold was loosened, tightened or re-decided.
⭐ The controls are INSIDE the predicate, and that is the point
The old prose could only be run by a human who would notice a broken import. A command cannot notice anything — so the three controls run before the subject, and a failure exits 9 rather than falling through to a verdict. ⛔ A dead instrument can no longer be misread as a fire. That is the failure mode this hold was most exposed to: the probe imports a package that may be re-exported, renamed or moved by any upstream release, and 「⛔ 同仪器的控制词双零是仪器坏,不读作缺席」.
Measured before it was written — against the pinned
@objectstack/spec@17.4.0filter{object}$strictobjectobject⇒
instrument lit: true, one-liner exit 1. The hold is correct today and the exit now fires by itself when it stops being.⭐⭐ A correction this probe forced, recorded because the card's own wording invites it
The first cut of the control asserted an array-form filter would be ACCEPTED. It read REFUSED, and⚠️ a control failing is not a result — it means the question was wrong. Reading the declaration settled it: at this version
ElementDataSourceSchema.filterisFilterCondition, which is{ [key: string]: … }plus$and/$or/$not— record-shaped by design, with no array form at all. So the record form is not an accident the upstream tolerates; it is the declared shape today, and this card waits on a genuine upstream narrowing. ⛔ Had the control been skipped, that REFUSED would have read as evidence for the card.Release:.⛔ The state label is unchanged and remains the triage seat's to set. This edit repairs an exit; ⛔ it transitions nothing.
Generated by Claude Code