Skip to content

Query text: resolve the @ reference prefix and make basePath: a qualifier - #6836

Merged
rbuergi merged 4 commits into
mainfrom
fix/6828-name-query-partition
Oct 15, 2026
Merged

rbuergi merged 4 commits into
mainfrom
fix/6828-name-query-partition

Conversation

@rbuergi

@rbuergi rbuergi commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

Refs #6828 (part 1 of 3 in the issue: the count: 0 for a name search).

Root cause

name: was never the problem: it is a case-insensitive exact match on MeshNode.Name on both executors (QueryEvaluator.CompareEqual, LOWER(n.name) = @p in the Postgres generator), quoted multi-word values included. The LOCATION written into the query text was:

  1. The @ 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: [].
  2. 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, so name:"First Last" basePath:@space (with the basePath argument also passed) answered count: 0 for 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"):

  • basePath argument only → 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

QueryParser resolves location tokens before anything reads them: a LEADING @ (and @/) comes off every path:/namespace:/basePath: value, alternatives included; basePath:X is a reserved qualifier meaning namespace:X scope:descendants unless the query states its own scope:. An @ inside a value (a partition named after an address) is untouched. Both executors consume the same ParsedQuery, so there is one fix for both.

Tests

  • MeshWeaver.Hosting.Test/LocationReferencePrefixTest — the parsed Path/Scope/NamedPartitions for every shape, alternation, the negated form, an explicit scope, and the control that an inner @ is kept.
  • Memex.Portal.Shared.Test/SearchResolvesInQueryLocationsTest — through MeshOperations.Search (the MCP and agent search): 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.cs reverted to main; the tests unchanged except that QueryParser.BasePathQualifier was spelled as the literal "basePath" so they compile):

  • LocationReferencePrefixTest: total: 12, failed: 11, succeeded: 1 (the one pass is the control AnAtInsideAPathIsNotAPrefix), 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: 0 and total: 5, failed: 0; full MeshWeaver.Hosting.Test total: 1347, failed: 0, skipped: 1; Memex.Portal.Shared.Test ~Search total: 22, failed: 0.

Not in this PR

  • Part 3 of the issue (a query anchored at one namespace read against another's partition): separate root cause in MeshOperations.Search's basePath composition — separate PR.
  • Part 2 (thread transcripts out-ranking the contact in an unfiltered free-text search): a ranking-policy decision, raised with the maintainer; not changed here.

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

…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>
Copilot AI balanced review requested due to automatic review settings October 15, 2026 13:50
@rbuergi
rbuergi enabled auto-merge October 15, 2026 13:50

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.

🟡 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.

Comment thread src/MeshWeaver.Mesh.Contract/Query/QueryParser.cs
@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Test Results

    20 files   -   6      20 suites   - 6   1h 0m 11s ⏱️ +14s
12 419 tests  - 306  12 419 ✅  - 113  0 💤  - 193  0 ❌ ±0 
12 435 runs   - 306  12 435 ✅  - 113  0 💤  - 193  0 ❌ ±0 

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.

   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---)
   --- End of inner exception stack trace ---, expected: True)
   --- End of inner exception stack trace ---, isDenial: True)
 ---> (Inner Exception #1) MeshWeaver.Mesh.QueryProviderStalledException: Query provider(s) [pg] did not emit an Initial within the query fan-in's 16s bound for query 'nodeType:NodeType' (user 'system'). The merged Initial gates on EVERY provider, so this query has NO snapshot to answer with — it is reported as unavailable (retryable) rather than left hanging with no error. This is an availability failure, never a permission verdict: a consumer deciding access must fail CLOSED and say it could not establish the answer. Fix the stalled provider; never bump the consumer's timeout.<---
 ---> (Inner Exception #1) MeshWeaver.Messaging.Hub.Test.InfrastructureFaultTest+ProviderException (0x80004005): Failed to connect to 10.42.18.4:5432<---
 ---> (Inner Exception #1) System.ArgumentException: Value does not fall within the expected range.<---
 ---> (Inner Exception #1) System.InvalidOperationException: boom<---
 ---> (Inner Exception #1) System.InvalidOperationException: source B is misconfigured<---
…
Memex.Portal.Shared.Test.InstanceIdRulesMatchTheRegistryTest ‑ TheSetupHostAgreesWithTheRegistry(candidate: "d9294db0-8a36-4196-ba5f-24e1c335f417")
Memex.Portal.Shared.Test.PublishStorageFaultIsNotAConflictTest ‑ AStorageFault_IsA500_NamingTheError(fault: System.AggregateException: One or more errors occurred. (Access to the path '/data/modules/activation.d/MeshWeaver.Markdown.Export.json' is denied.)
 ---> System.UnauthorizedAccessException: Access to the path '/data/modules/activation.d/MeshWeaver.Markdown.Export.json' is denied.
   --- End of inner exception stack trace ---)
Memex.Portal.Shared.Test.PublishStorageFaultIsNotAConflictTest ‑ AStorageFault_IsA500_NamingTheError(fault: System.InvalidOperationException: landing faulted
 ---> System.UnauthorizedAccessException: Access to the path '/data/modules/activation.d/MeshWeaver.Markdown.Export.json' is denied.
   --- End of inner exception stack trace ---)
Memex.Portal.Shared.Test.SearchResolvesInQueryLocationsTest ‑ AnExactNameIsFound_WhereverTheLocationIsWritten(shape: "name:\"{0}\" basePath:@NameSearchSpace", basePath: "@NameSearchSpace")
Memex.Portal.Shared.Test.SearchResolvesInQueryLocationsTest ‑ AnExactNameIsFound_WhereverTheLocationIsWritten(shape: "name:\"{0}\" basePath:@NameSearchSpace", basePath: null)
Memex.Portal.Shared.Test.SearchResolvesInQueryLocationsTest ‑ AnExactNameIsFound_WhereverTheLocationIsWritten(shape: "name:\"{0}\"", basePath: "@NameSearchSpace")
Memex.Portal.Shared.Test.SearchResolvesInQueryLocationsTest ‑ AnExactNameIsFound_WhereverTheLocationIsWritten(shape: "namespace:@NameSearchSpace scope:descendants name:"···, basePath: null)
Memex.Portal.Shared.Test.SearchResolvesInQueryLocationsTest ‑ AnExactNameIsFound_WhereverTheLocationIsWritten(shape: "path:@/NameSearchSpace scope:descendants name:\"{0}"···, basePath: null)
Memex.Portal.Shared.Test.SessionDenialIsAnAnswerTest ‑ OnlyAVerdictReadsAsADenial(shape: "the same verdict nested, as a late denial dispatch"···, failure: System.InvalidOperationException: write failed
 ---> System.UnauthorizedAccessException: Access denied
   --- End of inner exception stack trace ---, isDenial: True)
MeshWeaver.Compiler.Pipeline.Test.SourcesWatcherStallBackoffTest ‑ The_production_classifier_recognises_a_stall_through_every_wrapping(because: "a stall as an aggregate's FIRST member", fault: System.AggregateException: One or more errors occurred. (Query provider(s) [pg] did not emit an Initial within the query fan-in's 16s bound for query 'nodeType:NodeType' (user 'system'). The merged Initial gates on EVERY provider, so this query has NO snapshot to answer with — it is reported as unavailable (retryable) rather than left hanging with no error. This is an availability failure, never a permission verdict: a consumer deciding access must fail CLOSED and say it could not establish the answer. Fix the stalled provider; never bump the consumer's timeout.)
 ---> MeshWeaver.Mesh.QueryProviderStalledException: Query provider(s) [pg] did not emit an Initial within the query fan-in's 16s bound for query 'nodeType:NodeType' (user 'system'). The merged Initial gates on EVERY provider, so this query has NO snapshot to answer with — it is reported as unavailable (retryable) rather than left hanging with no error. This is an availability failure, never a permission verdict: a consumer deciding access must fail CLOSED and say it could not establish the answer. Fix the stalled provider; never bump the consumer's timeout.
   --- End of inner exception stack trace ---, expected: True)
…

♻️ This comment has been updated with latest results.

rbuergi and others added 3 commits October 15, 2026 21:20
…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>
Copilot AI balanced review requested due to automatic review settings October 15, 2026 19:22
@meshweaver-cloud
meshweaver-cloud Bot disabled auto-merge October 15, 2026 19:22

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.

🟢 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

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