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
The seven converged rule-array filter doors refuse the record form with a bare invalid_type — this package's own guidance convention is not applied at any of them #17320
Filed by the domain:spec execution seat, session_01MkQhmuuJAVDjmeWNixwDDH, 2026-09-10T06:40Z, out of the at-ACCEPT residue of #15442 / #15449 (PR #17257) and #15807 (PR #17267). ⛔ Unclaimed. No domain:* label and no pm:* state: ⛔ both are the triage seat's to produce.
Measured on origin/main501959b72.
The reading
Seven filter doors converged on z.array(ViewFilterRuleSchema) in the objectui#6206 family. On the record form an author used to write — { status: 'active' } — each one produces exactly one zod issue: invalid_type at path filter, expected array, received object. Nothing else.
The seven doors, by declaring symbol (packages/spec/src):
door
symbol
file
the binding every data-bound element carries
ElementDataSourceSchema.filter
ui/page.zod.ts
object-grid
ComponentPropsMap['object-grid'].filter
ui/component.zod.ts
object-metric
ComponentPropsMap['object-metric'].filter
ui/component.zod.ts
object-kanban
ComponentPropsMap['object-kanban'].filter
ui/component.zod.ts
object-calendar
ComponentPropsMap['object-calendar'].filter
ui/component.zod.ts
element:number
ComponentPropsMap['element:number'].filter
ui/component.zod.ts
element:record_picker
ComponentPropsMap['element:record_picker'].filter
ui/component.zod.ts
What is already there, and what is not — the narrowing that matters
⚠️A first draft of this card said the prescription "ships only in the migration ledger". That is false and is corrected here before filing. All seven .describe() strings already end with The MongoDB-style record form is refused — see migration \element-…-filter-rule-array`, and the three SemanticMigrationentries carry the full conversion table (record → rule array, operator objects →operator`, several keys AND together, legacy shorthands normalized on parse):
The gap is the runtime refusal, not the documentation. Nothing bridges .describe() into a zod issue: there is no global error map in this package (setErrorMap / z.config → 0 hits under packages/spec/src, lit control: strictObject's own error callback at shared/strict-object.tsstrictObject() is present and does exactly this bridging for the unknown-key case). So an author — or an AI agent authoring metadata, which is the population these doors exist for — reads expected array, received object and has no pointer to the entry that would tell it what to write instead.
Each of the three migration entries states the bare refusal as its own acceptance criterion, in the entry's own words: "a record-form filter: { status: 'active' } is refused at the filter path (invalid_type, expected array)". So this is not a regression against what was ruled — it is the residue the ruling did not cover.
Why this package already treats a bare invalid_type as insufficient
Three precedents in packages/spec/src, all zod-v4 { error } params, all measured on 501959b72:
shared/expression.zod.ts — EvaluatedExpressionSchema.source is z.string({ error: () => EVALUATED_EXPRESSION_SOURCE_REQUIRED }) plus a .refine(..., { message: … }), so a missing or blank source names itself instead of emitting invalid_type.
ui/view.zod.ts — flattenedViewOverlayFields()'s object and viewKind both use error: (issue) => (issue.input === undefined ? INLINE_VIEW_… : undefined), i.e. a targeted message for the one shape an author gets wrong, falling through to the default otherwise.
shared/strict-object.ts — strictObject() passes error: strictObjectError(options, shape), which names the surface, echoes the offending key and suggests the closest declared key with the candidate list read from shape.
The third one is the closest model: guidance derived from the schema rather than transcribed beside it, so it cannot drift.
Why it matters
The population at these doors is metadata authors, and the failure mode the convergence was ruled to end (objectui#6206, maintainer batch adjudication 2026-08-25, verbatim 「同意」, Option B) was two orthographies, silent success on both. The convergence replaced silence with a refusal, which is the right direction. But the refusal an author actually receives is the one sentence that does not say what the other orthography is — so the author's next action is a guess, and the second-guess (an ObjectQL AST tuple array, which the z.unknown() block doors used to take) fails at filter.0 with a second bare invalid_type.
Suggested shape for whoever takes it
One shared guidance constant per family, wired through the zod-v4 { error } param at all seven doors, naming the rule-array form and the migration entry id. ⚠️ The error callback must fall through (return undefined) for anything other than the record shape, as flattenedViewOverlayFields() does — a blanket message would swallow the filter.0 element-level issues an array author needs.
⚠️ Whoever takes it should check whether widening the message counts as clause ② (needs:contract-review): the accept set does not move, but the emitted issue text is read by the objectui parity fixtures and by packages/lint, so the blast radius is larger than the schema diff.
Dedup
Complete enumerations on origin/main-era GitHub, read 2026-09-10T06:40Z: objectstack open domain:spec = 111 (2 pages, 100 + 11), open finding = 160 (100 + 60), open domain:services = 94 (1 page). Union 295 cards grepped for filter / invalid_type / rule array / guidance / refusal.
Nearest neighbours, each read and judged not a duplicate:
Filed by the
domain:specexecution seat,session_01MkQhmuuJAVDjmeWNixwDDH, 2026-09-10T06:40Z, out of the at-ACCEPT residue of #15442 / #15449 (PR #17257) and #15807 (PR #17267). ⛔ Unclaimed. Nodomain:*label and nopm:*state: ⛔ both are the triage seat's to produce.Measured on
origin/main501959b72.The reading
Seven
filterdoors converged onz.array(ViewFilterRuleSchema)in the objectui#6206 family. On the record form an author used to write —{ status: 'active' }— each one produces exactly one zod issue:invalid_typeat pathfilter, expected array, received object. Nothing else.The seven doors, by declaring symbol (
packages/spec/src):ElementDataSourceSchema.filterui/page.zod.tsobject-gridComponentPropsMap['object-grid'].filterui/component.zod.tsobject-metricComponentPropsMap['object-metric'].filterui/component.zod.tsobject-kanbanComponentPropsMap['object-kanban'].filterui/component.zod.tsobject-calendarComponentPropsMap['object-calendar'].filterui/component.zod.tselement:numberComponentPropsMap['element:number'].filterui/component.zod.tselement:record_pickerComponentPropsMap['element:record_picker'].filterui/component.zod.tsWhat is already there, and what is not — the narrowing that matters
.describe()strings already end withThe MongoDB-style record form is refused — see migration \element-…-filter-rule-array`, and the threeSemanticMigrationentries carry the full conversion table (record → rule array, operator objects →operator`, several keys AND together, legacy shorthands normalized on parse):migrations/entries/semantic/18.element-data-source-and-object-block-filter-rule-array.tsmigrations/entries/semantic/18.element-number-filter-rule-array.tsmigrations/entries/semantic/18.element-record-picker-filter-rule-array.tsThe gap is the runtime refusal, not the documentation. Nothing bridges
.describe()into a zod issue: there is no global error map in this package (setErrorMap/z.config→ 0 hits underpackages/spec/src, lit control:strictObject's ownerrorcallback atshared/strict-object.tsstrictObject()is present and does exactly this bridging for the unknown-key case). So an author — or an AI agent authoring metadata, which is the population these doors exist for — readsexpected array, received objectand has no pointer to the entry that would tell it what to write instead.Each of the three migration entries states the bare refusal as its own acceptance criterion, in the entry's own words: "a record-form
filter: { status: 'active' }is refused at thefilterpath (invalid_type, expected array)". So this is not a regression against what was ruled — it is the residue the ruling did not cover.Why this package already treats a bare
invalid_typeas insufficientThree precedents in
packages/spec/src, all zod-v4{ error }params, all measured on501959b72:shared/expression.zod.ts—EvaluatedExpressionSchema.sourceisz.string({ error: () => EVALUATED_EXPRESSION_SOURCE_REQUIRED })plus a.refine(..., { message: … }), so a missing or blank source names itself instead of emittinginvalid_type.ui/view.zod.ts—flattenedViewOverlayFields()'sobjectandviewKindboth useerror: (issue) => (issue.input === undefined ? INLINE_VIEW_… : undefined), i.e. a targeted message for the one shape an author gets wrong, falling through to the default otherwise.shared/strict-object.ts—strictObject()passeserror: strictObjectError(options, shape), which names the surface, echoes the offending key and suggests the closest declared key with the candidate list read fromshape.The third one is the closest model: guidance derived from the schema rather than transcribed beside it, so it cannot drift.
Why it matters
The population at these doors is metadata authors, and the failure mode the convergence was ruled to end (objectui#6206, maintainer batch adjudication 2026-08-25, verbatim 「同意」, Option B) was two orthographies, silent success on both. The convergence replaced silence with a refusal, which is the right direction. But the refusal an author actually receives is the one sentence that does not say what the other orthography is — so the author's next action is a guess, and the second-guess (an ObjectQL AST tuple array, which the
z.unknown()block doors used to take) fails atfilter.0with a second bareinvalid_type.Suggested shape for whoever takes it
One shared guidance constant per family, wired through the zod-v4⚠️ The
{ error }param at all seven doors, naming the rule-array form and the migration entry id.errorcallback must fall through (return undefined) for anything other than the record shape, asflattenedViewOverlayFields()does — a blanket message would swallow thefilter.0element-level issues an array author needs.needs:contract-review): the accept set does not move, but the emitted issue text is read by the objectui parity fixtures and bypackages/lint, so the blast radius is larger than the schema diff.Dedup
Complete enumerations on
origin/main-era GitHub, read 2026-09-10T06:40Z: objectstack opendomain:spec= 111 (2 pages, 100 + 11), openfinding= 160 (100 + 60), opendomain:services= 94 (1 page). Union 295 cards grepped forfilter/invalid_type/rule array/guidance/refusal.Nearest neighbours, each read and judged not a duplicate:
protectionblock's unknown-key refusal carries zod's bare message — no surface, no declared keys, no rename, on four authorable types #16845 —ProtectionSchema's unknown-key refusal carries zod's bare message, on four authorable types. Same campaign, different zod issue code: Theprotectionblock's unknown-key refusal carries zod's bare message — no surface, no declared keys, no rename, on four authorable types #16845 isunrecognized_keysand its fix is adopting thestrictObjecthelper; this card isinvalid_typeat a converged type door, whichstrictObjectdoes not reach.object/filterdata-binding family —dataSourceas the single data-binding door (re-anchor of the deleted #6590 tracker) #11509 (pm:on-hold,target:v18) — retire the flatobject/filterbinding family in favour ofdataSource. That is whether the doors should exist; this is what they say when they refuse.widget.filter(dashboard.zod.ts:387,:720) still declaresFilterConditionSchema— a further location under ui#6206-B outsideComponentPropsMap, and the console's DashboardWidgetInspector authors exactly that record form #15829 — the dashboardwidget.filteris stillFilterConditionSchemaand was explicitly excluded from this convergence by theelement-data-source-and-object-block-filter-rule-arrayentry's own text. It is the eighth door, not yet converged; if it converges it inherits this card.convertFiltersToASTvsValueDataSourceacceptance sets, open) — different layers.Source
PR #17257 (#15442 anchor, #15449 member) · PR #17267 (#15807) · the three
18.*-filter-rule-arraysemantic entries onorigin/mainGenerated by Claude Code