Repository navigation
fix(#2641): heal the self-typed User declaration inside the partition its instance query is pinned to - #2723
Conversation
… its instance query is pinned to The startup repair (#2605) read the declaration paths through path-routed storage only. On memex-cloud `User`'s first segment routes to the partition `user`, which V27 renamed to `auth`, so the probe answered "absent" while the fossil sat in the auth schema — exactly where UserNodeType pins every path-less `nodeType:User` query, i.e. where UserIdentityCache reads it. The sweep wrote nothing and, having no line for "nothing found", said nothing. The sweep now resolves each candidate declaration's own instance query through MeshConfiguration.ResolveRoutingHints and, when it is pinned to a partition, also reads the path inside that partition via each writable IPartitionStorageProvider's partition-scoped adapter (CreateAdapterForTable), retyping a fossil through the adapter that found it. Candidates are filtered with the validator's now-public IsNodeTypeDeclarationContent, and every pass ends with an Information summary (paths, pinned partitions, rows read / retyped) so a miss is a count of zero rather than silence. SelfTypedDeclarationPinnedPartitionRepairTest models the production store (specific Auth provider whose path-routed adapter declines `User`, whose scoped adapter exposes the fossil): times out on the old sweep, passes now. Refs #2641 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EPCWramjFYquX5SaMdeJKW
There was a problem hiding this comment.
Pull request overview
This PR extends the startup self-typed NodeType declaration repair to also probe and heal durable declaration fossils located in the partition that the declaration’s own instance query is routed to (not just where the declaration path routes), addressing the memex-cloud User fossil scenario described in #2641.
Changes:
- Update
SelfTypedDeclarationDurableRepairto run sequential “lanes”: the existing path-routed read plus partition-scoped reads for partitions pinned by query routing rules, and retype via the adapter that found the fossil. - Expose and reuse
NodeTypeDeclarationSelfTypingValidator.IsNodeTypeDeclarationContentso guard/repair candidate selection share one definition. - Add a deterministic regression test modeling the pinned-partition-only visibility case, plus a What’s New entry.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| test/MeshWeaver.Hosting.Monolith.Test/SelfTypedDeclarationPinnedPartitionRepairTest.cs | Adds a regression test that models a fossil reachable only via a partition-scoped adapter (Auth) and verifies it is retyped in-place without creating a stray path-routed copy. |
| src/MeshWeaver.Graph/Security/SelfTypedDeclarationDurableRepair.cs | Adds pinned-partition probing lanes, shared candidate classification, and enhanced logging for repair visibility. |
| src/MeshWeaver.Graph/Security/NodeTypeDeclarationSelfTypingValidator.cs | Makes the NodeType-declaration-content classifier public so repair candidate selection matches the validator’s definition. |
| src/MeshWeaver.Documentation/Data/WhatsNew/2026-08-30-user-directory-fossil-healed-in-auth-partition.md | Documents the user-visible fix in the What’s New feed. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…faulting lane ends only itself Review finding: the end-of-sweep summary was emitted only on OnCompleted, so a lane whose read faulted ended the sweep with a warning and no summary — the exact silence the summary exists to end — and, because the lanes are concatenated, skipped every lane after it. Each lane now isolates its own read fault (logged, empty, next lane runs), mirroring the per-row tolerance, and the summary is emitted on both completion and fault with the outcome named. Refs #2641 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EPCWramjFYquX5SaMdeJKW
Test Results (shard 3)693 tests 501 ✅ 4m 42s ⏱️ Results for commit 8a77351. |
Test Results (shard 5)1 532 tests 1 532 ✅ 6m 17s ⏱️ Results for commit 8a77351. |
Test Results (shard 2)968 tests 968 ✅ 5m 58s ⏱️ Results for commit 8a77351. |
Test Results (shard 4) 10 files 10 suites 5m 47s ⏱️ Results for commit 8a77351. |
Test Results (shard 0)913 tests 913 ✅ 5m 29s ⏱️ Results for commit 8a77351. |
Test Results (shard 1)792 tests 788 ✅ 6m 39s ⏱️ Results for commit 8a77351. |
Test Results 41 files 41 suites 34m 54s ⏱️ Results for commit 8a77351. |
The
UserIdentityCachehalf of #2641 — branch 3, and the mechanismSelfTypedDeclarationDurableRepair(#2605) never considered the fossilUserrow on memex-cloud: it read the declaration paths through the ordinary path-routedIStorageAdapter.ReadMany, andUser's first segment routes to the partitionuser— which the V27 migration renamed toauth(V31 dropped the stray one that reappeared). The path-routed probe therefore answered "absent" (the tolerated42P01), the sweep wrote nothing, and — because "nothing found" had no log line — said nothing.The row lives in the
authschema, which is exactly where every consumer finds it:UserNodeTypepins the path-lessnodeType:Userquery (verbatimUserIdentityCache.DirectoryQuery) to theAuthpartition via aQueryRoutingRule. The collision the repair exists to remove is "the declaration answers its own instance query", so the row that matters is the one that query reaches — not the one the path route reaches.Live evidence (memex-cloud, image carrying #2605)
search nodeType:User{path:"User", nodeType:"User", version:2, lastModified:2026-06-02}+ the real accounts — the fossil, via the Auth pinsearch nodeType:User path:Useruser, absentsearch path:UsernodeType:"NodeType")retyped durable declaration row 'User'norretyping 'User' failedThe fix (
src/MeshWeaver.Graph/Security/SelfTypedDeclarationDurableRepair.cs)The sweep now runs two lanes per candidate declaration, in sequence:
nodeType:{path}) is pinned to a partition byMeshConfiguration.ResolveRoutingHints— the same resolution the query pipeline performs — a read of the same path inside that partition, through each writableIPartitionStorageProvider's partition-scoped adapter (CreateAdapterForTable, the seam the partition-storage hubs address a schema through regardless of the path's first segment). A fossil found there is retyped through the adapter that found it, so the write lands in the schema the row is in.Also:
NodeTypeDeclarationSelfTypingValidator.IsNodeTypeDeclarationContent(now public) instead of a bareis NodeTypeDefinition, so the guard, the predicate and the candidate set share one definition of "declares a NodeType";Deterministic repro —
SelfTypedDeclarationPinnedPartitionRepairTestModels the production store with the in-memory partition stack: a wildcard catch-all plus a specific
Authprovider whose path-routed adapter only answers forAuth/…(what the Postgres path router does with a first segment) and whose partition-scoped adapter exposes the whole store. The fossil is seeded into that store — reachable through the partition, invisible to the path.src/files reverted, rebuilt): fails —System.TimeoutExceptionafter 30 s, theauthrow never leavesnodeType: "User"(the path-routed read never sees it)authrow flips toNodeType = "NodeType", version 2 → 3, content preserved; no stray copy is written under the path route; the mirrored real account beside it is untouched.Existing
SelfTypedDeclarationDurableRepairTest(2),SelfTypedDeclarationRepairRetainsNothingTest(4) andNodeTypeDeclarationSelfTypingValidatorTest(9) all pass. BuiltMeshWeaver.Graph,MeshWeaver.Hosting.Monolith.Test,MeshWeaver.Graph.Testwith-c Release -warnaserror:0 Error(s).Not in this PR
MonotonicWriteGuard/VersionWritingdecorators (they wrap only the path-routed root adapter); the backend's own version-conditional upsert (Monotonic write guard is per-process, and the PG upsert has no version condition — a fresh replica's first write can roll a node back #971) still guards the row.What's New:
src/MeshWeaver.Documentation/Data/WhatsNew/2026-08-30-user-directory-fossil-healed-in-auth-partition.md(Category: Fix).Refs #2641