Skip to content

fix: CMTK0003 reports assertions and results lost through pass-throughs, branches and Task's combinators - #164

Merged
CaffeinatedCoder merged 5 commits into
release/2.3.0from
fix/cmtk0003-wrapped-assertions
Oct 29, 2026
Merged

CaffeinatedCoder merged 5 commits into
release/2.3.0from
fix/cmtk0003-wrapped-assertions

Conversation

@CaffeinatedCoder

Copy link
Copy Markdown
Owner

Closes #152
Closes #157
Closes #159
Closes #160
Closes #161
Closes #162

Problem

An assertion of CodoMetis.TypeKit.Testing on a Task fails a test only through the task it returns. CMTK0003 reported one dropped as a statement, but not one passed through a plain Task's ConfigureAwait or WaitAsync, or sitting in a ?:, ?? or switch (#152). Nor did it report one handed to Task.WhenAll, Task.WhenAny and 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 Result side that 2.2.0 code can contain:

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:
  • Variants/DroppedTaskShapes (new catalogue) and DroppedTaskVariantTests:
    • 25 calls: every assertion on a Task and a ValueTask, plus a call returning a task of a Result.
    • 9 pass-throughs, 39 forms (including the silent controls) and 11 uses.
    • 830 cases, one compilation per call and form. A single compilation per call overflowed the verifier's recursive matching.
  • New test A_WhenAny_of_results_the_statement_made_reports_and_of_held_ones_is_silent.
  • Decision 0119 (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.
  • Docs:
    • The Analyzers README's assertion paragraph, "Waiting and loops", and the "What a new version may change" exception list.
    • The CMTK0003 row of design/analyzers.md.
    • The changelog: the Testing line, and a Changed line that says a 2.2.0 build can fail on upgrade, which forms do it, and what to write instead.
    • Claims T02-a-few-2-2-forms-are-reported, T02-a-wrapped-assertion-is-reported, T02-combined-assertions-are-reported, T02-wait-all-observes-assertions and T02-when-any-of-results-is-reported.

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.
  • Each guard seeded and caught. The CMTK0003 misses dropped async assertions through Task wrappers and branches #152 fix three ways: without the plain Task in PassesOn, with the check limited to the statement's own call, and without the await condition. Then 18 seeds of the combinator and Result fixes, 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.
  • Input class: AIS, a call's task dropped or lost by a statement; the catalogue is new and holds every axis above. The weaving-review §8 neighbours (?? beside ?:, pass-throughs on a held task, held beside made) are axes of it.

🤖 Generated with Claude Code

CaffeinatedCoder and others added 5 commits October 29, 2026 16:23
…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>
…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>
@CaffeinatedCoder CaffeinatedCoder added this to the 2.3.0 milestone Oct 29, 2026
@CaffeinatedCoder CaffeinatedCoder added bug Something isn't working silent Compiles or answers and does less than it appears to severity/medium Inconsistency or failure in a narrow scenario package/analyzers Affects CodoMetis.TypeKit.Analyzers package/testing Affects CodoMetis.TypeKit.Testing area/option-result Option, Result and their extensions labels Oct 29, 2026
@CaffeinatedCoder
CaffeinatedCoder merged commit 9878a6c into release/2.3.0 Oct 29, 2026
17 checks passed
@CaffeinatedCoder
CaffeinatedCoder deleted the fix/cmtk0003-wrapped-assertions branch October 29, 2026 18:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/option-result Option, Result and their extensions bug Something isn't working package/analyzers Affects CodoMetis.TypeKit.Analyzers package/testing Affects CodoMetis.TypeKit.Testing severity/medium Inconsistency or failure in a narrow scenario silent Compiles or answers and does less than it appears to

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant