Skip to content

Add KD-56 and KD-57, and throw on Chroma Cloud for the filters on the documents that give the wrong records there - #127

Merged
Laurianti merged 7 commits into
mainfrom
kd-regex-empty-text
Oct 12, 2026
Merged

Laurianti merged 7 commits into
mainfrom
kd-regex-empty-text

Conversation

@Laurianti

@Laurianti Laurianti commented Oct 12, 2026 •

Copy link
Copy Markdown
Member

On Chroma Cloud two filters on the documents give the wrong records: a $regex whose pattern takes an empty text finds every record, and, once Chroma Cloud has indexed the records, a $contains of fewer than 3 characters finds none. This adds KD-56 and KD-57, and makes the client throw for such filters on Chroma Cloud rather than give or delete the wrong records.

  • Measured on 12 October 2026.

    • $regex on a collection of three records: one without a document, one with the document "" and one with "x".

      Filter Chroma Cloud Chroma 1.5.9
      $regex "^x$" "x" "x"
      $regex "^$" all three ""
      $regex "^" all three "", "x"
      $regex "^.*$" all three "", "x"
      $not_regex "^$" none no document, "x"

      On Chroma Cloud the same with this client, with the Python client 1.5.9 and in plain HTTP, and the same in the Search API. A delete by filters with $regex "^$" deleted all three records.

    • Every element of the syntax of the Rust crate regex, the one of Chroma, as $regex and $not_regex, in plain HTTP on 2,100 records: of 252 filters, Chroma Cloud gives the wrong records for exactly those whose pattern has a match of minimum length 0, as Chroma computes it with its parser regex-syntax. Chroma 1.5.9 gives the right records for all.

    • $contains and $not_contains with texts of 0 to 4 characters, in plain HTTP on 2,100 records and with the Python client 1.5.9 on 2,080. Before Chroma Cloud has indexed the records all are right. Once it has indexed them, with fewer than 3 characters $contains finds no record and $not_contains every record, also those without a document. The characters are the Unicode code points: αβ and 😀 are wrong, abc, αβγ and o w right. The Python client rejects an empty text.

  • Before: the client sent such filters as they are. On Chroma Cloud a get, a query or a search gave the wrong records, and a delete deleted them: every record with $regex "^$" or $not_contains "ab".

  • Now: on Chroma Cloud, before any request, a filter on the documents throws an ArgumentException:

    • a $regex or $not_regex whose pattern takes an empty text, or that the client cannot read. The client reads a pattern as Chroma does, with the syntax of regex 1.12 as regex-syntax 0.8 reads it: classes with ranges, nested and POSIX classes like [[:alpha:]], word boundaries like \b{start-half}, groups, flags with the verbose mode (?x), and counts. A pattern it cannot read is one that Chroma rejects.
    • a $contains or $not_contains whose text has fewer than 3 characters.

    This holds in GetAsync, QueryAsync, both DeleteAsync and SearchAsync, also inside $and, $or and Not. The message names the filter and what is right instead: Regex("(?s).") for the records with a document that is not empty, NotRegex("(?s).") for the others, and for a short text Regex or NotRegex with it as the pattern, like Regex("ab"). On a single server nothing changes, and the filter is built for the check only on Chroma Cloud: an error of the filter comes from the operation, as before.

  • Tests:

    • RegexMinimumLengthTests: 155 cases, every element of the syntax at docs.rs with the minimum length of a match, and what Chroma rejects; each agrees with regex-syntax 0.8.10. Against regex-syntax 0.8.10 itself on 505,481 generated patterns, 158,250 of which it reads with a minimum length: the client gives 0 where regex-syntax gives 0 and more than 0 elsewhere, and every pattern the client cannot read is one that regex-syntax rejects.
    • DocumentFiltersTests, on a fake server: 27 filters that give the wrong records on Chroma Cloud, or that the client cannot read, throw there in seven operations and send nothing; 19 filters go; every filter goes on a single server; the messages; a filter that the get rejects still fails its task.
    • ApiV2CompleteTests.DocumentFiltersThatChromaCloudGetsWrong: on Chroma Cloud the errors, also for deletes, which delete nothing; on Chroma Cloud and on 1.5.9 what is right instead.
    • Before the change the new tests fail on Chroma Cloud and on Chroma 1.5.9, and each of 38 mutations of the check and of the parser makes them fail. With it the whole suite passes on 1.5.9, the changed classes on Chroma Cloud, on 0.6.3, 1.0.0, 0.4.23 and on the netstandard2.0 build, the .NET Framework tests and the trimmed and NativeAOT test application.
  • Docs: KD-56 and KD-57 in docs/COMPATIBILITY.md, docs/queries-and-filters.md, and the XML comments of Contains, NotContains, Regex and NotRegex.

@Laurianti
Laurianti force-pushed the kd-regex-empty-text branch from be28bf2 to b16e9d3 Compare October 12, 2026 16:22
@Laurianti Laurianti changed the title Add KD-56: on Chroma Cloud a $regex on the documents that takes an empty text finds every record Add KD-56, and throw on Chroma Cloud for a $regex on the documents that takes an empty text, which finds every record there Oct 12, 2026
@Laurianti
Laurianti marked this pull request as ready for review October 12, 2026 17:18
@Laurianti
Laurianti requested a review from a team as a code owner October 12, 2026 17:18
Copilot AI balanced review requested due to automatic review settings October 12, 2026 17:18

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Regex evaluation timeouts currently escape as an unintended exception type instead of being handled as unverifiable patterns.

1 open finding
What changed in this PR

Adds a Chroma Cloud safeguard for KD-56 to prevent empty-matching document regexes from returning or deleting incorrect records.

Changes:

  • Validates document regexes before Cloud requests.
  • Adds unit and integration coverage.
  • Documents KD-56 and supported alternatives.
File Description
ChromaDB.Client/​ChromaCollectionClient.cs Implements regex validation across reads and deletes.
ChromaDB.Client/​ChromaWhereDocumentOperator.cs Documents Cloud behavior on regex APIs.
ChromaDB.Client.Tests/​DocumentRegexesTests.cs Tests validation across operations and servers.
ChromaDB.Client.Tests/​ApiV2CompleteTests.cs Adds server-level KD-56 coverage.
docs/​COMPATIBILITY.md Records KD-56.
docs/​queries-and-filters.md Explains restrictions and alternatives.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread ChromaDB.Client/ChromaCollectionClient.cs Outdated
… crate regex, for the minimum length of a match
…or a $contains on the documents of fewer than 3 characters, which finds no record once indexed (KD-57)
@Laurianti Laurianti changed the title Add KD-56, and throw on Chroma Cloud for a $regex on the documents that takes an empty text, which finds every record there Add KD-56 and KD-57, and throw on Chroma Cloud for the filters on the documents that give the wrong records there Oct 12, 2026
@Laurianti
Laurianti requested a balanced review from Copilot October 12, 2026 20:02

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The custom parser mirrors an external regex grammar and warrants final human validation despite extensive tests.

0 open findings

1 resolved since last review

🧠 Review effort: Balanced

@Laurianti
Laurianti merged commit c780a57 into main Oct 12, 2026
16 checks passed
@Laurianti
Laurianti deleted the kd-regex-empty-text branch October 12, 2026 20:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants