Skip to content

FuzzyScorer joins its own assembly's namespace — and three phantom AI imports go with it - #2349

Merged
rbuergi merged 6 commits into
mainfrom
fix/2344-fuzzyscorer-namespace
Aug 26, 2026
Merged

rbuergi merged 6 commits into
mainfrom
fix/2344-fuzzyscorer-namespace

Conversation

@rbuergi

@rbuergi rbuergi commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Closes #2344.

The mismatch

src/MeshWeaver.Data/Completion/FuzzyScorer.cs declared namespace MeshWeaver.AI.Completion while shipping in MeshWeaver.Data — the only file in its own directory to do so:

file namespace
AutocompletePrefixRegistry.cs MeshWeaver.Data.Completion
DataAutocompleteProvider.cs MeshWeaver.Data.Completion
FuzzyScorer.cs MeshWeaver.AI.Completion

🚨 It was not cosmetic — it manufactured three phantom dependencies

Declaring a type in MeshWeaver.AI.Completion from MeshWeaver.Data makes the parent namespace MeshWeaver.AI exist in the compilation of every project referencing MeshWeaver.Data — with or without the AI assembly anywhere in sight.

Three core files were importing precisely that:

file project references MeshWeaver.AI?
src/MeshWeaver.GitSync/GitHubCredentialService.cs no
src/MeshWeaver.PluginCatalog/InstanceAutoRegistrationService.cs no
src/MeshWeaver.PluginCatalog/SyncTokenSigningKeyService.cs no

Each carried using MeshWeaver.AI; resolving to an empty namespace. They import nothing. They only ever compiled as a side effect of the misplaced namespace, and all three broke the moment it was fixed — which is how they were found, not by inspection.

The cost is the one #2276 cannot afford: git grep MeshWeaver.AI src/ reported hits in two core projects with no dependency on AI at all. An audit of "has AI left core?" would chase them, or conclude the extraction was incomplete when it was not.

Consumers updated

  • StaticNodeQueryProvider — a fully-qualified new MeshWeaver.AI.Completion.FuzzyScorer() inside core hosting, plus its cref
  • QueryEvaluator, ContentAutocompleteProvider, AutocompleteMultiSourceTest
  • SpacesInFileNameTest — already imported MeshWeaver.Data.Completion, so its AI import simply went

MeshWeaver.AI.Completion still exists for the three types that genuinely belong to it (AutocompleteClient, AutocompleteStreamProvider, SkillAutocompleteProvider).

Result

The only MeshWeaver.AI left in core is prose comments plus one deliberate by-name entry in Plugin.Build/CompilationEnvironment.cs — the in-mesh compile reference set, which needs the name.

Verification

  • ContentCollections, PluginCatalog, Autocomplete.Test, AI.Test all build -c Release -p:CIRun=true -warnaserror → 0 Warning(s), 0 Error(s)
  • FuzzyScorer-exercising tests green: 7 + 24

No What's New entry — internal refactor, no user-visible effect.

Refs #2276

🤖 Generated with Claude Code

… phantom AI imports go

src/MeshWeaver.Data/Completion/FuzzyScorer.cs declared `namespace MeshWeaver.AI.Completion`
while shipping in MeshWeaver.Data — the only file in its own directory to do so; its two
neighbours are MeshWeaver.Data.Completion. Renamed to match the assembly it is in.

That mismatch was not cosmetic. Declaring a type in MeshWeaver.AI.Completion from
MeshWeaver.Data makes the PARENT namespace MeshWeaver.AI *exist* in the compilation of
every project that references MeshWeaver.Data — with or without the AI assembly anywhere
in sight. Three core files were importing exactly that:

    src/MeshWeaver.GitSync/GitHubCredentialService.cs
    src/MeshWeaver.PluginCatalog/InstanceAutoRegistrationService.cs
    src/MeshWeaver.PluginCatalog/SyncTokenSigningKeyService.cs

Each carried `using MeshWeaver.AI;` resolving to an empty-but-existing namespace, and
NEITHER project has a ProjectReference to MeshWeaver.AI. They import nothing; they only
ever compiled as a side effect of the misplaced namespace, and all three broke the moment
it was fixed — which is how they were found.

The cost is exactly the one #2276 cannot afford: `git grep MeshWeaver.AI src/` reported
hits in two core projects with no dependency on AI at all. An audit of "has AI left core?"
would either chase them or conclude the extraction was incomplete when it was not.

Consumers updated: StaticNodeQueryProvider (a fully-qualified `new
MeshWeaver.AI.Completion.FuzzyScorer()` inside core hosting, plus its cref), QueryEvaluator,
ContentAutocompleteProvider, AutocompleteMultiSourceTest, and SpacesInFileNameTest — which
already imported MeshWeaver.Data.Completion, so its AI import simply went.

MeshWeaver.AI.Completion still exists for the three types that genuinely belong to it
(AutocompleteClient, AutocompleteStreamProvider, SkillAutocompleteProvider).

After this, the only MeshWeaver.AI left in core is prose comments plus one deliberate
by-name entry in Plugin.Build/CompilationEnvironment.cs — the in-mesh compile reference
set, which needs the name.

Verified: MeshWeaver.ContentCollections, MeshWeaver.PluginCatalog, MeshWeaver.Autocomplete.Test
and MeshWeaver.AI.Test all build -c Release -warnaserror at 0 Warning(s)/0 Error(s), and the
FuzzyScorer-exercising tests pass (7 + 24).

No What's New entry: internal refactor, no user-visible effect.

Closes #2344

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 26, 2026 09:36

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

This PR fixes a namespace/assembly mismatch by moving FuzzyScorer into the MeshWeaver.Data.Completion namespace (matching its project), and updates consumers accordingly. This removes accidental “phantom” MeshWeaver.AI references in core projects that do not actually depend on the AI assembly, supporting the broader effort to keep AI concerns out of core (#2276).

Changes:

  • Rename FuzzyScorer’s namespace from MeshWeaver.AI.Completion to MeshWeaver.Data.Completion.
  • Update core/query/autocomplete consumers to reference the corrected namespace (including XML cref and fully-qualified construction).
  • Remove now-invalid/unused using MeshWeaver.AI; imports from non-AI core projects.

Reviewed changes

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

Show a summary per file
File Description
src/MeshWeaver.Data/Completion/FuzzyScorer.cs Moves FuzzyScorer into MeshWeaver.Data.Completion to match the assembly/project.
src/MeshWeaver.Hosting/Persistence/Query/QueryEvaluator.cs Switches using to the corrected MeshWeaver.Data.Completion namespace.
src/MeshWeaver.Hosting/Persistence/Query/StaticNodeQueryProvider.cs Updates cref and fully-qualified instantiation to MeshWeaver.Data.Completion.FuzzyScorer.
src/MeshWeaver.ContentCollections/Completion/ContentAutocompleteProvider.cs Removes AI completion import; relies on MeshWeaver.Data.Completion for scoring.
src/MeshWeaver.GitSync/GitHubCredentialService.cs Removes phantom using MeshWeaver.AI; from a non-AI project.
src/MeshWeaver.PluginCatalog/InstanceAutoRegistrationService.cs Removes phantom using MeshWeaver.AI; from a non-AI project.
src/MeshWeaver.PluginCatalog/SyncTokenSigningKeyService.cs Removes phantom using MeshWeaver.AI; from a non-AI project.
test/MeshWeaver.Autocomplete.Test/AutocompleteMultiSourceTest.cs Updates test to construct the scorer from Data.Completion.
test/MeshWeaver.AI.Test/SpacesInFileNameTest.cs Removes now-invalid using MeshWeaver.AI.Completion; while keeping data completion usage.

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

@github-actions

github-actions Bot commented Aug 26, 2026 •

Copy link
Copy Markdown
Contributor

Test Results

    53 files      53 suites   1h 1m 55s ⏱️
11 245 tests 10 940 ✅ 305 💤 0 ❌
11 813 runs  11 508 ✅ 305 💤 0 ❌

Results for commit 77a996d.

♻️ This comment has been updated with latest results.

…ne too

The first pass swept src/ only, found three phantom `using MeshWeaver.AI;` and declared
core clean. It was not: test/MeshWeaver.Graph.Test/SatelliteContentAndMenuStateTest.cs
carried the same dead import, resolving to the same empty namespace MeshWeaver.Data was
contributing to. CI's solution build caught it; the per-project builds could not, because
none of them compiled that project.

Rerunning the scan across BOTH trees reported fourteen — and acting on that would have
broken four test projects. The check only looked at DIRECT ProjectReference, while
NodeOperations.Test, Hosting.Monolith.Test, Security.Test and Acme.Test all reach
MeshWeaver.AI TRANSITIVELY, so their usings import real types. Computing the transitive
closure cuts fourteen to exactly one — Graph.Test — which is precisely what CI failed on.

So the same too-narrow predicate produced both errors: first missing a tree, then
over-claiming within it.

Also re-verified the two src/ projects already changed against the transitive standard:
MeshWeaver.PluginCatalog and MeshWeaver.GitSync genuinely cannot reach MeshWeaver.AI, so
those removals were correct.

Verified with a full solution build this time, not per-project ones — a namespace change
has repo-wide blast radius, and per-project builds are exactly what let this through:
MW_ALLOW_SOLUTION_BUILD=1 dotnet build MeshWeaver.slnx -c Release -p:CIRun=true -warnaserror
→ 0 Warning(s), 0 Error(s). Confirmed it was a real compile rather than an up-to-date
no-op: MeshWeaver.Graph.Test.dll (11:54:33) is newer than the edited source (11:54:15).

Refs #2344

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@rbuergi

rbuergi commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

Fixed — my sweep was incomplete, and the correction is worth recording

CI was right and I was wrong twice, in the same direction.

Miss 1 — wrong scope. I swept src/ for phantom using MeshWeaver.AI;, found three, and declared core clean without sweeping test/. test/MeshWeaver.Graph.Test/SatelliteContentAndMenuStateTest.cs carried the same dead import. My per-project builds could not catch it because none of them compiled that project; the solution build did.

Miss 2 — wrong predicate. Rerunning across both trees reported 14 phantoms. Acting on that would have broken four test projects:

project direct AI reference reaches AI transitively
NodeOperations.Test no yes
Hosting.Monolith.Test no yes
Security.Test no yes
Acme.Test no yes
Graph.Test no no ← the only real phantom

The check only looked at direct ProjectReference. Those four reach MeshWeaver.AI transitively, so their usings import real types. Computing the transitive closure cuts 14 to exactly 1 — which matches what CI actually failed on.

Same too-narrow predicate behind both: first it missed a tree, then it over-claimed within it.

I also re-checked the two src/ projects I had already changed against the transitive standard — PluginCatalog and GitSync genuinely cannot reach MeshWeaver.AI, so those removals were correct.

Verification, tightened

Per-project builds are what let this through, so this time:

MW_ALLOW_SOLUTION_BUILD=1 dotnet build MeshWeaver.slnx -c Release -p:CIRun=true -warnaserror
EXIT=0 · 0 Warning(s) · 0 Error(s)

And confirmed it was a real compile rather than an up-to-date no-op — MeshWeaver.Graph.Test.dll (11:54:33) is newer than the edited source (11:54:15).

@github-actions

github-actions Bot commented Aug 26, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 5)

    9 files      9 suites   7m 4s ⏱️
1 609 tests 1 608 ✅ 1 💤 0 ❌
1 610 runs  1 609 ✅ 1 💤 0 ❌

Results for commit 77a996d.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 26, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 3)

    9 files      9 suites   5m 20s ⏱️
1 973 tests 1 973 ✅ 0 💤 0 ❌
2 538 runs  2 538 ✅ 0 💤 0 ❌

Results for commit 77a996d.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 26, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 0)

599 tests   595 ✅  17m 4s ⏱️
  7 suites    4 💤
  7 files      0 ❌

Results for commit 77a996d.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 26, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 1)

2 027 tests   1 834 ✅  9m 20s ⏱️
    9 suites    193 💤
    9 files        0 ❌

Results for commit 77a996d.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 26, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 2)

2 878 tests   2 775 ✅  8m 11s ⏱️
    9 suites    103 💤
    9 files        0 ❌

Results for commit 77a996d.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 26, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 4)

2 161 tests   2 157 ✅  14m 53s ⏱️
   10 suites      4 💤
   10 files        0 ❌

Results for commit 77a996d.

♻️ This comment has been updated with latest results.

rbuergi and others added 2 commits August 26, 2026 13:46
CI caught a fourth `using MeshWeaver.AI;` resolving to the empty namespace FuzzyScorer's
misplaced declaration created: memex/Memex.Portal.Shared/Api/MeshApiEndpoints.cs. The
earlier sweep covered src/ and test/ and stopped there, so memex/ was never looked at —
the third scope miss on the same task.

Swept every tree this time (src, test, memex, tools, samples), classifying by TRANSITIVE
ProjectReference reachability rather than a direct reference, since four test projects
legitimately reach MeshWeaver.AI through their dependencies and their imports are real.
Result across the whole repository: exactly one phantom, the file above.

Verified with a solution build rather than per-project ones — per-project builds are
precisely what let the previous two escape:
MW_ALLOW_SOLUTION_BUILD=1 dotnet build MeshWeaver.slnx -c Release -p:CIRun=true -warnaserror
→ EXIT=0, 0 Warning(s), 0 Error(s).

Refs #2344

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@rbuergi

rbuergi commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

Fixed — and the sweep is now repo-wide

CI found a fourth phantom import: memex/Memex.Portal.Shared/Api/MeshApiEndpoints.cs. My earlier sweep covered src/ and test/ and stopped there, so memex/ was never looked at. That is the third scope miss on this one task, and the pattern is consistent: each time I narrowed the search and then reported the result as if it were complete.

This time I swept every tree — src, test, memex, tools, samples — classifying by transitive ProjectReference reachability rather than a direct reference, because four test projects legitimately reach MeshWeaver.AI through their dependencies and their imports are real.

Repo-wide result: exactly one phantom, the file above.

Verified with a solution build rather than per-project ones, since per-project builds are exactly what let the previous two escape:

MW_ALLOW_SOLUTION_BUILD=1 dotnet build MeshWeaver.slnx -c Release -p:CIRun=true -warnaserror
EXIT=0 · 0 Warning(s) · 0 Error(s)

@rbuergi

rbuergi commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

Re-synced onto current main (was 55 commits behind)

The red was MeshWeaver.Threading.Test exit=124 TIMEOUT (8m wall-clock cap hit — likely fixture/init hang) — a whole-assembly hang, in a suite this diff does not touch. A namespace rename plus four dead-using removals cannot hang a fixture.

Merging main here is justified on staleness, not hope: the branch was 55 commits behind, so it was re-sampling whatever main has since fixed, and every red on it looks like a defect in the change.

Revert-check with three dots confirms the branch still contributes only its own files (11 changed, 5 insertions / 12 deletions), so the merge reverted nothing.

Re-verified on the merged tree with a solution build — per-project builds are what let two earlier phantoms escape:

MW_ALLOW_SOLUTION_BUILD=1 dotnet build MeshWeaver.slnx -c Release -p:CIRun=true -warnaserror
EXIT=0 · 0 Warning(s) · 0 Error(s)

If it reds again on Threading.Test, that is a new signal and I will read it as one rather than merging main a second time.

@rbuergi

rbuergi commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

Re-synced (40 commits behind) — and the plugins-gate red was a FALSE regression

Read rather than retried. The gate's own log says the compile succeeded:

ok  Store/Coupon [32 source(s), 9 dependency record entr(ies)]

The failure appears after that, alongside the gate losing its own bookkeeping to a cross-hub write race:

[MergeGuard] Store/Coupon: refused stale/reordered cross-hub write to 'lastCompileSucceededAt'
             (changed since the writer's base) — kept the newer live value.
[MergeGuard] Store/Coupon: refused stale/reordered cross-hub write to 'lastCompiledVersion'  … 
[MergeGuard] Store/Coupon: refused stale/reordered cross-hub write to 'latestAssemblyPath'   … 

So the compile-state writes were refused as stale, the gate then read a state that did not record success, and reported 1 new failure(s), 0 stale allow entr(ies) — a failure it never actually observed. Same family as the bake-gate false regressions.

🚨 Worth stating plainly, because a namespace rename is exactly the change this gate exists to catch: had Store/Coupon genuinely failed to compile against MeshWeaver.Data.Completion, that would be a real cross-repo break in Roslyn-compiled node source no local build can see. It did not — the compile is logged ok, and no error CS appears anywhere in the job.

Also re-synced: the branch was 40 commits behind, so it was re-sampling whatever main has since fixed. Revert-check with three dots confirms it still contributes only its own files (11 changed, 5 insertions / 12 deletions).

Re-verified on the merged tree with a solution build — per-project builds are what let two earlier phantom imports escape:

MW_ALLOW_SOLUTION_BUILD=1 dotnet build MeshWeaver.slnx -c Release -p:CIRun=true -warnaserror
EXIT=0 · 0 Warning(s) · 0 Error(s)

@rbuergi
rbuergi enabled auto-merge August 26, 2026 16:15
@rbuergi
rbuergi merged commit 71bd288 into main Aug 26, 2026
27 checks passed
@rbuergi
rbuergi deleted the fix/2344-fuzzyscorer-namespace branch August 28, 2026 08:56
rbuergi added a commit that referenced this pull request Aug 28, 2026
#2349 removed `using MeshWeaver.AI;` from MeshApiEndpoints as a phantom, and
main went red with CS0246. Two fixes then restored it independently — #2408
added it under a banner comment at the top of the file, #2411 added it again
inline further down with its own explanation. Both landed, so main now
carries the SAME using twice and fails CS0105 under warnings-as-errors.

The type genuinely needs it: MeshOperations ships in assembly
MeshWeaver.Mesh.Operations but keeps namespace MeshWeaver.AI, frozen by the
TypeForwardedTo contract in #2370. So this keeps ONE directive and folds
both explanations into the banner that sits directly above it, including
why it looks removable and the fact that removing it has now cost three
red-main incidents.

One directive, one explanation, kept together — the two split copies are
exactly how the second restore could not see the first.

Verified: Memex.Portal.Shared builds clean.
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.

FuzzyScorer ships in MeshWeaver.Data but declares namespace MeshWeaver.AI.Completion

2 participants