⛔ Filed bare for triage — ⛔ no priority:*, ⛔ no domain:*, ⛔ no type asserted. Routing and grading are triage's.
Found by the os-dev round implementing #19514 (PR #19750) and filed by the domain:spec seat 5 (座位贴 #19357) — devs do not POST /issues. ⛔ Not introduced by that PR: the gap is pre-existing, and that round deliberately did NOT fix it (reason below, which the seat judges correct).
The defect
A view filter rule that OMITS value on a value-taking operator parses green and then 400s at the query path.
| reading |
result |
ViewFilterRuleSchema.safeParse({ field: 'name', operator: 'icontains' }) |
ACCEPT |
parseFilterAST(['name','icontains']) |
throws INVALID_FILTER — Filter comparand at where.name.$icontains is undefined |
the same pair for contains |
identical |
⇒ it is the whole value-taking class, ⛔ not an icontains sub-case.
⚠️ Provenance, split by who measured what. The two runtime readings above are the implementing round's, reported on #19514; the seat has ⛔ NOT re-run them and does not restate them as its own. What the seat DID verify, at source on PR #19750's head 1a2a7eb588:
packages/spec/src/ui/view.zod.ts:861-862 — value: z.union([...]).optional(), i.e. .optional() unconditionally;
:855 — the key's own published docblock reads 「Filter value (optional for unary operators like is_empty, is_null)」.
⇒ the published text declares it NOT optional for every other operator, and the schema does not enforce that. That half is measured by the seat and is the ADR-0078 / ADR-0049 shape: a declaration with nothing behind it.
Why it is class (c)
The metadata is a stored view / block filter config — authored by one party, stored, re-authored by another, which is the charter's own example of (c). A rule saved without its comparand passes the protocol and fails at query time, for a different person, later.
⭐ Why #19514's round was right NOT to fix it here
⛔ This is recorded so nobody reads the omission as an oversight. #19514 closes its deltas by deriving from FILTER_TEXT_CASES — the published conformance table — rather than restating rules. But that table writes no row about ABSENCE, and isRefusedTextComparand's own docblock hands the absent-value carve-out to the caller. ⇒ refusing absence inside #19514 would have widened past the table, which is exactly the boundary that change holds everywhere else.
It also fails the bounded-in-place exemption's second condition: the form is not pinned — whether objectui's filter builder emits valueless rows is NOT MEASURED — and requiring value on every non-unary operator is a far wider accept-set narrowing, owing its own ADR-0087 entry and its own ruling.
Seam
spec:ui/ViewFilterRule.value → runtime:parseFilterAST | renderer:ObjectGrid lowering sink
⛔ What this card does NOT claim
Dedupe words
ViewFilterRule value omitted non-unary operator · filter comparand undefined parse accept · view filter rule missing value INVALID_FILTER · optional value declared not enforced
出处
#19514 的施工轮(报告见该卡)· PR #19750 · objectui#9050 裁决 C′
Generated by Claude Code
⛔ Filed bare for triage — ⛔ no
priority:*, ⛔ nodomain:*, ⛔ no type asserted. Routing and grading are triage's.Found by the
os-devround implementing #19514 (PR #19750) and filed by thedomain:specseat 5 (座位贴 #19357) — devs do notPOST /issues. ⛔ Not introduced by that PR: the gap is pre-existing, and that round deliberately did NOT fix it (reason below, which the seat judges correct).The defect
A view filter rule that OMITS
valueon a value-taking operator parses green and then 400s at the query path.ViewFilterRuleSchema.safeParse({ field: 'name', operator: 'icontains' })parseFilterAST(['name','icontains'])INVALID_FILTER—Filter comparand at where.name.$icontains is undefinedcontains⇒ it is the whole value-taking class, ⛔ not an
icontainssub-case.1a2a7eb588:packages/spec/src/ui/view.zod.ts:861-862—value: z.union([...]).optional(), i.e..optional()unconditionally;:855— the key's own published docblock reads 「Filter value (optional for unary operators likeis_empty,is_null)」.⇒ the published text declares it NOT optional for every other operator, and the schema does not enforce that. That half is measured by the seat and is the ADR-0078 / ADR-0049 shape: a declaration with nothing behind it.
Why it is class (c)
The metadata is a stored view / block filter config — authored by one party, stored, re-authored by another, which is the charter's own example of (c). A rule saved without its comparand passes the protocol and fails at query time, for a different person, later.
⭐ Why #19514's round was right NOT to fix it here
⛔ This is recorded so nobody reads the omission as an oversight. #19514 closes its deltas by deriving from
FILTER_TEXT_CASES— the published conformance table — rather than restating rules. But that table writes no row about ABSENCE, andisRefusedTextComparand's own docblock hands the absent-value carve-out to the caller. ⇒ refusing absence inside #19514 would have widened past the table, which is exactly the boundary that change holds everywhere else.It also fails the bounded-in-place exemption's second condition: the form is not pinned — whether objectui's filter builder emits valueless rows is NOT MEASURED — and requiring
valueon every non-unary operator is a far wider accept-set narrowing, owing its own ADR-0087 entry and its own ruling.Seam
spec:ui/ViewFilterRule.value→runtime:parseFilterAST|renderer:ObjectGridlowering sink⛔ What this card does NOT claim
valuerequired unless the operator is unary」. That is one candidate; it narrows a published accept set and would need its own ADR-0087 disposition and a ruling on the launch-window convention. ⛔ The seat does not grade it.ViewFilterRuleSchemaaccepts two shapes every consumer refuses, andObjectGridProps.defaultFiltersisz.unknown()so nothing gates it at all — the protocol half of objectui#9050's ruling C′ #19514 declared.FILTER_TEXT_CASESshould grow an absence row without a decision; that table is a backend conformance table and adding to it changes what every consumer must refuse.Dedupe words
ViewFilterRule value omitted non-unary operator·filter comparand undefined parse accept·view filter rule missing value INVALID_FILTER·optional value declared not enforced出处
#19514 的施工轮(报告见该卡)· PR #19750 · objectui#9050 裁决 C′
Generated by Claude Code