Repository navigation
release: 2.3.0 - #176
Merged
Merged
release: 2.3.0#176
Conversation
…abels, milestone, branch and issue link The repository had 66 pull requests and no issue, milestone or label of its own. It adopts CodoMetis.ValueRanges' scheme (decision 109): - issue forms for a bug, an enhancement and an epic, with blank issues off and security reports sent to the private advisory form; a pull request template (Closes #n, Problem, Change, Tests); - labels: one type, a severity on a bug, package/* and area/*, silent, breaking, found-by/prober, stacked, epic. The legend is in CONTRIBUTING's "Issues and labels", and AGENTS.md has an Issues section; - a release is an epic with a milestone of its version; the roadmap stays in design/roadmap.md. pr-hygiene.yml runs tools/PrHygiene on the event payload of every pull request into main or a release branch. ValueRanges' check is a bash script; under decision 92 this one is a tool project, BCL only, with its tests. Besides ValueRanges' rules (one type label, a severity on a bug, a closing reference), it holds decision 94's branch naming against the type label, the release's milestone, silent only on a bug, and breaking only into a major. Each rule was proved by deleting it from the tool: 12 seeds, each caught by the 41 tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The ReleaseNotesFromChangelog target writes the section under '## $(Version)' of CHANGELOG.md into every nuspec, as the plain text nuget.org shows (measured on package pages: it escapes the notes and links bare URLs, nothing else), with one line linking the whole changelog. Every package carries the whole section: the areas name topics, not packages, and every satellite depends on the base package. A missing or empty section, a relative link, or notes over 35,000 characters fail the pack, naming the file. PackageReleaseNotesTests holds the packed nuspecs to the section, and runs the target on a sample changelog of every Markdown shape and of MSBuild-special text, in LF and CRLF, and on the four it must refuse. Closes #75 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CodeQL resolved the virtual object.ToString() in Hx.BindText's enum arm to every override in the database, Sides.Answer.ToString() among them, which reads JsonException.Path; it then reported exception information reaching the bind probe's request body (code-scanning alert 1, cs/information-exposure-through-exception). The value there is always a boxed enum, so the cast to Enum gives the same text and narrows the call. Closes #78 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
build: track work as labelled issues, and check each PR's labels, milestone, branch and issue link
The branch's previous head carried a failed 'Labels and issue link' run from the closed PR 79 (its branch was then named chore/), which the release branch's ruleset counts against PR 80 too. An empty commit gives the PR check runs of its own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-enum refactor: BindText's enum arm calls Enum.ToString (CodeQL alert 1)
…er the problem A caught exception was lost on the way to a Fault<TFault>: the MapError that turns it into the fault an endpoint answers dropped it, so a log of the refusal could not say what failed underneath (decision 52). - Fault<TFault>.Cause, set by Fault.Of(reason, detail, cause) and the constructor of the same shape, and Of(reason, detail, cause) on Fault<T1, T2> and Fault<T1, T2, T3>. WithRule and `with` keep it. A null cause is refused where one is given. - Equality and the hash code are the reason's, the detail's and the rule's, written by hand so the cause takes no part; ToString prints as 2.2 did. - AspNetCore: FaultProblem<TFault>.Cause, and IFaultFeature.Cause as a default member, so a host's own implementation still builds. The problem's members are the same with a cause as without one. - READMEs (core, and AspNetCore's "What failed underneath" with compiled samples), changelog, the option-result note; the roadmap item goes. - The C03 seeds are regenerated against the new source. The private Problem() helper stays the composed overloads' alone, so each-error-own-set still breaks composed faults only. Proved by seeding: equality over the cause fails two tests, a dropped cause in ToHttpResult six, and the cause's message written into the problem five. Closes #84 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and Patch Result.CatchAsync gains four ValueTask forms, valued and command, wide and narrowed, catching as the Task forms do. Each is [OverloadResolutionPriority(-1)], so an async lambda binds to the Task form as before; without it the repository's own CatchAsync calls are CS0121, the ambiguity decision 30 measured. Catch keeps refusing a ValueTask at run time. Option<T>.TraverseAsync and Patch<T>.TraverseAsync, with token forms, are the synchronous Traverse with the operation awaited: None, a clear and an absent field call nothing and check no token. Decision 110 records both. The completeness tests (null delegate, null task, asynchronous context, uninitialized result) cover the eight new members. Closes #88 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t unawaited Every assertion of CodoMetis.TypeKit.Testing has a form on a Task and on a ValueTask of what it checks, beside its synchronous form: it awaits the task and answers as the synchronous form does, the same content back and the same message. A task that faults propagates its own exception, and a null task is refused by the parameter's name. An assertion on a task fails the test only through the task it returns, so `service.FindAsync(id).ShouldBeSome();` without await passed whatever the task held, and C# warns only in an async method. CMTK0003 reports such a statement, through ConfigureAwait and in a lambda's body too. It knows the assertions by the Testing assembly's identity, as it knows the Generators assembly, so a consumer's own extension on a pending result stays silent: every reported call is new in 2.3, and no build that worked before breaks. The C20 seed whichever-of-its-types is regenerated against the new FaultAssertions.cs. Closes #87 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FaultResponse.WithoutFaultName() answers a member without naming it, for causes a client must not tell apart: a sign-in's unknown user and wrong password, mapped to 401 and withheld, answer alike without a mapping to one member at the boundary. The problem has no fault and no rule, and a fault set member's description no longer stands in as its detail, since it names the member as surely; the occurrence's own detail is kept. IFaultFeature gains NameWithheld, a default member, so the host still logs the fault and sees that the client is not told. The document's problem schema is shared and keeps fault optional; a response whose every fault withholds its name ends its description with "The problem names no fault." The startup warning for two fault types that write one name counts only the members that write it (Found-By: VA, the sibling of the problem's fault member). Decision 111 records it; decision 64's index row points to it. Stacked on feat/catch-async-valuetask for the record's number. Seven probe seeds that patch the changed lines are regenerated: C03 shared-status-types, C05 stays-the-errors, C06 description-as-detail and no-description-no-detail, C08 leave-one-out-fixes, C14 declared-describes- fault and declared-problem. Closes #85 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The prober cost more than it paid: a release's `prober seeds --all` built the probe harness once per seed, 170 seeds at about four minutes, and one change to the fault responses staled 23 seeds of five probes. The replay, the footprints, the ledger, the covering arrays and the gate carried the same weight. Removed: tools/Prober and its tests, the corpus under tools/probe/ with its 38 probes and 170 seeds, the probes and probe-status jobs of dotnet.yml, the replay and gate steps of release.yml, .claude/probe-axes.md, the probe-triage skill, the probe conventions tests, and DocsQuery's check of the facts the corpus cited. The verified facts and their fixtures stay. Added, after CodoMetis.ValueRanges (test/oracles/README.md): - claims.json: the prober's 169 obligations as 150 claims, one per distinct sentence, each quoted verbatim, 112 held by a named test class; - surface-waivers.json: every public member of the run-time libraries is claimed or waived; the documents never read for claims are waived as unread (#98); - oracles.json and seeds/: five oracles that already existed (JsonParityTests, NullDelegateTests, AsynchronousContextTests, NotWireTypeTests, KeyGenerationVariantTests), each with a seed; all five caught by `oracles seeds`, about ten seconds each; - candidates.json and axes.md; - test/CodoMetis.TypeKit.Oracles.Tests, which holds the catalogue in CI, and tools/Oracles, the local `seeds` and `status`. Decision 112 supersedes decisions 96, 99 to 104 and 108, decision 107 but for its fixture rule, and decision 97's gate. AGENTS.md, CONTRIBUTING.md and design/plan.md describe the kit. Stacked on #96 for the decision's number. Closes #97 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n static fields CodeAnnotations held seven AttributeConstruction objects in static readonly fields. An AttributeConstruction belongs to one compilation, and a static field outlives it: at design time, where the IDE keeps Metalama's process across edits, every compilation that filled the fields stays reachable. Gael Fraiteur of Metalama found it reviewing the project (metalama/Metalama discussion 2305); metalama/Metalama#2307 will detect the pattern, and is still open. Each is a static property with an expression body now, so the 78 call sites (AddAttribute(CodeAnnotations.CompilerGenerated) and the like) are unchanged, and so is the generated code: the generated-surface snapshot and the woven probes pass as before. CompileTimeStaticStateTests (conventions) holds every static field of .Generators, and every static auto-property with storage, to an allowlist of durable types: strings, Type, DiagnosticDefinition, and arrays, lists and tuples of those. [Template] members are introduced into the target and hold nothing. With the seven fields restored it fails, naming all seven. Input class: static storage in compile-time code. The test walks every source of .Generators; the other static storage there (the DiagnosticDefinitions, TypedConversionMethods, GeneratedMemberNames) is durable, so there was no sibling to fix. Defect class CRP: what it costs is memory over an IDE session, with no effect on what is generated. Closes #90 Defect-Class: CRP Found-By: OR Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ther assembly's interface FabricTests gains TestForeignIdentifier, declared in the Generators tests and reaching IValue<Guid> through IProbeIdentifier, an interface of the probes assembly. ProbeCustomerId covered a derived interface of the same assembly only. Whatever the fabric selects with, the chain through a type it did not compile is the one most likely to be missed, and a miss compiles silently. Seeded with a selection of direct implementations only (DerivedTypesOptions.DirectOnly over the index of derived types), the theory fails on it and on ProbeCustomerId. Refs #91 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Metalama.Testing.AspectTesting 2026.1.30 tests the real generators, internal aspects and TransitiveProjectFabric included, through a project reference. It runs on xunit v2 and VSTest, so it stays out of the solution's test run. - It runs as a project of its own with its own global.json, which keeps the SDK pin and drops the test key. `dotnet test` from the spike folder passes 4 of 4. From the root, the MTP selection refuses it. - In a scratch .slnx, one VSTest project makes `dotnet test --solution` refuse the whole run, so no other test runs. IsTestProject=false hides it from that run, but then VSTest's `dotnet test` also runs nothing and exits 0. - `dotnet vstest` on the built dll runs it from anywhere. CI would need one more step, which was not run. - A seeded defect in a scratch copy of src/ fails the two snapshots whose output it changes. - Plain, validated and closed-set shapes give 235 to 349 lines each. They are formatted but fully qualified, so they suit a review per member, not per file. - Reading them showed dead code after the return in every generated TryParse(string?): TryParseTemplate's meta.InsertStatement calls are still emitted after a compile-time return. Refs #93 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…osed set Gael Fraiteur of Metalama suggested showing the generated code for the simple cases (metalama/Metalama discussion 2305). The root README shows what OrderId gets, and the Generators README what Email and OrderStatus get, each in a collapsed block beside where the page declares it: the field, the private constructor, Value, From or TryFrom, FromKnownGood and Revalidate, CompareTo and ToString; for the closed set the static constructor that names the members, Name and Match. The blocks are trimmed, not pasted. The woven code is fully qualified, puts attributes on every member and casts on every returned expression: OrderId alone is about 200 lines, and AspectTesting's expected files are no shorter (spike, #93). So the check compares reading forms. The samples project sets MetalamaEmitCompilerTransformedFiles, and GeneratedCodeBlockTests (conventions) holds each block marked <!-- not compiled: generated code for {file}, trimmed (GeneratedCodeBlockTests) --> to the woven form of that sample file: every member shown, body included, and every interface of its base list, after both sides lose attributes, comments, namespace qualifiers, casts and this., and System.String reads as string. A block may leave members out, and says so in a comment. Seeded: a From body changed in the root README fails, printing the block's member and the generated one. A_member_that_differs_is_found holds the comparison to a wrong body, an extra member and an interface the woven base list lacks. Closes #92 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every generated TryParse(string?, IFormatProvider?, out TSelf) over a wrapped type with a TryParse of its own, or over a string, ended in a declaration of __inner and a try/catch (FormatException) after its return. TryParseTemplate returned from a compile-time if, which ends the run-time body, but the two meta.InsertStatement calls after it are compile-time code and still ran. Nothing reached the tail and it changed no behaviour, but it was in every value object that parses, and in the code the READMEs now show. The AspectTesting spike found it reading its expected output (#93). The three branches are an if-else chain now, so the InsertStatements run only in the last one: the strategies without a TryParse of their own (a type converter, a static Parse, a string constructor), whose body is unchanged. WovenReachabilityTests (conventions) reads the probes' woven files and fails on any statement after a return or a throw of the same block, a local function excepted. Before the fix it found 26, one per value object of the probes that parses; after it, none. A fixture pins what counts. Input class: the parse strategies. The probes hold each of them (string, enum, Uri, the primitives and dates, a span-parsable type, NodaTime through its type converter, a static Parse, a string constructor), and the four final-branch bodies are the same as before. The other template that calls InsertStatement, JsonConverterWriteTemplate, has no early return. Closes #100 Defect-Class: GTS Found-By: SF Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…atics fix: CodeAnnotations builds its attribute constructions on use, not in static fields
fix: a generated TryParse ends at its return, with no unreachable tail
…erface test: the fabric generates a value object whose marker comes through another assembly's interface
spike: Metalama.Testing.AspectTesting beside xunit.v3 on MTP
docs: the READMEs show the generated code for OrderId, Email and a closed set
feat: CatchAsync takes a ValueTask, and TraverseAsync reaches Option and Patch
feat: a fault mapping can withhold the fault's name from the problem
chore: retire the prober for ValueRanges' oracle kit
feat: a fault keeps the exception that caused it, for the log and never the problem
The changelog keeps every entry and the roadmap drops both items; the prober seed this branch edited is deleted, as #108 retired the prober. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat: assertions on a Task or ValueTask, and CMTK0003 reports one left unawaited
`oracles seeds` read any failed test as a catch, so a SQL Server fixture that never started (2022 under QEMU on an arm64 Mac) credited both SQL Server seeds while every test failed in `SqlServer.InitializeAsync`, and the tool exited 0. The tool now runs every oracle the selected seeds name on a copy with no seed first, built and filtered as the seeded runs are. A seed is CAUGHT only when its oracle passes there and fails with the seed in a test of its own. A run that never reached the tests is ERROR, exit 4, with or without the seed. The TRX decides that, as measured with xunit.v3 4.0.2: - a fixture that fails to set up fails each test with one of xunit's own messages; - a fixture that fails in Dispose is only an `error` counter; - a crashed host writes no TRX and exits other than 0 or 2; - a run whose every test is skipped ran nothing. A failing baseline is ERROR too. Decision 118 records the rule, and the README, CONTRIBUTING and AGENTS say what ERROR means at release. Input class: the ways a run fails outside a test's own code. SeedVerdictTests covers each kind measured above and every setup message xunit.v3.core 4.0.2 holds. With the setup check and the baseline seeded out, three of those tests fail, the dead fixture of #151 among them. Closes #151. Defect-Class: TOOL Found-By: OR Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs: the 2.3.0 changelog lists the Generators fixes, the generated code and the README introduction
…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>
#151 merges first and takes 0117, and the records are numbered in merge order, so this record becomes 0118: its file, heading, index rows and the links from design/analyzers.md and the roadmap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…assertions # Conflicts: # design/analyzers.md
fix: oracles seeds credits a seed only against a passing baseline
…3-new-api-forms # Conflicts: # design/adr/README.md
…Any of results The maintainer took #159 into 2.3.0: CMTK0003 reports a Task.WhenAny of tasks of results dropped without await, which code built on 2.2.0 can contain. Such a statement loses every result, so the report finds a defect. Decision 118, its index row, design/analyzers.md and the Analyzers README's "What a new version may change" name the exception beside the rule, so the README's promise stays true. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…orms docs: an Error may learn, in a minor version, a form only that version's new API writes
…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>
…sertions fix: CMTK0003 reports assertions and results lost through pass-throughs, branches and Task's combinators
…to the rest AGENTS.md loads into every agent session. Five sections repeated what another file holds or detailed what an agent needs only at one moment: - Finding code: the graph's measured gaps move to design/code-graph.md (new, linked from design/plan.md); AGENTS.md keeps the rule and the gaps in one line. - Commands: the BuildVerdict, BashGuard and session-start paragraph shrinks to what the verdict prints and what the guard refuses. - Issues: the label legend, epics and PR checks are CONTRIBUTING's; what stays is what trips agents here. - Workflow step 7: the oracle-kit mechanics are test/oracles/README.md's. - Releasing: CONTRIBUTING's "Releasing" holds the steps; the seeds, the arm64 image and the never-delete-a-seed rule stay. "Rules that are easy to break" is unchanged, and so is every heading another document cites. 22,230 to 17,956 characters, about 1.1k tokens less per session start. Conventions tests pass (2,002) and docs-query check is clean. Refs #167 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs: AGENTS.md keeps what an agent needs before it acts, and points to the rest
…s as planned A net11.0 asset joins a 2.x minor only with the net10.0 group's dependency floors (a higher floor is NU1605 for an application that holds the lower version, measured on SDK 11 RC1), a superset surface that needs no C# 15 to call, the same generated members on every target and LangVersion 14 until an implementation needs 15. The SDK 11 spike (#170) comes first. 3.0.0 stays C# 15 unions and the net10.0 drop, timed to .NET 12 LTS; refines decision 44. Closes #169 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A union new on net11.0 is an addition, not a second contract: measured on SDK 11 RC1, a net10.0 consumer sees nothing, a LangVersion 14 net11.0 consumer who holds the value builds, and one who matches on it gets CS9327. 3.0.0 keeps the net10.0 drop and the change of an existing contract. The record is renamed to say so; the dependency-floor rule is unchanged. Refs #169 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…gh catches that cannot keep them A Task.WhenAny inside a Task.WhenAll or a Task.Run completes with the faulted assertion as its value, so awaiting the outer task saw no failure and the rule said nothing (#165). HandsOn now returns how deep the root holds the failure instead of a bool: 0 where its task faults with it (WhenAll, Run), one more for each task that completes with it as a value (WhenAny, WhenEach, an async lambda that returns it), one fewer for each await that unwraps one. DroppedAssertion treats an awaited, waited-for or converted combinator as observing only a failure at depth 0, so the same path reports await Task.WhenAll(Task.WhenAny(...)), await Task.Run(() => Task.WhenAny(...)), their Wait() and plain-Task forms, at any depth, and keeps await await Task.WhenAny(...) silent. Task.WaitAll of a WhenAny was already reported once, at the WhenAny's conversion to a plain Task. A catch around an awaited assertion in an async lambda counted as observing the failure whatever it did (#166). EnclosingAsyncFunction now stops only at a catch that keeps it: the await is in its try block, its type is or is a base of TypeKitAssertionException (resolved in the Testing assembly by its metadata name), and its handler can complete (control flow: endpoint reachable, or a return/break leaves it). A constant false filter leaves the handler unreachable, so control flow already reads it as never completing: an explicit filter check, seeded, was caught by nothing, and is not kept. catch { throw; }, a log and throw;, throw new ..., catch (OperationCanceledException) and when (false) now report. A filter that is no constant counts as keeping the failure: an Error reports only a failure lost whatever the filter answers. Both forms are written only with 2.3.0's Testing API, so decision 0118 covers them; no 2.2.0 build reports more. Input class: AIS, an assertion's task lost by a statement. Variants/DroppedTaskShapes gains 42 forms, all assertion-only: every combinator inside each other, three and four deep, arrays, Selects and async lambdas of WhenAny that return it, await it once, twice and three times; every catch kind (try/finally, rethrow, log and rethrow, throw another, unrelated type, false filter, nested tries, await in a handler or a finally) against silent controls (catch all, catch the assertion's exception, true filter, opaque filter, conditional rethrow, return, a later clause, nested tries that keep it); and Task.WaitAll/WaitAny of nested combinators. 1837 cases, from 830. IgnoredOutcomeAnalyzerTests holds the issues' snippets and a look-alike TypeKitAssertionException of another type. Seeded 11 ways, each caught by DroppedTaskVariantTests (failing cases): the producer's depth (192), WhenAny's depth (168), an async lambda's return (48), await unwrapping (48), a catch's try block only (48), the exception type (48), the rethrow check (144), its exit points (24), the exception's metadata name (48), the base chain (240), and an unreachable handler read as completing, which turns the when (false) rows red (24). README (CMTK0003) says so; claims T03-a-nested-when-any-is-reported, T03-a-catch-that-cannot-keep-the-failure-is-reported and T03-an-unknown-filter-counts-as-catching quote it. Closes #165 Closes #166 Defect-Class: AIS Found-By: OR Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Metalama is one version for every target and TypeKit follows the maintained Metalama year in a minor (1.5.0 already raised the floor in one). The move is not only a restore error: a woven net11.0 project goes from C# 14 to 15, an unsupported IDE host fails silently, and Metalama 2027 drops Visual Studio 2022. The record lists the conditions (stable 2027.0, a license-free CI and clean-container build, the ceiling and the 2.4.x line documented), corrects the rule on the language version and the SDK, and adds the measurements. Refs #169, #170, #173 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The Semantic Versioning FAQ calls a dependency update with an unchanged public API compatible, so the first rule no longer refuses a higher floor in a minor, on every target or on net11.0 alone. The raise is documented instead: the changelog names the dependency, the floors, who it reaches (NU1605 for a project that holds the lower version) and both ways out, and the smoke test shows it. Metalama is the same rule on the dependency with the widest reach. The record is renamed to say so; the roadmap and the index row follow. Refs #169 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
docs: decision 120, a net11.0 target and documented floor raises join a 2.x minor
…-rethrow fix: CMTK0003 reports assertions lost in nested combinators and through catches that cannot keep them
The 2.3.0 section of CHANGELOG.md is dated 2026-10-29, and its links name blob/v2.3.0/, so the release notes open the pages as they were released. AnalyzerReleases.Shipped.md gets its "Release 2.3.0" header. 2.3.0 adds no rule: CMTK0003 and CMTK0009 widen rules shipped earlier, and Unshipped.md is empty. The empty "Release 2.2.0" header goes: Roslyn's release tracking refuses any header after an empty release (RS2007, measured with 2.3.0 empty and with 2.3.0 carrying a changed rule), so 2.2.0's header would have failed this release and every later one. CONTRIBUTING's step 3 says so. Closes #174 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs: close 2.3.0: the changelog dated, the analyzer release recorded
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 #67
Release 2.3.0 into main
The changelog's 2.3.0 section, dated 2026-10-29, is the release notes: async Testing assertions held by CMTK0003,
Fault.CauseandWithoutFaultName(),IAsyncEnumerableandOption/Patchtraversal, inline value-object schemas, the Add Create code fix, SQL Server oracles, the docs site and walkthrough.Checked locally on
release/2.3.0before the tag (CONTRIBUTING, "Releasing", step 1):oracles seeds: every seed caught, every baseline passing without its seed, the SQL Server oracles included (exit 0).docs-query due --nuget: no fact due (0 of 34 pinned external).The last topics were #171 (decision 120), #172 (CMTK0003, #165 and #166) and #175 (the changelog dated, the analyzer release recorded). The tag goes on this PR's merge commit.
🤖 Generated with Claude Code