Add tests for core behaviour the suite ran but never checked - #871
Merged
Merged
Conversation
…; drop a check dispatchNow already makes Tests for: the registration latch closing on the process ActionExecuteRegistry only; held calls rejected with BridgeDestroyedError and attaches dropped (not issued) on teardown; deregistering one handler keeping the others tracked; a posted off-owner registration holding calls made meanwhile; an empty assignHandlerPrimary key promoting nothing; a failed promote logging the backend's reason; a stale bind reply staying stale after a switch followed by an attach or a reconnect; inline publish when the backend settles on the owner; the guiExec owner check; setExecuteDeadline(0) disarming and starting no thread. executeAttachedVia's continuation no longer re-checks currentId == 0: dispatchNow rejects an unbound binding with the same error, now pinned by a test of an attach that settles with no instance. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141t3QdB4FkiHqiCX2M2eF2
…uite ran but never checked ~LocalBackend stopping a running Task handler; a call cancelled while waiting behind a Task handler finishing as a failure; trackedPendingCount counting in-flight calls; executeLatencyMs covering the handler's run time; an empty assignPrimary key filing nothing; a change-aware instance staying notified after one of two handlers releases it; the adapter running a synchronous verb inline when re-entered from its own control strand. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141t3QdB4FkiHqiCX2M2eF2
…backs, and repairTornTail's trim and report A rollback at offset zero (an empty file) is a real rollback, a second short write on the same handle must roll back to the shortened file, a file with no complete record is emptied, and the trim warning carries the discarded byte count while an intact file logs nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141t3QdB4FkiHqiCX2M2eF2
…nt64 edge and the refusal messages peekCallId's "saw a digit" flag only ever guarded returning a value that is already 0 when no digit was seen, so it goes. Tests now cover ids containing the digit 0, the largest id that still fits next to the first one that would wrap, decode's size refusal naming the refused size, and interpretHelloReply carrying the peer's own message (or "malformed reply" for an empty one). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141t3QdB4FkiHqiCX2M2eF2
… promoted instance dies with its handler Both ActionDispatcher entry points close the latch when they read the process dispatcher and leave it open for a locally owned one. An instance promoted by assignPrimary carries exactly the one attachment of the handler that created it, so releasing that handler destroys it and frees its key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141t3QdB4FkiHqiCX2M2eF2
…el, close and delay retire their loop timers delay() holds 0 until its timer is armed and cancels whatever it holds on a stop, so a scheduler handle of 0 would let it cancel another caller's callback; the Handle doc now says so and a test pins it. Cancelling, destroying the scheduler, stopping a delay and destroying a suspended delay each retire the event loop's timer, asserted on the loop's own pending-timer count rather than only on the callback not running. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141t3QdB4FkiHqiCX2M2eF2
…into when the post then fails An executor that runs the posted attach and then throws leaves the await already settled by the handler the attach installed. The coroutine has to see the value exactly once, not the post's exception on top of a queued resumption. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141t3QdB4FkiHqiCX2M2eF2
…drain on destruction, and OwnedState::ask's post An action started by a leave() that is still running when that leave() returns starts the next queued action from its own leave(). A ThreadPoolExecutor destroyed with work queued runs all of it before joining, as its destructor documents -- the test asserted only that the join returned. OwnedState::ask called off the owner runs its body on the owner. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141t3QdB4FkiHqiCX2M2eF2
…FNV-1a digest, key decoding by view, and the never-configured observe state Optional, map key, map value, reflected member and a PayloadShapeTag's inner shape each cost one level, so nine of any of them render the leaf as the opaque tag. The fingerprint digest is checked against published FNV-1a vectors, since a journal's stamp is compared across builds. keyFromString decodes only the characters its view spans, and ScopedObserveOverride works in a process that has never installed a sink. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141t3QdB4FkiHqiCX2M2eF2
…ijection across both halves nextOpaqueId's `id = 0` was overwritten before its first read; the loop now declares the candidate where it is drawn. The existing bijection samples each vary only one half of the counter, so a permutation that ignores the high word or folds its output to 32 bits still passes them. A sample of 2^19 counters spread over both words collides ~32 times under such a permutation and never under the real one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141t3QdB4FkiHqiCX2M2eF2
The undecodable-envelope line's size, capped prefix and ellipsis, the per-request debug line's bodyBytes, and the latency metric's value were emitted but never read: any of them could report a constant and the suite stayed green. The logger override and metric sink make each one checkable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141t3QdB4FkiHqiCX2M2eF2
…etirement on reply drainedWithin(0) answers from the in-flight count its request finds; a test now queues an execute's completion right behind the request, so deferring the answer to a timer turns it into `true`. An execute that answers before its executeTimeout must cancel the armed deadline, which otherwise holds the server alive until it fires. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141t3QdB4FkiHqiCX2M2eF2
…ap around construction A connection that has released its one reference to a shared instance cannot release another connection's; an attach re-pointing onto a key already live releases the old instance; a register at the cap is refused before any model is constructed; and a register whose own construction fills the last slot is refused by the re-test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141t3QdB4FkiHqiCX2M2eF2
…and cancelPending assignPrimary files the instance under its key; binding a private instance over a live one releases it; cancelPending fails every call still in flight, not just the most recent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141t3QdB4FkiHqiCX2M2eF2
const guards and capture, reserve before the push loop, a private flag behind a setter, contains() for the log match, named leaks, and a NOLINT for the by-value parameter ActionCall::localOpAsync's signature requires. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141t3QdB4FkiHqiCX2M2eF2
…ive the keyed failure The parked handler stored its completion callback, which holds the call, which holds the handler: a cycle LeakSanitizer reports once the test ends. finish() takes the callback out before running it. The bind-path test recorded the keyed call's failure into a local that went out of scope before the owner delivered it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141t3QdB4FkiHqiCX2M2eF2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141t3QdB4FkiHqiCX2M2eF2
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
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.
A local Mull mutation run over
include/morph/core/on cc00977 scored 73.0%: 790 mutants, 577 killed, 213 survived. A survivor is a change to the library thatmorph_testsstill passes. This PR goes through all 213. Each one has been applied to the header by hand and given a verdict.Every new test was checked in both directions. It fails with the mutation applied by hand to the header, and passes against the original code.
No library defect was found. Every survivor that changes behaviour was a test gap, not wrong code.
The 42 misreports. Mull reported these as survivors, but each one fails an existing test once the mutation is applied by hand. The likely cause is that Mull mutates one translation unit's copy of an inline header function and the linker keeps an unmutated copy. That cause is inferred, not proven. Either way, survivors reported in header code need checking by hand before anyone acts on them.
The constant 42 means
falsefor a bool. In LLVM IR, Mull's replacement constant 42 truncates tofalsefor abool. Soflag = false→= 42leaves the program unchanged, and those mutants are counted as unable to change behaviour.Changes
bridge.hpp: acurrentId == 0check thatdispatchNowalready makes with the same error.wire.hpp:peekCallId'ssawDigitflag, which only guarded returning a value that is already 0.remote.hpp:nextOpaqueId's initial value, which was always overwritten.TimeoutSchedulerdocumentation. TheHandledoc now states that a handle is never 0.DelayAwaiterrelies on that.setExecuteDeadline(0)disarming the deadline and starting no timer threadexecuteLatencyMscovers the handler's run timetrackedPendingCountOpaqueIdGeneratoris a bijection across both halvesdrainedWithin(0)executeTimeoutdeadline is retired when the reply arrivesassignPrimary, private re-bind andcancelPendingrollBackShortWriteandrepairTornTailedgespeekCallIdat zero digits and at theuint64boundaryTimeoutSchedulerretiring its loop timers on cancel, close and delayOwnedState::askposting to the ownerThe two survivors with no test are
remote.hpp's in-flight slot release, which is only reachable ifdispatchExecutethrows between reserving the slot and posting, andcoroutine.hpp:243, a stop racing the timer arm. Neither has a seam that would make a deterministic test.Re-running the same Mull campaign on this branch, before the rebase so the base is still cc00977, scores 82.78%: 784 mutants, 649 killed, 135 survived. That is up from 73.0%.
🤖 Generated with Claude Code
https://claude.ai/code/session_0141t3QdB4FkiHqiCX2M2eF2