Skip to content

A message arriving mid-activation could overtake the queue that ordered it (fixes the kernel CS0103 reorder) - #1155

Merged
rbuergi merged 3 commits into
mainfrom
fix/1145-activation-backlog-leapfrog
Aug 10, 2026
Merged

rbuergi merged 3 commits into
mainfrom
fix/1145-activation-backlog-leapfrog

Conversation

@rbuergi

@rbuergi rbuergi commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Root cause

RoutingServiceBase.RouteInMesh preserves FIFO for a not-yet-activated address through the per-address ActivationSerializer (bef2604) — but its hosted-hub short-circuit consults only "is the hub registered?". A hub becomes registered the moment its construction completes (HostedHubsCollection.GetHub publishes it to messageHubs BEFORE 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's GetRemoteStream subscriptions racing the three SubmitCodeRequest posts. 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 — "use sharedValue" reaches the REPL before "define sharedValue" → 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), the ActivationSerializer Concat pump, KernelContainer's eager Observe forward, hosted-hub mailboxes, and KernelExecutor's Select(RunSubmission).Concat() REPL queue.

Deterministic repro

ActivationBacklogFifoTest scripts the exact interleaving with a timing-only gate around the real PathResolutionService (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 processes A, C, B on every run; after the fix A, B, C. Verified fail-before/pass-after in both orders with the final test shape.

Fix

In RouteInMesh, a still-live ActivationSerializer for 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 — TryEnqueue then returns false — so the steady-state direct path is untouched.

Verification

  • ActivationBacklogFifoTest: deterministic A, C, B fail 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; KernelReplChainingTest green.
  • WhatsNewEntryIntegrityTest green.
  • dotnet build -c Release -warnaserror clean 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

…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
Copilot AI lite review requested due to automatic review settings August 10, 2026 15:30

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 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.RouteInMesh to prioritize enqueuing into an already-live ActivationSerializer before taking the hosted-hub short-circuit path.
  • Add ActivationBacklogFifoTest to 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.

Comment thread src/MeshWeaver.Hosting/RoutingServiceBase.cs
@github-actions

github-actions Bot commented Aug 10, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 0)

701 tests   701 ✅  13m 41s ⏱️
 10 suites    0 💤
 10 files      0 ❌

Results for commit bb48890.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 10, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 3)

   11 files     11 suites   10m 5s ⏱️
1 984 tests 1 876 ✅ 108 💤 0 ❌
2 162 runs  2 054 ✅ 108 💤 0 ❌

Results for commit bb48890.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 10, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 2)

1 925 tests   1 924 ✅  5m 26s ⏱️
   11 suites      1 💤
   11 files        0 ❌

Results for commit bb48890.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 10, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 5)

1 773 tests   1 581 ✅  6m 15s ⏱️
   11 suites    192 💤
   11 files        0 ❌

Results for commit bb48890.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 10, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 1)

1 287 tests   1 286 ✅  6m 49s ⏱️
   11 suites      1 💤
   11 files        0 ❌

Results for commit bb48890.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 10, 2026 •

Copy link
Copy Markdown
Contributor

Test Results (shard 4)

1 350 tests   1 345 ✅  8m 23s ⏱️
   11 suites      5 💤
   11 files        0 ❌

Results for commit bb48890.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 10, 2026 •

Copy link
Copy Markdown
Contributor

Test Results

   65 files     65 suites   50m 42s ⏱️
9 020 tests 8 713 ✅ 307 💤 0 ❌
9 198 runs  8 891 ✅ 307 💤 0 ❌

Results for commit bb48890.

♻️ This comment has been updated with latest results.

rbuergi and others added 2 commits August 10, 2026 18:16
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>
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.

Three back-to-back kernel submissions lose shared state — CS0103 on the monolith path

2 participants