Repository navigation
fix: CMTK0003 reports assertions and results lost through pass-throughs, branches and Task's combinators - #164
Merged
Conversation
…r a branch An assertion of CodoMetis.TypeKit.Testing on a Task or ValueTask fails the test only through the task it returns. CMTK0003 reported one dropped as a statement, but not one that returns a plain Task followed by ConfigureAwait or WaitAsync (ShouldBeNone, command ShouldBeSuccess, the expected-value ShouldBeError, ShouldBeAbsent, ShouldBeNull), nor any assertion in a branch of a ?:, ?? or switch expression so wrapped. Tasks.PassesOn now hands on a plain Task's ConfigureAwait and WaitAsync too, and the pending-assertion check runs inside the Producers loop that already judged each branch of a dropped result, so both forms of the rule take one path. Awaited, held, returned and `_ =` uses stay silent. Decision 117 covers the wider reach. Input class: AIS, a call's task dropped by a statement. There was no catalogue for it; Variants/DroppedTaskShapes is new: 25 calls (every Testing assertion on a Task and a ValueTask, and a call returning a Task of a Result) by 9 pass-throughs (none, both ConfigureAwait overloads, every WaitAsync overload, one chained) by 6 forms (the call, the lowered static form, ?., both branches of ?:, ??'s right operand, both arms of a switch) by 6 uses (dropped, a lambda's body, awaited, discarded, held, returned): 6,831 statements, DroppedTaskVariantTests. Seeded three ways: without the plain Task in PassesOn the 12 plain-Task assertions fail; with the assertion check limited to the statement's own call all 24 assertions fail; without the await condition all 24 assertions fail on false reports of their awaited forms (58 for ShouldHold on a Task alone). No sibling beyond #152's two was found. Claim T02-a-wrapped-assertion-is-reported quotes the README's new sentence. Closes #152 Defect-Class: AIS Found-By: OR Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…assertions # Conflicts: # design/analyzers.md
…inators An assertion of CodoMetis.TypeKit.Testing fails a test only through its task. CMTK0003 now reports one handed to Task.WhenAll, Task.Run or Task.WhenEach whose task is dropped, and one given to Task.WhenAny or Task.WaitAny, which finish with the first task and never show a failure, awaited or not. It counts arguments, arrays, collection expressions, a Select, a query, a ToList, a method group and an async lambda that awaits one (no catch between). Tasks the caller holds, an assertion discarded where it is made and one given to a call that returns no task stay silent; Task.WaitAll throws, so it is silent. A WhenAny of assertions converted to a plain Task or waited for, and a loop that never reads the assertions its header made, are reported too (#157). For tasks of results, the same sweep found four forms 2.2.0 missed, which ship in 2.3.0 under decision 0119: a dropped Task.WhenAny (Tasks.PendingOutcome now sees a task of a task, #159), Wait() on a ?:, ?? or switch (AnalyzeWait goes through Producers, #160), an array written in Task.WaitAll or WaitAny (each element's call, #161) and a dropped Task.WhenEach (#162). A WhenAny of held tasks returns one of them and is now silent, where 2.2.0 reported it awaited. Input class: AIS, a call's task dropped or lost by a statement. Variants/DroppedTaskShapes now has 25 calls by 9 pass-throughs by 39 forms by 11 uses, run one compilation per call and form (830 cases, DroppedTaskVariantTests): a single compilation per call overflowed the verifier's recursive matching. Seeded 18 ways, each caught: without the combinators 378 cases fail, without HandsOn's checks 48, a task of a task one level deep 3 plus the WhenAny fact, WhenAny of held tasks not stored 1 plus the fact, Wait on the own call only 3, arrays 2, method groups 18, the await jump 48, the catch check 24, Task.Run 48, WhenEach 25, the assertion loop 48, the conversion's assertion path 72, WaitAny 48, query syntax 24, calls that return no task 24, Wait's assertion path 72, WhenEach of results 1. Claims T02-combined-assertions-are-reported, T02-wait-all-observes-assertions and T02-when-any-of-results-is-reported quote the README. Defect-Class: AIS Found-By: VA Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-wrapped-assertions
…that release The maintainer widened decision 118's one exception: a form an Error misses, found before its version is tagged, is reported in that version when it loses what the rule protects in every build, though code built on the previous minor can contain it. 2.3.0's cases are #159 to #162; the rule stops at the tag, after which decision 34 holds. 0118's index row says it is widened by 0119. The Analyzers README's "What a new version may change" lists the four 2.2-writable forms and what to write instead, the changelog's Changed section says an upgrade can fail a build with them, the CMTK0003 row of design/analyzers.md lists every form the PR reaches, and claim T02-a-few-2-2-forms-are-reported quotes the README. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 29, 2026
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 #152
Closes #157
Closes #159
Closes #160
Closes #161
Closes #162
Problem
An assertion of
CodoMetis.TypeKit.Testingon aTaskfails a test only through the task it returns. CMTK0003 reported one dropped as a statement, but not one passed through a plainTask'sConfigureAwaitorWaitAsync, or sitting in a?:,??orswitch(#152). Nor did it report one handed toTask.WhenAll,Task.WhenAnyand their kin (#157). In each of these, a failing assertion leaves its task unobserved and the test passes.The sweep of the same input class found four forms on the
Resultside that 2.2.0 code can contain:Task.WhenAnyofResulttasks (CMTK0003 misses a Task.WhenAny of Result tasks dropped without await #159);Wait()on a branch (CMTK0003 misses Wait() on a ?:, ?? or switch of Result tasks #160);Task.WaitAllorTask.WaitAny(CMTK0003 misses an array of Result tasks written in Task.WaitAll or Task.WaitAny #161);Task.WhenEach(CMTK0003 misses a dropped Task.WhenEach of Result tasks #162).The maintainer took them into 2.3.0 (decision 0119).
Change
IgnoredOutcomeAnalyzer, one shared path for both forms of the rule, no special case beside it:Tasks.PassesOntakes a plainTask'sConfigureAwaitandWaitAsync.Producersloop that already judged each branch.DroppedAssertionreports an assertion handed toTask.WhenAll,Task.RunorTask.WhenEachwhose task is dropped, and toTask.WhenAnyin any use.MadeAssertions/HandsOnfollow arrays, collection expressions,Select, query syntax,ToList, method groups, and anasynclambda that awaits one with nocatchbetween.TaskandWaituse the same check.Task.WaitAnyreports each assertion it was given. A loop that never reads the assertions its header made is reported.Task.WaitAllthrows the failures, so it stays silent.Tasks.PendingOutcomesees a task of a task (CMTK0003 misses a Task.WhenAny of Result tasks dropped without await #159).AnalyzeWaitgoes throughProducers(CMTK0003 misses Wait() on a ?:, ?? or switch of Result tasks #160).WhenEachof tasks the statement made is a sequence of results (CMTK0003 misses a dropped Task.WhenEach of Result tasks #162).ReturnsItsStoredReceivertakes aWhenAnyof held tasks, which returns one of them, so that form is now silent where 2.2.0 reported it awaited.Variants/DroppedTaskShapes(new catalogue) andDroppedTaskVariantTests:Taskand aValueTask, plus a call returning a task of aResult.A_WhenAny_of_results_the_statement_made_reports_and_of_held_ones_is_silent.design/adr/0119-…): before the tag, a gap an Error has ships in that release. The rule stops at the tag, after which decision 34 holds. 0118's index row says it is widened by 0119.design/analyzers.md.Tests
CodoMetis.TypeKit.Analyzers.Tests: 2679 passed.CodoMetis.TypeKit.Conventions.Tests: 2000 passed, with Samples and Probes built.CodoMetis.TypeKit.Oracles.Tests: 51 passed.docs-query check: clean.TaskinPassesOn, with the check limited to the statement's own call, and without the await condition. Then 18 seeds of the combinator andResultfixes, each failing the sweep (1 to 378 cases) and, for CMTK0003 misses a Task.WhenAny of Result tasks dropped without await #159, the new test.??beside?:, pass-throughs on a held task, held beside made) are axes of it.🤖 Generated with Claude Code