Skip to content

spec: publish the icontains text-comparand refusal (predicate + reason) beside FILTER_TEXT_CASES so every face reads one implementation — ruling D on objectui#9048 #18113

Description

@os-elon-musk

Filed by the director seat (objectstack #12708, summon #23, session_01WCEaPsmKY4UyoivKkkaUHt) executing decision batch #133 item 1 — maintainer 「决裁批 #133 同意」 to the recommended D on objectui#9048, 2026-09-14T03:29Z. Lane by landing site: packages/specdomain:spec. Priority inherited from the parent card (p2); triage may re-rank.

The ruling this card executes (verbatim from objectui#9048, batch #133 item 1)

D — lift the predicate to the contract's owner. @objectstack/spec already publishes the refusal as conformance cases (FILTER_TEXT_CASES) and already exports runtime comparand helpers from the sibling module (isAcceptedFilterComparand, normalizeFilterComparandTypes in filter-comparand-type.ts, both re-exported by packages/spec/src/data/index.ts). D exports the text-comparand refusal predicate (+ its reason text) from that same place; @object-ui/core's internal text-comparand.ts becomes a call into spec, and @object-ui/data-objectstack reads the same door. One implementation, three envelopes, and it lives with the producer of the rule.

What to build (this repo only)

Two exports, reachable from the package entry via packages/spec/src/data/index.ts (the dev chooses whether they live in filter-text-conformance.ts beside FILTER_TEXT_CASES or in a sibling module that data/index.ts re-exports — both satisfy the ruling):

  1. isRefusedTextComparand(target: unknown): booleantrue exactly for the two REJECTION rows FILTER_TEXT_CASES declares for the case-insensitive-contains operator: a non-string comparand, or the empty string.
  2. textComparandRefusalReason(field: string, operator: string, target: unknown): string — the contract's half of the message, returned without leading capital or trailing period so each face seats it in its own envelope; operator is the spelling that ARRIVED ($icontains or icontains), never a canonical substitute.

⚠️ The reason text is load-bearing, not stylistic: FILTER_TEXT_CASES rows carry mustMention, and two objectui faces already ship this exact text byte-for-byte. The reference implementation is objectui packages/core/src/utils/text-comparand.ts (on objectui origin/main @ 55f39ee9) — port its two functions' behaviour and message bytes; ⛔ do not reword. Its describeComparand helper travels with the reason function if the reason needs it.

Acceptance

  • A pin that drives every FILTER_TEXT_CASES case through isRefusedTextComparand: each REJECTION case answers true, each FILTER_TEXT_ROWS comparand answers false.
  • A pin that the reason text for '' and for a non-string comparand contains each case's mustMention tokens for BOTH arriving spellings.
  • Clause-②: yes — two new exported symbols on the published @objectstack/spec entry; changeset minor; needs:contract-review carrier at claim per the seat's protocol.
  • Acceptance note (measurement, ⛔ not a gate): this repo's own faces already refuse the same rows (@objectstack/formula / the engine answer 0 of 9 FILTER_TEXT_ROWS, per objectui#9048's dev report). Measure whether any of them is a literal copy of this predicate; if so, fold it onto the new export in the same PR (one implementation), else report the reading and leave it.

Fences

  • ⛔ No objectui change in this PR — objectui#9048 is the consumer half and is pm:blocked on this card; it unblocks when objectui's installed @objectstack/spec version exports isRefusedTextComparand (the installable-consumer criterion, ⛔ not merge).
  • ⛔ No new error code: INVALID_FILTER is the declared code and is already in the ledger.
  • content/docs/releases/** untouched.

Re-check before claiming

git fetch origin main
git grep -n -E 'export (const|function) (isRefusedTextComparand|textComparandRefusalReason)' origin/main -- packages/spec/src   # expected 0 today
git grep -n -E "export \* from './filter-text-conformance'" origin/main -- packages/spec/src/data/index.ts                   # expected 1 (entry reachability)

Refs

objectui#9048 (parent ruling, batch #133 item 1) · objectui#9152 (the objectui half already landed) · objectui#8748 / objectui#9001 (the two shipped envelopes) · packages/spec/src/data/filter-text-conformance.ts · packages/spec/src/data/filter-comparand-type.ts (sibling runtime helpers precedent)

Dedup terms: isRefusedTextComparand, textComparandRefusalReason, FILTER_TEXT_CASES export predicate, icontains empty comparand spec export, text-comparand


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions