Repository navigation
Query text: resolve the @ reference prefix and make basePath: a qualifier - #6836
Conversation
…fier (#6828) A name search answered count: 0 for nodes that exist because the location written into the query text was not resolved: namespace:@x / path:@x kept the @ and anchored at a partition literally called "@x", and basePath: (the word the tools advertise) became a filter on a property no node has. The parser now strips a leading @ / @/ from every path:/namespace:/basePath: value and reads basePath:X as namespace:X scope:descendants. Both executors consume the same ParsedQuery. Refs #6828 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
Singleton-list and wildcard basePath: forms still omit deeper matches by losing the implicit descendant scope.
1 open finding
What changed in this PR
Addresses the location-parsing portion of #6828 by normalizing query references in the shared parser used by both search executors.
Changes:
- Strips leading
@prefixes from location values. - Adds
basePath:as a descendant-search qualifier. - Adds parser and search regression tests, plus syntax documentation.
| File | Description |
|---|---|
| test/MeshWeaver.Hosting.Test/LocationReferencePrefixTest.cs | Tests location normalization and qualifier parsing. |
| test/Memex.Portal.Shared.Test/SearchResolvesInQueryLocationsTest.cs | Tests exact-name searches across location forms. |
| src/MeshWeaver.Mesh.Contract/Query/QueryParser.cs | Normalizes references and recognizes basePath:. |
| src/MeshWeaver.Documentation/Data/DataMesh/QuerySyntax.md | Documents location syntax and name matching. |
| src/MeshWeaver.Documentation/Data/Architecture/DataAccessPatterns.md | Adds the basePath: qualifier reference. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Test Results 20 files - 6 20 suites - 6 1h 0m 11s ⏱️ +14s Results for commit d16e994. ± Comparison against base commit cab0ae9. This pull request removes 369 and adds 37 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
…he descendants (#6828) Review of #6836: a one-value list basePath:(@acme) defaulted to Children and a wildcard basePath:@acme/*/Contacts stayed Exact, both missing deeper matches their documented namespace:... scope:descendants equivalents include. Every positive single-location form now takes the implicit descendant scope, a wildcard included (it sets no concrete anchor, and is widened to the subtree); an explicit scope: is kept. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🟢 Approval recommended
The localized parser changes match the documented behavior, and regression coverage addresses the previously identified singleton-list and wildcard cases.
0 open findings
1 resolved since last review
🧠 Review effort: Balanced

Refs #6828 (part 1 of 3 in the issue: the
count: 0for a name search).Root cause
name:was never the problem: it is a case-insensitive exact match onMeshNode.Nameon both executors (QueryEvaluator.CompareEqual,LOWER(n.name) = @pin the Postgres generator), quoted multi-word values included. The LOCATION written into the query text was:@reference prefix was kept. Tool arguments strip it (MeshOperations.ResolvePath), the parser did not.namespace:@acme …/path:@acme …anchored at a partition literally called@acme: zero rows, no error,coverage.partitions: [].basePath:was not a qualifier. The tools advertise the word, so an agent writes it into the query; the parser turned it into a FILTER on a property no node has, soname:"First Last" basePath:@space(with the basePath argument also passed) answeredcount: 0for nodes that exist.Measured on a live portal before the fix, one credential, seconds apart, on a node in my own home (
name:"Update Probe"):count: 1… namespace:@<home>→count: 0, partitions: []… path:@<home> scope:descendants→count: 0, partitions: []… basePath:@<home>plus the basePath argument →count: 0, partitions: ["<home>"]Fix
QueryParserresolves location tokens before anything reads them: a LEADING@(and@/) comes off everypath:/namespace:/basePath:value, alternatives included;basePath:Xis a reserved qualifier meaningnamespace:X scope:descendantsunless the query states its ownscope:. An@inside a value (a partition named after an address) is untouched. Both executors consume the sameParsedQuery, so there is one fix for both.Tests
MeshWeaver.Hosting.Test/LocationReferencePrefixTest— the parsedPath/Scope/NamedPartitionsfor every shape, alternation, the negated form, an explicit scope, and the control that an inner@is kept.Memex.Portal.Shared.Test/SearchResolvesInQueryLocationsTest— throughMeshOperations.Search(the MCP and agentsearch): an exact multi-word name two levels below the space is found for every way of writing the location, case-insensitively, with coverage naming the space; control per shape: a name nobody has answers 0.Negative control (
QueryParser.csreverted to main; the tests unchanged except thatQueryParser.BasePathQualifierwas spelled as the literal"basePath"so they compile):LocationReferencePrefixTest:total: 12, failed: 11, succeeded: 1(the one pass is the controlAnAtInsideAPathIsNotAPrefix), e.g.failed …TheReferencePrefixComesOffAnInQueryAnchor(query: "namespace:@acme name:\"Jane Doe\"", …),failed …BasePathIsTheDescendantsOfItsPath_NotAFilter(…).SearchResolvesInQueryLocationsTest:total: 5, failed: 4, succeeded: 1(the one pass is the baseline: the basePath argument alone), e.g.failed …AnExactNameIsFound_WhereverTheLocationIsWritten(shape: "name:\"{0}\" basePath:@NameSearchSpace", basePath: "@NameSearchSpace").Fix restored:
total: 12, failed: 0andtotal: 5, failed: 0; fullMeshWeaver.Hosting.Testtotal: 1347, failed: 0, skipped: 1;Memex.Portal.Shared.Test~Searchtotal: 22, failed: 0.Not in this PR
MeshOperations.Search's basePath composition — separate PR.Recycle on deploy: none (parser change; no per-node hub state).
Pairs-with: none — adds a public const and private members; removes nothing.
🤖 Generated with Claude Code