Repository navigation
A message arriving mid-activation could overtake the queue that ordered it (fixes the kernel CS0103 reorder) - #1155
Conversation
…ed it Three back-to-back kernel submissions intermittently lost shared state on the monolith path (CS0103: 'sharedValue' does not exist): a later submission reached the REPL before the one defining the variable. RouteInMesh keeps FIFO for a not-yet-activated address through the per-address ActivationSerializer - but its hosted-hub short-circuit consulted only "is the hub registered?". A hub becomes registered the moment its construction completes (HostedHubsCollection.GetHub publishes it BEFORE the serializer has drained the deliveries queued behind the activating message), so a message arriving in that window was handed straight to the hub's mailbox, overtaking every delivery still in the backlog. For the kernel test, the session hub's activation (driven by the GetRemoteStream subscriptions racing the posts) completed between the arrivals of submission 1 and submissions 2/3 - "use sharedValue" executed before "define sharedValue". ActivationBacklogFifoTest pins the leapfrog deterministically with a timing-only gate around the real PathResolutionService: before the fix the probe hub processes A, C, B on every run; after it, A, B, C. Fix: while an activation serializer for the address is still live, every message joins its queue (Concat preserves total arrival order). The serializer self-retires when the backlog drains, so the steady-state direct path is untouched. Fixes #1145 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UYLgoPK1qLtyxZ2ixdFtj5
There was a problem hiding this comment.
Pull request overview
This PR fixes a routing FIFO violation during hub activation in the monolith path: messages posted while an address’s activation backlog is still draining could bypass the ActivationSerializer once the hub becomes “hosted/registered”, causing later messages to overtake earlier queued deliveries (e.g., triggering kernel CS0103 by running “use variable” before “define variable”).
Changes:
- Update
RoutingServiceBase.RouteInMeshto prioritize enqueuing into an already-liveActivationSerializerbefore taking the hosted-hub short-circuit path. - Add
ActivationBacklogFifoTestto deterministically reproduce (and pin) the specific mid-activation reordering window. - Add a What’s New entry documenting the user-visible fix (“code cells no longer forget earlier cells”).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| test/MeshWeaver.Hosting.Monolith.Test/ActivationBacklogFifoTest.cs | Adds a deterministic regression test that proves messages A/B/C preserve post order through the activation backlog window. |
| src/MeshWeaver.Hosting/RoutingServiceBase.cs | Fixes the ordering hole by enqueuing into an existing, still-draining activation serializer before routing directly to a newly hosted hub. |
| src/MeshWeaver.Documentation/Data/WhatsNew/2026-08-10-code-cells-no-longer-forget-earlier-cells.md | Documents the user-facing symptom and the behavioral guarantee restored by the routing fix. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Test Results (shard 0)701 tests 701 ✅ 13m 41s ⏱️ Results for commit bb48890. ♻️ This comment has been updated with latest results. |
Test Results (shard 3) 11 files 11 suites 10m 5s ⏱️ Results for commit bb48890. ♻️ This comment has been updated with latest results. |
Test Results (shard 2)1 925 tests 1 924 ✅ 5m 26s ⏱️ Results for commit bb48890. ♻️ This comment has been updated with latest results. |
Test Results (shard 5)1 773 tests 1 581 ✅ 6m 15s ⏱️ Results for commit bb48890. ♻️ This comment has been updated with latest results. |
Test Results (shard 1)1 287 tests 1 286 ✅ 6m 49s ⏱️ Results for commit bb48890. ♻️ This comment has been updated with latest results. |
Test Results (shard 4)1 350 tests 1 345 ✅ 8m 23s ⏱️ Results for commit bb48890. ♻️ This comment has been updated with latest results. |
Test Results 65 files 65 suites 50m 42s ⏱️ Results for commit bb48890. ♻️ This comment has been updated with latest results. |
Review follow-up on #1155: RouteInMesh computed `GetHostAddress` twice — once for the hosted-hub probe and once for the activation-serializer key. GetHostAddress is idempotent (every return path yields an address with Host == null), so the second call could only ever return the first one's result; the extra traversal bought nothing and made it harder to see that the two lookups are keyed on the SAME value. That sameness is load-bearing, not cosmetic: the fix in this PR only holds because the serializer lookup and the hosted-hub short-circuit agree on the key. If they could diverge, a message would miss the live queue and leapfrog it again — exactly #1145. Collapsed to one `address` and stated the invariant where the value is computed so nobody re-adds the second call. No behavioural change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Root cause
RoutingServiceBase.RouteInMeshpreserves FIFO for a not-yet-activated address through the per-addressActivationSerializer(bef2604) — but its hosted-hub short-circuit consults only "is the hub registered?". A hub becomes registered the moment its construction completes (HostedHubsCollection.GetHubpublishes it tomessageHubsBEFORE the serializer has drained the deliveries queued behind the activating message). A message arriving in that window was handed straight to the hub's mailbox and overtook every delivery still in the backlog.For
MonolithKernelTest.ThreeSubmissions_ShareState: the kernel-session Activity hub is activated concurrently by the test'sGetRemoteStreamsubscriptions racing the threeSubmitCodeRequestposts. When the activation completes between the arrival of submission 1 (already queued in the serializer) and submissions 2/3, the later submissions short-circuit past it — "usesharedValue" reaches the REPL before "definesharedValue" → CS0103. Three submissions + two streams put more messages in the backlog and more arrival gaps for the registration to land in than the 2-submission sibling — matching the observed discriminator (2 passes, 3 fails in the same runs).Everything else on the path was verified order-preserving: client action block → mesh mailbox →
RouteInMesh(serial per mailbox), theActivationSerializerConcat pump,KernelContainer's eagerObserveforward, hosted-hub mailboxes, andKernelExecutor'sSelect(RunSubmission).Concat()REPL queue.Deterministic repro
ActivationBacklogFifoTestscripts the exact interleaving with a timing-only gate around the realPathResolutionService(no data faked, no sleeps — every step is fenced on an observable condition): A parks in activation (serializer alive), B joins the backlog (fenced), A is released — hub registered, B parked in its serializer turn — and C is posted in exactly that window. Before the fix the probe hub processesA, C, Bon every run; after the fixA, B, C. Verified fail-before/pass-after in both orders with the final test shape.Fix
In
RouteInMesh, a still-liveActivationSerializerfor the address takes precedence over the hosted-hub short-circuit: the message joins the queue, and Concat preserves total arrival order. The serializer self-retires the moment its backlog drains —TryEnqueuethen returnsfalse— so the steady-state direct path is untouched.Verification
ActivationBacklogFifoTest: deterministicA, C, Bfail before, green after (both verified).MonolithKernelTest(MeshWeaver.Persistence.Test): 8/8 green, incl.ThreeSubmissions_ShareState,MultipleSubmissions_ShareKernelState, and both interactive-showcase pipelines.MonolithMeshTest+ShutdownRoutingRejectClassificationTest+SubscribeRequestIdentityRoutingTest: 23/23 green;KernelReplChainingTestgreen.WhatsNewEntryIntegrityTestgreen.dotnet build -c Release -warnaserrorclean for the touched chains (MeshWeaver.Hosting via Hosting.Monolith.Test, MeshWeaver.Documentation via Documentation.Test).Fixes #1145
🤖 Generated with Claude Code
https://claude.ai/code/session_01UYLgoPK1qLtyxZ2ixdFtj5