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
[finding] The console filter builder mints a SCALAR value for the in / notIn operators, which the spec now refuses (objectstack#6227) #3958
Out-of-scope observation from implementing objectstack#6227 (which constrains ViewFilterRuleSchema.value by operator). Unassigned, not queued. Duplicate search: no open issue in this repo matches "filter builder operator value array".
Fact
FilterBuilder (packages/components/src/custom/filter-builder.tsx) can emit a filter row whose operator is in / notIn while its value is a scalar, by three steps that are each individually reasonable:
addCondition() (:226) seeds every new row as { operator: "equals", value: "" }.
Changing the operator dropdown calls updateCondition(condition.id, { operator: value }) (:493) — it does not reset value, so the scalar "" survives the switch to in.
renderValueInput() (:306) only renders a multi-select widget when field?.options && isMultiOperator (:324) or for lookup-like fields (:312). A plain text/number field with no static options therefore falls through to the single-value <Input>regardless of operator, so whatever the user types stays a scalar.
foldFilterGroupToSpecRules (packages/app-shell/src/views/viewFilterFold.ts:106-126) then carries value through verbatim — it normalizes the operator but never the value shape:
This shape was already broken end-to-end before objectstack#6227 — it saved cleanly and then answered 400 INVALID_FILTER when the view was rendered (objectstack#5869). What changes is when the user finds out: after objectstack#6227 the spec schema refuses it at save time, so the console will surface a validation refusal on a row its own UI led the user into building.
That is a strict improvement in timing and a regression in felt UX unless the builder stops minting the shape: the user picks a legitimate operator from the dropdown the builder offered, types a value into the input the builder rendered, and is refused.
Secondary observation — one spelling adrift
isMultiOperator is decided from a local literal (:308):
notIn is an alias in the spec vocabulary, not the canonical member — the canonical spelling is not_in, and normalizeFilterOperator folds one to the other. Any code path that hands this component a canonical not_in (for example a stored view read back) gets isMultiOperator === false and renders the single-value input for a set operator. objectstack#6227 exports VIEW_FILTER_LIST_VALUE_OPERATORS and VIEW_FILTER_PAIR_VALUE_OPERATORS from @objectstack/spec precisely so this list stops being a second local dialect.
Suggested direction (not pre-judged)
Reset / re-shape value when the operator changes between scalar-valued and list-valued families.
Render a multi-value input for in / not_in even when the field has no static options (a token/tag input), and a two-bound input for between.
Decide the operator families from the spec's exported vocabularies rather than a local literal.
Triage: pm:blocked, Blocked-by: objectstack-ai/objectstack#6227 added to the body (defect-class card, deliberately not queued yet).
Classification: concrete defect, not observation — three-step repro with named anchors (filter-builder.tsx:226/:308/:493, viewFilterFold.ts:106-126), and the notIn-vs-not_in canonical-spelling half is a live wrong-widget defect for any stored view read back in canonical form. But the card's canonical fix imports VIEW_FILTER_LIST_VALUE_OPERATORS / VIEW_FILTER_PAIR_VALUE_OPERATORS from @objectstack/spec, which do not exist on any published spec until objectstack#6227 lands.
Anchors re-verified on objectui origin/main @ 69becd2: isMultiOperator = ["in", "notIn"] local literal at filter-builder.tsx:308 (plus the operator vocabulary literals at :165/:166), and renderValueInput's fall-through to the single-value input for optionless plain fields — all live.
Activity
os-zhuang commentedon Aug 9, 2026
Triage:
pm:blocked,Blocked-by: objectstack-ai/objectstack#6227added to the body (defect-class card, deliberately not queued yet).filter-builder.tsx:226/:308/:493,viewFilterFold.ts:106-126), and thenotIn-vs-not_incanonical-spelling half is a live wrong-widget defect for any stored view read back in canonical form. But the card's canonical fix importsVIEW_FILTER_LIST_VALUE_OPERATORS/VIEW_FILTER_PAIR_VALUE_OPERATORSfrom@objectstack/spec, which do not exist on any published spec until objectstack#6227 lands.pm:dispatched(domain:spec, claimed, PR docs: teachcontentas text's expression channel, notvalue(29 occurrences, not 23) #7114 open, not merged). Dispatching this card now would force the local-literal fix the card itself argues against. When docs(core,data-objectstack): let each adapter README document its own directory #6227 merges, the unlock sweep should re-verify this card's file face at the merged ref and also mind pin lag — the exports reach this repo only after the next@objectstack/specpin covers docs(core,data-objectstack): let each adapter README document its own directory #6227's commit.origin/main@69becd2:isMultiOperator = ["in", "notIn"]local literal atfilter-builder.tsx:308(plus the operator vocabulary literals at:165/:166), andrenderValueInput's fall-through to the single-value input for optionless plain fields — all live.VALID_AST_OPERATORS现已逐字收录全部 19 个 view operator,断言即使mapOperator退化为恒等也仍绿 #3641 (operator-parity tests) are adjacent but distinct; no card covers the scalar-for-set-operator minting. Clean.domain:*label — objectui is a whole-repo seat; notarget:*from this seat (objectui board is the objectui seat's production).本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
claude commentedon Aug 14, 2026
Unlock sweep: blocker cleared.
pm:blocked→pm:queue.Declared blocker: objectstack-ai/objectstack#6227 — verified closed against the GitHub API on 2026-08-14. No other blocker is declared on this card.
Authorization: maintainer directive (this session) —「先做 23 张 blocked 解锁 10 张 on-hold 按各自自述处理」· PM session
01JaVVMrSxt7Tgi1uwEuDtH7Generated by Claude Code
yinlianghui commentedon Aug 16, 2026
Claim: 批次 8(座位
repo:objectui,sessionsession_01GTRjn8xBqp75dk7kFupVRt,batch:5)。解锁核验:Blocked-by: objectstack#6227已于 2026-08-09 关闭(spec 侧按算子约束 value 形状 + 导出VIEW_FILTER_LIST_VALUE_OPERATORS/VIEW_FILTER_PAIR_VALUE_OPERATORS已落地);本卡自身范围 closed-PR 搜索无已交付实现。Branch:
claude/issue-3958-filter-builder-set-operatorsFile surface:
packages/components/src/custom/filter-builder.tsx+ 其测试;app-shell/src/views/viewFilterFold.ts预计只读核验不改;⛔ 不碰renderers/form/form.tsx(#4085 同批在飞)、不碰packages/fields的 FilterConditionField(#3567 同批在飞,另一组件)。方向裁定(契约机械,三条全做):①operator 在标量/列表/区间家族间切换时重整
value形状(不静默携带旧标量);②in/not_in在无静态 options 的字段上渲染多值 token 输入,between渲染二元输入 —— builder 不再产出 spec 拒绝的形状;③家族判定改读 spec 导出词表,删除本地["in","notIn"]字面量(canonicalnot_in读回也必须命中多值输入,别名归一钉双向)。Generated by Claude Code
fix(components): FilterBuilder 为 in/not_in/between 渲染匹配形状的值输入 (object…
fix(components): FilterBuilder 切换 field 时把算子归到新桶内 (objectstack-ai#4768)…