Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
26882e5
build: open 2.3.1 from v2.3.0, and move the package-validation baseli…
CaffeinatedCoder Oct 30, 2026
4a3d9a6
fix: refuse an explicit implementation of a generated member wherever…
CaffeinatedCoder Oct 30, 2026
72bb05c
fix: refuse a value object's Equals of a base record's type
CaffeinatedCoder Oct 30, 2026
e606d64
fix: refuse a base record's public generated member and name a public…
CaffeinatedCoder Oct 30, 2026
03e199b
fix: refuse a base record's Create that generic T.Create reaches besi…
CaffeinatedCoder Oct 30, 2026
a019677
Merge pull request #200 from CaffeinatedCoder/build/open-2-3-1
CaffeinatedCoder Oct 30, 2026
5f5ad55
fix: refuse a seam a base record declares in place of the value object
CaffeinatedCoder Oct 30, 2026
319de43
Merge remote-tracking branch 'origin/release/2.3.1' into ci-fix/inter…
CaffeinatedCoder Oct 30, 2026
d08c987
Merge remote-tracking branch 'origin/release/2.3.1' into ci-fix/hand-…
CaffeinatedCoder Oct 30, 2026
8fac39b
Merge pull request #201 from CaffeinatedCoder/fix/interface-explicit-…
CaffeinatedCoder Oct 30, 2026
e29bbf9
Merge branch 'release/2.3.1' into fix/hand-written-equals-tbase-refus…
CaffeinatedCoder Oct 30, 2026
70e3d8b
Merge pull request #202 from CaffeinatedCoder/fix/hand-written-equals…
CaffeinatedCoder Oct 30, 2026
a0830a7
Merge branch 'release/2.3.1' into fix/inherited-seam-refused-2-3-1
CaffeinatedCoder Oct 30, 2026
fb11acf
Merge pull request #203 from CaffeinatedCoder/fix/inherited-seam-refu…
CaffeinatedCoder Oct 30, 2026
f714c5d
fix: refuse a value-object contract declared through an interface or …
CaffeinatedCoder Oct 30, 2026
dbdd44e
Merge pull request #204 from CaffeinatedCoder/fix/value-object-contra…
CaffeinatedCoder Oct 30, 2026
a3f72f5
fix: CMTK0005 and CMTK0006 report a new()-constrained value-object pa…
CaffeinatedCoder Oct 30, 2026
3d2abfd
fix: refuse ordering a value object with its own CompareTo that a pro…
CaffeinatedCoder Oct 30, 2026
9f749a4
fix: refuse a closed set's base-class member the generators introduce…
CaffeinatedCoder Oct 30, 2026
d573eef
fix: refuse ordering a boxed value object read back through ?? or a p…
CaffeinatedCoder Oct 31, 2026
8562de6
fix: refuse ordering a boxed value object a grouping, a join or a sub…
CaffeinatedCoder Oct 31, 2026
dba724c
fix: CMTK0005 stays silent on an array with a constant zero in any di…
CaffeinatedCoder Oct 31, 2026
1e81f02
fix: CMTK0005 reads a zero length of any integral type as zero
CaffeinatedCoder Oct 31, 2026
52572fb
fix: let a query filter order the context's own values without a lambda
CaffeinatedCoder Oct 31, 2026
fbfb8ef
fix: keep an overload of a generated member that differs by arity or …
CaffeinatedCoder Oct 31, 2026
27d7cc0
fix: CMTK0005 reports Array.CreateInstance, CreateInstanceFromArrayTy…
CaffeinatedCoder Oct 31, 2026
b2931de
fix: CMTK0006 counts an assignment through a cast of this, mapped to …
CaffeinatedCoder Oct 31, 2026
b699d74
fix: a generic or by-reference overload of a seam or a synthesized me…
CaffeinatedCoder Oct 31, 2026
8bae037
fix: CMTK0006 no longer counts an initializer of another object as as…
CaffeinatedCoder Oct 31, 2026
2ec8b72
fix: describe each element of a list or a dictionary of patches as a …
CaffeinatedCoder Oct 31, 2026
bb8922f
fix: describe a nullable patch as its argument admitting null, not as…
CaffeinatedCoder Oct 31, 2026
7961c35
docs: record KB-057, a nullable contract's element type and its null
CaffeinatedCoder Oct 31, 2026
c1c6e3d
fix: a base's private member of a generated name is hidden from the v…
CaffeinatedCoder Oct 31, 2026
c855caa
Merge pull request #216 from CaffeinatedCoder/fix/no-default-new-cons…
CaffeinatedCoder Oct 31, 2026
48af3f2
Merge pull request #218 from CaffeinatedCoder/fix/closed-set-base-mem…
CaffeinatedCoder Oct 31, 2026
45db0a1
Merge pull request #217 from CaffeinatedCoder/fix/ef-boxed-ordering-r…
CaffeinatedCoder Oct 31, 2026
2e60d4c
Merge pull request #233 from CaffeinatedCoder/fix/zero-dimension-arra…
CaffeinatedCoder Oct 31, 2026
3ed21e1
Merge remote-tracking branch 'origin/release/2.3.1' into HEAD
CaffeinatedCoder Oct 31, 2026
773dc9a
Merge remote-tracking branch 'origin/release/2.3.1' into HEAD
CaffeinatedCoder Oct 31, 2026
ab8e85b
Merge remote-tracking branch 'origin/release/2.3.1' into HEAD
CaffeinatedCoder Oct 31, 2026
19bb13d
test: keep the claims sorted by id, as OracleCatalogueTests requires
CaffeinatedCoder Oct 31, 2026
4bcbf80
test: keep the claims sorted by id, as OracleCatalogueTests requires
CaffeinatedCoder Oct 31, 2026
88ae0fe
Merge pull request #243 from CaffeinatedCoder/fix/explicit-interface-…
CaffeinatedCoder Oct 31, 2026
cc72fa4
Merge pull request #237 from CaffeinatedCoder/fix/patch-container-sch…
CaffeinatedCoder Oct 31, 2026
c506852
Merge remote-tracking branch 'origin/release/2.3.1' into fix/ef-filte…
CaffeinatedCoder Oct 31, 2026
3e6aa36
Merge remote-tracking branch 'origin/release/2.3.1' into HEAD
CaffeinatedCoder Oct 31, 2026
3fd7867
Merge remote-tracking branch 'origin/release/2.3.1' into HEAD
CaffeinatedCoder Oct 31, 2026
bdf961d
test: run the analyzer sweeps' rows in parallel, and leave the pragma…
CaffeinatedCoder Oct 31, 2026
c8fb57c
Merge pull request #250 from CaffeinatedCoder/test/analyzer-sweeps-pa…
CaffeinatedCoder Oct 31, 2026
0df62c1
test: run the EF Core query sweeps' rows in parallel, and create each…
CaffeinatedCoder Oct 31, 2026
f25a8d1
test: run the EF Core rows one collection at a time again, keeping th…
CaffeinatedCoder Oct 31, 2026
abe2763
Merge pull request #252 from CaffeinatedCoder/test/linux-leg-sweeps-2…
CaffeinatedCoder Oct 31, 2026
921c32c
Merge pull request #234 from CaffeinatedCoder/fix/ef-filter-captured-…
CaffeinatedCoder Oct 31, 2026
6706e17
build: merge release/2.3.1 into fix/array-factories-reported-2-3-1
CaffeinatedCoder Oct 31, 2026
ec40a3f
Merge pull request #235 from CaffeinatedCoder/fix/array-factories-rep…
CaffeinatedCoder Oct 31, 2026
c056511
build: merge release/2.3.1 into fix/generic-or-ref-overload-refused-2…
CaffeinatedCoder Oct 31, 2026
252c43f
Merge pull request #236 from CaffeinatedCoder/fix/generic-or-ref-over…
CaffeinatedCoder Oct 31, 2026
79f215f
build: merge release/2.3.1 into fix/private-base-member-refused-2-3-1
CaffeinatedCoder Oct 31, 2026
bce9e84
Merge pull request #244 from CaffeinatedCoder/fix/private-base-member…
CaffeinatedCoder Oct 31, 2026
fdd3ac2
docs: close 2.3.1: the changelog dated, the analyzer release recorded
CaffeinatedCoder Oct 31, 2026
24a05f5
Merge pull request #255 from CaffeinatedCoder/docs/release-2-3-1-closing
CaffeinatedCoder Oct 31, 2026
72d96f2
build: merge main into release/2.3.1, keeping 2.3.1's version and cha…
CaffeinatedCoder Oct 31, 2026
e9c375b
Merge pull request #257 from CaffeinatedCoder/build/release-2-3-1-tak…
CaffeinatedCoder Oct 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,30 @@ A version's heading reads `## <version> — Unreleased` until the release is pre
the release date. The release workflow refuses a tag whose section still says `Unreleased`, and the
section is the GitHub release's notes.

## 2.4.0 — Unreleased
## 2.3.1 — 2026-10-31

### Changed

- Packages: the public surface is checked against 2.3.0's, so nothing 2.3.0 ships is removed or changed in 2.4.0.
- Packages: the public surface is checked against 2.3.0's, so nothing 2.3.0 ships is removed or changed in 2.3.1.
- Analyzers: CMTK0005 and CMTK0006 now warn for a type parameter bound by a value object beside `new()`, as in `where T : IValue<int>, new()`, which CMTK0001 already reported: `new T[n]` and a `T` field nothing sets. In a build that treats warnings as errors, that can report code that built before ([CMTK0005](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/v2.3.1/src/CodoMetis.TypeKit.Analyzers/README.md#cmtk0005)).
- Generators: a generated member you wrote where a value object reaches it now fails the build (CMTK1011, CMTK1008 for comparison), so your build can fail when you upgrade: an explicit implementation such as `IFormattable.ToString` in an interface a value object or closed set implements, one in a base record from another project, a base record's public `MinValue` or `MaxValue`, which stood in for the generated one, and a base record's `Create` beside your own. Remove it, don't implement that interface, or declare the marker on the value object itself. A base record's public `Value`, `Parse`, `ToString(string?, IFormatProvider?)` and the like, and `IConvertible` through an interface, now fail with a CMTK error rather than a Metalama crash ([Write your own members](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/v2.3.1/src/CodoMetis.TypeKit.Generators/README.md#write-your-own-members)).
- Generators: an `Equals` a value object declares for one of its base records' types, such as `Equals(DeepBase?)`, now fails the build (CMTK1011), so your build can fail when you upgrade. A `HashSet<DeepBase>` compared by it while `==` compared the underlying value; normalise values in `Create` instead ([Equality](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/v2.3.1/src/CodoMetis.TypeKit.Generators/README.md#equality)).
- Generators: a `CompareTo(TSelf)`, `CompareTo(object)`, `TryFrom` or `Revalidate` a value object inherits from a base record now fails the build (CMTK1008, CMTK1011), so your build can fail when you upgrade. It stood in for the generated member: an inherited `CompareTo` made `<` overflow the stack and an EF Core query order by the column, and an inherited `TryFrom` need not run `Create`. Declare it on the value object ([Write your own members](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/v2.3.1/src/CodoMetis.TypeKit.Generators/README.md#write-your-own-members)).
- Generators: a closed set over a base class that declares a member the generators add now fails the build with CMTK1011 naming it, where it failed with a Metalama error that named nothing you wrote: its `Parse`, `TryParse`, `Match` or `All`, and an `IParsable<TSelf>` it implements. A base class's `ToString()` that isn't sealed now fails the build too (CMTK1011), so your build can fail when you upgrade: the generated `ToString()` replaced it without a word. Declare `ToString()` in the set, or seal the base's, which is then kept ([Closed sets](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/v2.3.1/src/CodoMetis.TypeKit.Generators/README.md#closed-sets)).
- Generators: `IValueObject<TSelf, T>`, `IValueObjectMaterializer<TSelf, T>` or `IPlainValueObject<TSelf, T>` declared through an interface of yours, such as an `IEntityId<TSelf> : IValueObject<TSelf, Guid>`, or by a base record now fails with CMTK1011 naming that interface, where it failed with a Metalama error (LAMA0512) that named nothing you wrote. To constrain generic code, use `IValueObject<TSelf, T>` itself ([Write your own members](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/v2.3.1/src/CodoMetis.TypeKit.Generators/README.md#write-your-own-members)).
- EF Core: `Min`, `Max`, `Order`, `OrderDescending` or `OrderBy(x => x)` over a value object with its own `CompareTo`, cast to `object` first, as in `Select(o => (object)o.Priority).Max()`, or read back through `??`, a member of a projection, a grouping's key, a join or a subquery's `First()`, as in `Select(o => new { Key = (object)o.Priority }).OrderBy(a => a.Key)`, now throws as the same query without the cast does. EF dropped the cast and answered the column's order, the opposite of memory's for a descending `CompareTo` ([Queries](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/v2.3.1/src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries)).
- Analyzers: CMTK0006 now warns when a constructor sets a member only on another object it creates, `new Order(...) { Id = id }` or `other with { Id = id }`, which it took as setting its own. In a build that treats warnings as errors, that can report code that built before ([CMTK0006](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/v2.3.1/src/CodoMetis.TypeKit.Analyzers/README.md#cmtk0006)).
- EF Core: a query filter that orders values your context holds without a lambda, as in `HasQueryFilter(o => o.Priority == Limits.Max())`, builds again; EF works it out in memory by your `CompareTo`. With a lambda, EF orders those values in the database, and the filter still fails ([Queries](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/v2.3.1/src/CodoMetis.TypeKit.EntityFrameworkCore/README.md#queries)).
- Analyzers: CMTK0005 now also warns at `Array.CreateInstance(typeof(OrderId), n)`, `Array.CreateInstanceFromArrayType(typeof(OrderId[]), n)` and `ArrayPool<OrderId>.Rent(n)`, which create default slots as `new OrderId[n]` does. In a build that treats warnings as errors, that can report code that built before ([CMTK0005](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/v2.3.1/src/CodoMetis.TypeKit.Analyzers/README.md#cmtk0005)).
- Generators: an overload of a generated member that C# tells apart by its type parameters, or by a parameter that is `ref`, `in` or `out` where the generated one's isn't (or the other way round), is now kept beside the generated member, on a value object, a closed set or a base of either, where the build failed with CMTK1011: a `Parse<TFormat>(string, IFormatProvider?)`, a `From(in int)`, a `TryParse` whose last parameter isn't `out` ([Write your own members](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/v2.3.1/src/CodoMetis.TypeKit.Generators/README.md#write-your-own-members)).
- Generators: a generic `ToString<TFormat>()`, or a generic or by-`in` `CompareTo(TSelf)`, is no longer taken for the one you may write: a value object printed what a record prints (`Level { Value = 3 }`), a closed set its type name, and the ordering was marked hand-written, so EF Core refused to order by it. A generic or by-reference overload of `TryFrom`, `Revalidate`, `CompareTo(object)`, `Equals`, `GetHashCode` or `PrintMembers` is kept beside the generated member, where the build failed with CMTK1011 or CMTK1008 ([Write your own members](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/v2.3.1/src/CodoMetis.TypeKit.Generators/README.md#write-your-own-members)).
- Generators: a member of a base record or of a closed set's base class that the type can't see, a `private` one such as a `private const int MaxValue`, doesn't count as its own: it stands in for no generated member, so the checks above leave it alone and the type is generated as in 2.3.0 ([Write your own members](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/v2.3.1/src/CodoMetis.TypeKit.Generators/README.md#write-your-own-members)).

### Fixed

- Analyzers: CMTK0005 no longer reports an array with a constant zero in any one dimension, such as `new OrderId[0, count]`, or a zero written as `0L` or, in a `stackalloc`, `(byte)0`: neither holds an element ([CMTK0005](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/v2.3.1/src/CodoMetis.TypeKit.Analyzers/README.md#cmtk0005)).
- Analyzers: CMTK0006 no longer reports an explicit interface implementation that every constructor assigns through a cast, `((IHasId)this).Id = id` ([CMTK0006](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/v2.3.1/src/CodoMetis.TypeKit.Analyzers/README.md#cmtk0006)).
- OpenAPI: each element of a list, an array or a dictionary of `Patch<T>` is described as a patch property is, the argument's schema admitting null, where it admitted anything. A nullable `Patch<T>?` is its argument's schema admitting null, where it was an empty required component; System.Text.Json reads a null there as a `null` patch, as it reads a property left out ([Use it in an endpoint and in the document](https://github.com/CaffeinatedCoder/CodoMetis.TypeKit/blob/v2.3.1/docs/merge-patches.md#use-it-in-an-endpoint-and-in-the-document)).

## 2.3.0 — 2026-10-29

Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>2.4.0</Version>
<Version>2.3.1</Version>
<Authors>CaffeinatedCoder</Authors>
<Copyright>Copyright (c) 2026 CaffeinatedCoder</Copyright>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ your projects. Thanks to the Metalama team.

## Status

2.3.0 is the current version. 1.0.0, released on 28 September 2026, was the first.
2.3.1 is the current version. 1.0.0, released on 28 September 2026, was the first.
[Migrating from 2.0 to 2.1](docs/migrating-to-2-1.md) lists what builds or runs differently since 2.0,
and [Migrating from 1.5 to 2.0](docs/migrating-to-2.md) what changed since 1.5.

Expand Down
Loading
Loading