Repository navigation
fix: stop asserting which of three racing terminals answered (#1599) - #1621
Merged
Merged
Conversation
SilentReadNackTest.OwnerDisposedWithReadOutstanding_IsNacked_NotLeftHanging fails
21 of 60 times on unmodified main (flake-repro rate mode, run 31818285657) — 35%,
by a wide margin the highest rate measured on this repo, and 7 of the 26
test-attributed CI failures in the last 30 failed runs.
WHAT IT ASSERTED, AND WHY THAT COULD NOT HOLD
HandleGetDataRequest has THREE terminals — the fault arm (hosted-hub creation
frozen), the empty-completion arm, and the disposal arm — and they sit behind ONE
Interlocked CAS precisely BECAUSE they race. Which one wins is deliberately not
ordered; the frozen-creation fault legitimately wins once an ancestor's teardown has
begun. The test required the disposal arm's own free text ("still outstanding") and
therefore had to win that coin flip.
The sender-FIFO ordering the class documents is real, but it orders the READ ahead of
the DisposeRequest at the owner. It never ordered the three terminals against each
other — and the class doc claimed the arm-specific assertion was the guard that would
catch a violation, which is what made a race look like a diagnostic.
WHY DROPPING IT LOSES NOTHING
All three arms go through NackSilentRead. So all three produce a DeliveryFailure with
ErrorType.ShuttingDown, the same "GetDataRequest({reference}) at '{hub.Address}': "
prefix, the same "shutting down" classifier MeshNodeStreamCache.IsTransientOwnerFailure
reads, and the same "Retry against the fresh activation." promise. ONLY the free text
differs — the caller cannot tell them apart, and does not need to.
What the old assertion was FOR — "a routing NACK must not be able to satisfy this" —
is now established directly, and better: the routing layer's failures carry
ErrorType.NotFound or a bare exception message (RoutingServiceBase, MonolithRoutingService),
never NackSilentRead's prefix and never the retry sentence. The test asserts both.
🚨 This is not a weakened assertion, and it is not the band-aid it could be mistaken
for. The mechanism under it is correct: three terminals, one answer, guaranteed by the
CAS. The defect was a test asserting an ordering the design deliberately does not
provide. Ordering the arms instead would add coupling to the read layer #1470/#1471
just reworked, for zero caller-visible difference — the answer is byte-identical
apart from prose.
Verified locally 3/3; the real gate is flake-repro rate mode on this branch against
main's measured 21/60, since this test passes locally either way.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KmBFaHTqhy7h742wkAaJKj
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes a flaky integration test by removing an assertion that depended on which of three intentionally racing HandleGetDataRequest terminal paths won the CAS, and instead asserts on the stable caller-visible contract (ErrorType.ShuttingDown plus NackSilentRead’s distinctive message prefix + retry promise).
Changes:
- Updates
SilentReadNackTest’s doc comments to clearly document what FIFO ordering guarantees (and what it does not), including the measured flake rate onmain. - Replaces the arm-specific
"still outstanding"assertion with contract-level assertions that discriminate handler NACKs from routing-layer failures without pinning a specific terminal arm.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Contributor
Contributor
Contributor
Contributor
Contributor
Contributor
Contributor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1599.
Measured, both arms
flake-reprorate mode, 60 iterationsmain, unmodifiedSame instrument, same iteration count, same test. It is also the largest single bucket in CI: 7 of the 26 test-attributed failures across the last 30 failed runs, 4 of them on
main(sweep posted on #1384).What it asserted, and why that could never hold
HandleGetDataRequesthas three terminals — the fault arm (hosted-hub creation frozen), the empty-completion arm, and the disposal arm — and they sit behind oneInterlockedCAS precisely because they race. Which one wins is deliberately not ordered; the frozen-creation fault legitimately wins once an ancestor's teardown has begun.The test required the disposal arm's own free text:
so it had to win that coin flip.
The sender-FIFO ordering the class documents is real, but it orders the read ahead of the
DisposeRequestat the owner. It never ordered the three terminals against each other — and the class doc claimed the arm-specific assertion was the guard that would catch a violation, which is what made a race look like a diagnostic.Why dropping it loses nothing
All three arms go through
NackSilentRead. So all three produce:DeliveryFailurewithErrorType.ShuttingDown,GetDataRequest({reference}) at '{hub.Address}':,"shutting down"markerMeshNodeStreamCache.IsTransientOwnerFailureclassifies on,"Retry against the fresh activation."promise.Only the free text differs. The caller cannot tell them apart, and does not need to.
What the old assertion was for — "a routing NACK must not be able to satisfy this" — is now established directly, and better: the routing layer's failures carry
ErrorType.NotFoundor a bare exception message (RoutingServiceBase,MonolithRoutingService), neverNackSilentRead's prefix and never the retry sentence. The test asserts both.🚨 Why this is not the band-aid it could be mistaken for
"The test was wrong" is exactly what a band-aid sounds like, so the evidence matters: the mechanism under the test is correct — three terminals, exactly one answer, guaranteed by the CAS — and the three answers are materially identical to the caller. The defect was a test asserting an ordering the design deliberately does not provide.
Ordering the arms instead would add coupling to the read layer #1470/#1471 just reworked, for zero caller-visible difference. The bound is not the problem and neither is the mechanism; the assertion was.
The class remarks now record the 21/60 measurement and say plainly what the FIFO does and does not order, so the next person does not re-derive it from a red shard.