Skip to content

Query: slashes in key:value are literal (nodeType:Edu/Exercise) — regression tests + investigation - #568

Merged
rbuergi merged 1 commit into
mainfrom
fix/query-parser-slash-in-values
Jul 20, 2026
Merged

rbuergi merged 1 commit into
mainfrom
fix/query-parser-slash-in-values

Conversation

@rbuergi

@rbuergi rbuergi commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Follow-up on the memex-cloud report (2026-07-19) that a structured query whose value contains a slash matched nothing:

  • nodeType:Edu/Exercise → 0 results, though the nodes exist
  • nodeType:Store/Plugin → 0, though the node exists

The stated hypothesis was that the query tokenizer drops/mis-splits the value at the slash.

What the investigation found

The tokenizer and the full Postgres query pipeline already treat a slash inside a key:value value as a literal that runs to the next whitespace. I could not reproduce a slash-drop anywhere in current main:

  • Parser (QueryParser.Tokenize → ParseSingleValue): a value reads to the next whitespace; / is an ordinary value char (and a valid field char). Pre-existing tests already cover this (Parse_PathValueWithSlash_ParsesCorrectly for nodeType:ACME/Project/Todo, Parse_ActivityQueryPattern for type/Story). This behaviour has been in place since AI models show their provider's brand logo in the model picker #407 (2026-07-10), i.e. before the 2026-07-19 observation.
  • SQL generation (PostgreSqlSqlGenerator): nodeType:Edu/Exercise → LOWER(n.node_type) = @p0, param edu/exercise — parameterized, slash intact.
  • Table routing (ResolveTableByNodeType, ResolvePinnedPartition, routing hints): a slashed value is not a known satellite type and has no namespace, so it resolves to mesh_nodes and fans out across every searchable partition — no mis-pin.
  • Live check: nodeType:Store/Plugin and nodeType:Edu/Exercise both return rows on the live memex mesh right now.

So the parser test the report expected to go RED actually goes GREEN — there is no tokenizer defect to fix. Fabricating a code change to a working parser would be a fake fix, so this PR ships regression coverage only and documents the finding.

The memex-cloud symptom was therefore almost certainly not a tokenizer bug — most likely environmental (an older deployed image, or the partition holding those nodes not yet present in searchable_schemas at query time). That is a separate, non-slash-specific issue (a non-slashed nodeType in the same partition would fail the same way) and is out of scope here.

Tests added (all green; Release + -warnaserror clean)

  • QueryParserTests.Parse_SlashedNodeTypeValue — Edu/Exercise, Store/Plugin, Store/Catalog keep the whole value; no stray free-text token.
  • QuerySyntaxTests — scoped (path:… scope:descendants) and unscoped single-partition nodeType:Edu/Exercise / nodeType:Store/Plugin return the seeded rows.
  • CrossPartitionSearchTests — the production cross-schema fan-out (PostgreSqlStorageAdapter.QueryNodesAcrossSchemasAsync and the full PostgreSqlPartitionedMeshQuery orchestrator) returns slashed-type nodes across every partition.

No production code changed — the PR is orthogonal to #562 (per-subject permission fold); it merged cleanly with current main.

🤖 Generated with Claude Code

Regression coverage for the memex-cloud 2026-07-19 report that
`nodeType:Edu/Exercise` / `nodeType:Store/Plugin` matched nothing.

Investigation found the query tokenizer and the full Postgres query
pipeline ALREADY treat a slash inside a key:value value as a literal
that runs to the next whitespace — verified end-to-end AND against the
live memex mesh (both slashed searches return rows). No production code
change was needed; these tests pin the contract so it can't regress.

- QueryParserTests.Parse_SlashedNodeTypeValue: Edu/Exercise, Store/Plugin,
  Store/Catalog keep the whole value, no stray free-text token.
- QuerySyntaxTests: scoped + unscoped single-partition nodeType queries
  with slashed types return the seeded rows.
- CrossPartitionSearchTests: the production cross-schema fan-out
  (adapter + PostgreSqlPartitionedMeshQuery) returns slashed-type nodes
  across every partition.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 20, 2026 00:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds regression coverage to confirm that structured query values containing slashes (e.g., nodeType:Edu/Exercise, nodeType:Store/Plugin) are parsed and executed literally (i.e., the slash is not treated as a delimiter), including cross-partition fan-out behavior in PostgreSQL.

Changes:

  • Added QueryParser regression tests to ensure slashed nodeType values remain intact and don’t leak into free-text search.
  • Added PostgreSQL query syntax tests validating nodeType:Edu/Exercise and nodeType:Store/Plugin filters return seeded rows (scoped and unscoped).
  • Added cross-schema fan-out tests validating slashed nodeType filters return results across partitions via both the low-level cross-schema query and the production orchestrator.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
test/MeshWeaver.Query.Test/QueryParserTests.cs Adds parser-level regression coverage for slashed nodeType values and ensures no TextSearch token is produced.
test/MeshWeaver.Hosting.PostgreSql.Test/QuerySyntaxTests.cs Seeds slashed nodeType nodes and asserts PostgreSQL query execution returns expected rows (scoped + unscoped).
test/MeshWeaver.Hosting.PostgreSql.Test/CrossPartitionSearchTests.cs Validates slashed nodeType queries work with production-style cross-schema fan-out across multiple partitions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 3)

   12 files  ±0     12 suites  ±0   4m 20s ⏱️ +7s
  951 tests ±0    947 ✅ ±0  4 💤 ±0  0 ❌ ±0 
1 009 runs  ±0  1 005 ✅ ±0  4 💤 ±0  0 ❌ ±0 

Results for commit 7ecc366. ± Comparison against base commit eb98324.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 0)

926 tests  ±0   920 ✅ ±0   4m 41s ⏱️ -6s
  5 suites ±0     6 💤 ±0 
  5 files   ±0     0 ❌ ±0 

Results for commit 7ecc366. ± Comparison against base commit eb98324.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 4)

1 876 tests  +4   1 688 ✅ +4   5m 21s ⏱️ +9s
   12 suites ±0     188 💤 ±0 
   12 files   ±0       0 ❌ ±0 

Results for commit 7ecc366. ± Comparison against base commit eb98324.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 2)

1 104 tests  ±0   1 001 ✅ ±0   5m 23s ⏱️ +12s
   10 suites ±0     103 💤 ±0 
   10 files   ±0       0 ❌ ±0 

Results for commit 7ecc366. ± Comparison against base commit eb98324.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 1)

1 122 tests  +3   1 121 ✅ +3   5m 31s ⏱️ -12s
   10 suites ±0       1 💤 ±0 
   10 files   ±0       0 ❌ ±0 

Results for commit 7ecc366. ± Comparison against base commit eb98324.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 5)

1 059 tests  ±0   1 058 ✅ ±0   5m 41s ⏱️ +4s
   12 suites ±0       1 💤 ±0 
   12 files   ±0       0 ❌ ±0 

Results for commit 7ecc366. ± Comparison against base commit eb98324.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results

   61 files  ±0     61 suites  ±0   31m 1s ⏱️ +16s
7 038 tests +7  6 735 ✅ +7  303 💤 ±0  0 ❌ ±0 
7 096 runs  +7  6 793 ✅ +7  303 💤 ±0  0 ❌ ±0 

Results for commit 7ecc366. ± Comparison against base commit eb98324.

@rbuergi
rbuergi merged commit 10063a2 into main Jul 20, 2026
16 checks passed
@rbuergi
rbuergi deleted the fix/query-parser-slash-in-values branch August 5, 2026 10:45
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.

2 participants