Skip to content

objectui: FilterConditionField cannot author spec’s $icontains — the case-insensitive contains is unreachable from the filter UI #4023

Description

@os-zhuang

Migrated from objectstack-ai/objectstack#6337 under the file-at-destination ruling (objectstack-ai/objectstack#7167, maintainer 2026-08-10). Originally filed 2026-08-07T14:06:06Z. The full prior thread — including triage rulings and hold/restart conditions — remains on the source issue and MUST be read before acting on this card.


Part of #3567 (transferred to the main backlog by the triage seat — feature-level work lives in objectstack whatever repo the code lands in; see the multi-repo coordination rule "One main backlog").

Blocked-by: objectstack-ai/objectstack#5702

What is missing

packages/spec's FieldOperatorsSchema gained $icontains (case-insensitive contains, spec describe: "folds ASCII case") between 17.0.0-rc.2 and rc.5. objectui's FilterConditionField has no builder operator that can author it, so the capability is unreachable from the filter UI. The existing bidirectional parity test in packages/fields/src/widgets/__tests__/FilterConditionField.operators.test.ts ("every spec field operator is reachable from the builder", objectui#2942) went red on the rc.5 bump and was handled by objectui#3560 as an explicit, ratcheted KNOWN_UNREACHABLE entry rather than a silent exclusion.

Deliverable (lands in objectui)

  1. Add a case-insensitive contains operator to the FilterConditionField builder vocabulary; condToMongo emits { field: { $icontains: value } }.
  2. kvToCondition reads it back — without the reverse mapping a saved filter view degrades on reopen.
  3. Ten locale packs gain the label key (the t() call-site key gate, objectui#3547).
  4. Remove the $icontains entry from KNOWN_UNREACHABLE in FilterConditionField.operators.test.ts; the parity assertion then takes over, and objectui#3560's ratchet simultaneously validates that the removal was legitimate.

Why this is blocked, and it is not the reason the filing issue gave

⚠️ The originating issue states the server already accepts $icontains. Half true, and the half that is false is the blocking half. Measured against objectstack origin/main:

So the spec vocabulary accepts the token while no driver can execute it. Shipping the builder operator first would put a filter in users' hands that every backend fails — strictly worse than the capability being absent. This card returns to the queue when objectstack-ai/objectstack#5702 merges.

Open product question (default recorded, not blocking)

Should today's contains have been case-insensitive all along? If so, the better shape is to have contains emit $icontains and add an explicit containsCaseSensitive for $contains — but that changes the behaviour of stored filter views, so it needs the maintainer. Default for this card: add a new operator, leave contains semantics untouched. A dev implements the default; if the maintainer wants the flip, say so here first and this card is re-scoped (it would then move to the decision inbox).

Provenance

Measured during objectui#3560 (@objectstack/* family bump to 17.0.0-rc.5). Not a regression introduced by that bump — a capability gap it exposed. Original filing: #3567.


Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions