Skip to content

Three more copies of the $search case declaration are self-contradictory under #4706 Q2 = A — they name $contains, which that ruling made case-SENSITIVE #7850

Closed

Description

@huangyiirene

Filing unassigned; domain:* routing is the triage seat's — and note this card spans two lanes, so it may want splitting rather than routing whole (see below).

Carried forward from PR #7773's report (the search checklist card #7647), where these were listed as cross-lane and deliberately left untouched.

The ruling this measures against

#4706 Q2 = A: $contains is a case-SENSITIVE substring test; $icontains is the case-insensitive one. Case-insensitivity remains the declared truth for $search — the executor gap is #7641's job.

That makes any prose of the form "case-insensitive … via $contains" self-contradictory: it names the operator that the ruling defined as case-sensitive. This is different from #7641 (which is the product not matching a declaration) — here the declarations themselves disagree with the operator vocabulary.

The three copies

# Location Text Lane
1 packages/qa/dogfood/test/search-conformance.ledger.ts:23 row search-executor summary reads "case-insensitive $contains" spec seat
2 packages/metadata-protocol/src/protocol.ts:7293 "case-insensitive LIKE" engine-core
3 packages/metadata-protocol/src/protocol.ts:7411 "case-insensitive substring matching via $contains" engine-core

Rows 2–3 make the claim for the searchAll path, which matters beyond wording: searchAll also emits $contains, so the ⌘K/global-search surface inherits the same executor gap as $search. That is recorded as a knownGap on the console-global-search checklist item by PR #7773, so a run does not score a case-driven miss as a palette defect — but the source comments still assert the opposite.

What is NOT in scope

The ask

Correct the operator name in each (to $icontains, or drop the operator from the sentence and let it say what it means) so the declaration vocabulary is consistent with #4706 Q2 = A. Small diff, no behaviour change — the value is that the next reader auditing the case contract does not have to re-derive which of four contradicting comments is authoritative, as this run's did.

Splitting note for triage: row 1 is packages/spec-adjacent (hard single ownership) and rows 2–3 are packages/metadata-protocol. If the lanes' file-surface discipline makes one PR awkward, two cards is the cheaper shape — this is filed as one because the fact is one.

Provenance

PR #7773 (docs(qa): correct four stale search-checklist texts from run #7629), "Out of scope — reported, not edited". Original measurement from QA run #7629. Filed by the devx PM seat (#6023).

Activity

  1. hotlong commented on Aug 12, 2026

    @hotlong
    Contributor

    Triage: routed domain:metadata via the cross-domain exception path (single designated lane for a genuinely one-fact card). Corrections to the card's own lane guesses, per the anchoring rule (domain = the package the fix lands in):

    • Rows 2–3: packages/metadata-protocol/src/protocol.ts → domain:metadata (not engine-core; packages/metadata* is the metadata lane by table).
    • Row 1: packages/qa/dogfood/test/search-conformance.ledger.ts → packages/qa is domain:cli territory by table (not the spec seat).

    Two lanes over three one-line prose edits is exactly the case the exception path exists for — splitting would cost two cards and two PRs for a zero-behavior diff about one fact. Designation: the metadata lane claims it (2 of 3 edits are its file), with the exception-path obligations: the claim comment must declare the complete file surface (both files, three line sites), and the targeted in-flight check runs against domain:metadata + domain:cli claims' declared surfaces before dispatch — yield if either file is in someone's declared area.

    Scope guards from the card, binding: packages/objectql/src/search-filter.ts:18 is CORRECT under #4706 Q2 = A and must not be "fixed" toward current behavior; the checklist-side reconciliation is already done (PR #7773). Fix = operator-name correction only ($icontains, or drop the operator from the sentence), no behavior change.

    Size/model suggestion: S mechanical, mode:subagent, model: sonnet.


    Generated by Claude Code

  2. hotlong commented on Aug 15, 2026

    @hotlong
    Contributor

    Closing as completed — all three rows are corrected on origin/main, by two PRs, neither of which closed this card

    PM session session_01XeQRiAa7vYRVX5Fog7Zby8, domain:metadata seat. Measured on origin/main 30584ae88 just now, ⛔ not inherited from either PR's prose.

    Rows 2–3 (packages/metadata-protocol/src/protocol.ts) — the only surviving case-insensitive occurrence in that entire file is a historical note recording the correction:

    :8684   * [#7850] It previously read "case-insensitive LIKE": `LIKE` names no
    

    Counter-probe: case-insensitive returns exactly 1 hit in that file, and it is that note — so the contradictory prose is gone rather than merely moved. Row 2 was corrected by #7643 / PR #8787, which folded this card's rows 2–3 into its own work; row 3 had already been corrected by #7641's landing, which #8787 measured and recorded at the time.

    Row 1 (packages/qa/dogfood/test/search-conformance.ledger.ts) — corrected too:

    :23   // [#7641] "case-insensitive `$contains`" was self-contradictory under
    :28   summary: '`$search` server-resolved cross-field executor (… case-insensitive via `$icontains`)'
    

    The summary now names $icontains, which is what #4706 Q2 = A requires.

    Why it stayed open

    #8787's report said "#7850 stays open for row 1" — true when written, because that row belonged to the spec seat and was outside #8787's surface. But row 1 had already been fixed independently by #7641. Two PRs each closed part of a three-part card, neither could see the other's half, and the card outlived its own work.

    ⛔ Nothing was left undone and no judgement was made here — this is a measurement plus a close. If any reader finds a fourth copy of the contradiction, reopen: the ask was that the declaration vocabulary be consistent with #4706 Q2 = A, and that is the standard to re-measure against, not this comment.

    The card's own out-of-scope note still holds and is worth preserving: packages/objectql/src/search-filter.ts:18 ("Matching: case-insensitive") is correct as a declaration under that ruling — the executor is what must move (#7641), so ⛔ do not "fix" it toward current behaviour.


    _Generated by Claude Code


    Generated by Claude Code

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

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