Skip to content

test: the owner-disposing NACK test fences on the owner ACCEPTING the patch - #5688

Merged
meshweaver-cloud[bot] merged 1 commit into
mainfrom
fix/owner-disposing-nack-race
Sep 25, 2026
Merged

meshweaver-cloud[bot] merged 1 commit into
mainfrom
fix/owner-disposing-nack-race

Conversation

@rbuergi

@rbuergi rbuergi commented Sep 25, 2026

Copy link
Copy Markdown
Contributor

What

NackReachesTheWaiterDuringTeardownTest.OwnerDisposingUnderMeshTeardown_StillAnswersTheWaitingCaller ejected #5664 from the merge queue (run 36019287652, job 107701388653, shard 4). This fixes the test's own synchronisation. There is no product change.

Root cause

The fence before Mesh.Dispose() waited for LatePatchResponseRegistry.ArmedCount > 0. The caller arms that watch before it posts (#2882: register, then post), so an armed watch proves the patch was sent. It does not prove the owner's patch handler ran, and that handler is what registers the OwnerDisposing disposal NACK. If the dispose lands between the two, the patch reaches an owner that never registered a NACK. The owner goes Dead owing nothing, and the assertion fails on a precondition the test never established.

The CI trace fits this. The watch was armed at +52 ms, dispose ran 1 ms later, the owner was Dead within the next 50 ms poll, and the window held no framework warning.

Evidence (linux/arm64 container, --cpus=2)

Build Result
unmodified, looped: alone, 40× in one process, whole Graph.Test in bulk; at the failing commit 6b7974d8 and at main 0 failures in 400+ runs
post held back 120 ms after the watch arms (temporary diagnostic, not committed) 40/40 red, identical assertion text
same delayed build, with this fence 40/40 green
normal build, with this fence 40/40 green; locally 1/1

Fix

The fence now waits for PATCH_MERGE_DISPATCHED@<owner> in Mesh.DescribeRequestFate(armedId). The handler stamps that stage strictly after RegisterOwnerDisposingNack. This is the same "accepted is observed, never assumed" wait DisposalRaceNackTest makes on ENQUEUED@<victim>. The finding is recorded in Doc/Architecture/TeardownVerdictsAreCausal → "A third: an ARMED watch is not an ACCEPTED patch".

Cross-repo

MeshWeaver.Plugins' TeardownTwinParityTest compares this body against its twin src/MeshWeaver.Hosting.Monolith.Test/NackReachesTheWaiterDuringTeardownTest.cs. The twin needs the same body, so it gets a paired Plugins PR that lands after this one.

Pairs-with: none — no public surface is removed (test + doc only)

🤖 Generated with Claude Code

… patch, not on the caller arming its watch

NackReachesTheWaiterDuringTeardownTest ejected #5664 from the merge queue
(run 36019287652, shard 4): watch armed at +52 ms, Mesh.Dispose() 1 ms
later, owner Dead within the next poll, watch still armed, no framework
warning in the window.

The fence waited for LatePatchResponseRegistry.ArmedCount > 0. The caller
arms that watch BEFORE it posts (#2882), so it proves the patch was SENT,
not that the owner's handler ran — and the handler is what registers the
disposal NACK. A dispose landing between the two leaves an owner that owes
nothing; the assertion then fails on a precondition the test never
established.

Evidence (linux/arm64 container, --cpus=2):
- 0 failures in 400+ loops (alone, 40x in one process, whole
  Graph.Test in bulk; at the failing commit 6b7974d and at main)
- holding the post back 120 ms after the watch arms: 40/40 red with the
  identical assertion text
- same delayed build with this fence: 40/40 green; normal build 40/40

The fence now waits for PATCH_MERGE_DISPATCHED@<owner> on the tree's
request-fate ledger, stamped strictly after RegisterOwnerDisposingNack —
the same "accepted is observed" wait DisposalRaceNackTest makes.

The MeshWeaver.Plugins twin (TeardownTwinParityTest) must carry the same
body; ported in the paired Plugins PR.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 25, 2026 07: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.

Copilot review overview

🟢 Approval recommended

No unresolved review issues remain.

Review effort: Lite
Findings: None

What changed in this PR

This pull request hardens a teardown race regression test by waiting for confirmed owner acceptance and documents the synchronization rule.

Changes:

  • Fences on PATCH_MERGE_DISPATCHED after NACK registration.
  • Documents why an armed watch does not prove owner acceptance.
File Description
test/​MeshWeaver.Graph.Test/​NackReachesTheWaiterDuringTeardownTest.cs Adds the owner-acceptance synchronization fence.
src/​MeshWeaver.Documentation/​Data/​Architecture/​TeardownVerdictsAreCausal.md Records the race and synchronization guidance.

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

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 3)

443 tests  ±0   443 ✅ ±0   55s ⏱️ -7s
  3 suites ±0     0 💤 ±0 
  3 files   ±0     0 ❌ ±0 

Results for commit 259db97. ± Comparison against base commit 3e86d5a.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 0)

  1 files  ±0    1 suites  ±0   3m 16s ⏱️ +40s
345 tests ±0  345 ✅ ±0  0 💤 ±0  0 ❌ ±0 
349 runs  ±0  349 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 259db97. ± Comparison against base commit 3e86d5a.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 1)

1 655 tests  ±0   1 655 ✅ ±0   3m 9s ⏱️ -11s
    2 suites ±0       0 💤 ±0 
    2 files   ±0       0 ❌ ±0 

Results for commit 259db97. ± Comparison against base commit 3e86d5a.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 4)

    3 files  ±0      3 suites  ±0   6m 14s ⏱️ +4s
2 014 tests ±0  2 014 ✅ ±0  0 💤 ±0  0 ❌ ±0 
2 015 runs  ±0  2 015 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit 259db97. ± Comparison against base commit 3e86d5a.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 2)

751 tests  ±0   559 ✅ ±0   7m 8s ⏱️ +3s
  3 suites ±0   192 💤 ±0 
  3 files   ±0     0 ❌ ±0 

Results for commit 259db97. ± Comparison against base commit 3e86d5a.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results (shard 5)

    5 files  ±0      5 suites  ±0   15m 42s ⏱️ +13s
4 093 tests ±0  4 091 ✅ ±0  2 💤 ±0  0 ❌ ±0 
4 097 runs  ±0  4 095 ✅ ±0  2 💤 ±0  0 ❌ ±0 

Results for commit 259db97. ± Comparison against base commit 3e86d5a.

@github-actions

Copy link
Copy Markdown
Contributor

Test Results

   17 files  ±0     17 suites  ±0   36m 26s ⏱️ +42s
9 301 tests ±0  9 107 ✅ ±0  194 💤 ±0  0 ❌ ±0 
9 310 runs  ±0  9 116 ✅ ±0  194 💤 ±0  0 ❌ ±0 

Results for commit 259db97. ± Comparison against base commit 3e86d5a.

@meshweaver-cloud
meshweaver-cloud Bot added this pull request to the merge queue Sep 25, 2026
Merged via the queue into main with commit d3b7262 Sep 25, 2026
40 checks passed
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