Repository navigation
Epic: 5.5.0 — EFCore.ComplexIndexes stays the EF Core 10 package #36
Description
Goal
Decided 2026-10-19; this replaces the 10.0.0 rename the epic held until then.
The existing ids stay on EF Core 10 / .NET 10 (LTS, supported to 2028-11). They are not renamed or renumbered. The rename happens at the EF Core 11 boundary instead, as a new package, CodoMetis.EFCore.SchemaKit, starting at 11.0.0 (#37).
That way a consumer swaps packages once, in the same upgrade in which they move to EF Core 11 and its native complex-type indexes. The old plan had them rename on EF Core 10 and rewrite again on 11.
5.5.0 is the last minor with a change of its own: it makes the line refuse EF Core 11. After it, release/5.x takes fixes only. The features ROADMAP.md planned for 5.5.0 (4.1 descriptor differ, 4.2 delete constraints, 4.3) move to SchemaKit.
In scope
- Refuse EF Core 11 at registration: EFCore.ComplexIndexes serves EF Core 10 only #55: refuse EF Core 11 at registration; the bug form and the READMEs point EF Core 11 users to SchemaKit.
- Every finding of the 5.5.0 pre-tag analysis and consumer probe, decided 2026-10-20. They were filed under 5.5.1 and 5.6.0, but 5.5.0 is not tagged yet, so each ships here:
- Loud bugs and test gaps (patch-eligible, but nothing waits for a patch): Typed exclusion-constraint filters on non-string JSON members fail at apply (text > integer) #78, Dropping both tables of a temporal foreign key fails when the principal sorts first, Down() included #79, Typed filters: char comparisons render an integer, and HasValue and other scalar members fail at migrations add, not at the declaration #80, btree_gist is injected only for gist with '=', and UseMethod("GiST") skips it #81, Index and constraint names are not checked against table, view and sequence names in the schema #82, SQL Server: a second clustered complex index in a later migration, and an index named like the table's key, fail only at apply #90, EF Core major guard: registering the differ by hand bypasses it and fails with MissingMethodException #91 (a way around Refuse EF Core 11 at registration: EFCore.ComplexIndexes serves EF Core 10 only #55's guard), Fractional index storage parameters render with the current culture on the stock Npgsql path #97, and the guards Tests: ten seeded defects in the PostgreSQL satellite that the suite does not catch #83 and Tests: seeded defects in the core and SQL Server differs that the suite does not catch, and the model-less SQL Server rendering #96 (Tests: seeded defects in the core and SQL Server differs that the suite does not catch, and the model-less SQL Server rendering #96 also fixes the harness trap that hid SQL Server: a unique complex index over nullable columns admits only one row without a value #88).
- Silent bugs The core differ silently drops SQL Server and Npgsql index options when it diffs a model a satellite should #92, TPC with a concrete base: complex indexes, exclusion and temporal constraints land on the base table only #93 and Typed expression indexes: string concatenation with a nullable operand differs from EF Core (COALESCE) #94. Each needs a minor with
### Changed answers, and 5.5.0 is already that minor. It already movesCustomIndex:RenderingVersionto 3, so consumers re-create indexes and rewrite the snapshot once instead of twice. - SQLite: re-create complex indexes after a table rebuild instead of refusing the migration #95 (SQLite re-creates complex indexes after a table rebuild), last. After the tag
release/5.xtakes fixes only, so it is 5.5.0 or never on 5.x. If its design stalls, close it as won't-do on 5.x and keep SQLite: a migration that rebuilds a table silently drops every complex index on it #86's refusal; SchemaKit does not need it, because EF Core 11 indexes complex properties itself.
- Two test layers the 5.5.0 findings show missing, decided 2026-10-20. Shipping code is at 93% of lines and 82% of branches, yet those findings failed only at apply or differed from EF Core's own translation:
- Tests: a SQL Server integration lane that applies migrations to a live server #100: a SQL Server integration lane that applies migrations to a live server (SQL Server: ALTER COLUMN on a column under a complex index fails at apply (Msg 5074) #84, SQL Server: a unique complex index over nullable columns admits only one row without a value #88 and SQL Server: a second clustered complex index in a later migration, and an index named like the table's key, fail only at apply #90 failed only there).
- Tests: sweep typed filters and typed expression indexes against EF Core's ToQueryString #101: a parity sweep of typed filters and typed expression indexes against
ToQueryString()(Typed filters use SQL null semantics: != and ! on a nullable operand drop NULL rows, a captured null renders = NULL #68, Typed filters double braces in string literals: x.Code != "{draft}" renders '{{draft}}' #70, Typed expression indexes render Substring and Trim differently from EF Core's queries, so no query uses them #72 and Typed expression indexes: string concatenation with a nullable operand differs from EF Core (COALESCE) #94 were each found by hand).
- CI the 5.x line needs before
release/5.xis cut, from the CI/CD scope analysis (2026-10-20):- CI: one gate job as the only required build check #110: one gate job as the only required build check, so
release/5.xcopies one check and a new lane needs no protection edit. - Release: run the full CI before publishing, and a nightly full run #111:
release.ymlruns every CI lane before it publishes, a nightly full run, and the SDK pinned inglobal.json. A fixes-only line sees few PRs, so drift has to be caught without them. - CI: select the PostgreSQL, SQL Server, consumer and pack lanes from a derived map #112 (lane selection, and the SQL Server lane's own test project) moved to 11.0.0 under Epic: CodoMetis.EFCore.SchemaKit 11.0.0 — the EF Core 11 successor #37: on a fixes-only line it saves little.
- CI: one gate job as the only required build check #110: one gate job as the only required build check, so
- docs: adopt the CodoMetis.ValueRanges changelog form #98: the changelogs adopt the CodoMetis.ValueRanges form, so the 5.5.0 notes are the first in it.
- Tag
v5.5.0, then cutrelease/5.xat the tag withmain's branch protection. After that,mainbecomes the SchemaKit line (SchemaKit 11.0.0-preview.1: the first slice of the new API, on EF Core 11 / Npgsql 11 under the new ids #38).
Out of scope
- Features, SQLite: re-create complex indexes after a table rebuild instead of refusing the migration #95 excepted (it removes the cost SQLite: a migration that rebuilds a table silently drops every complex index on it #86's refusal puts on SQLite users). Features go to SchemaKit.
- Deprecating the ids on nuget.org. That happens only when EF Core 10 leaves support, with SchemaKit as the alternate. Deprecating now would tell EF Core 10 users not to use the only package that serves them.
Done when
- Every sub-issue is closed (or SQLite: re-create complex indexes after a table rebuild instead of refusing the migration #95 closed as won't-do on 5.x).
- 5.5.0 is on NuGet.
release/5.xis cut atv5.5.0and protected likemain.ROADMAP.mdsays the same (Rewrite ROADMAP.md for the SchemaKit spin-off: D3–D11 decided #41).
Activity
[-]Epic: 10.0.0[/-][+]Epic: 5.5.0 — EFCore.ComplexIndexes stays the EF Core 10 package[/+]CaffeinatedCoder commentedon Oct 19, 2026
After #62 merges: release and cut steps for the maintainer
#62 (closes #55) carries the guard and opens 5.5.0. The steps below are the maintainer's: the tag, the
nugetapproval and the repository settings. I read the settings on 2026-10-19.1. Tag and publish
git switch main && git pull --ff-only git tag v5.5.0 git push origin v5.5.0release.ymlrunsverify(the full suite, then pack). Approve thenugetenvironment andpublishpushes the three packages.releasethen creates the GitHub release from## 5.5.0and attaches the SBOMs. The environment's deployment policy already allowsv*tags, so laterv5.5.xtags fromrelease/5.xneed no change.2. Cut
release/5.xat the taggit push origin v5.5.0^{commit}:refs/heads/release/5.xdotnet.ymlandpr-hygiene.ymlalready run onrelease/**.3. Copy
main's branch protection torelease/5.xAs read from
main: strict status checksTest (ubuntu-latest),Pack,Integration (PostgreSQL 18)andConsumer smoke test; PR required with 0 approvals; admins enforced; no force pushes, no deletions.Approvals stay at 0, as on
main. The tag ruleset "Release tags are immutable" already covers everyv*tag.4. Open 5.5.1 on
release/5.x, in the first PR into itMove
Versionto 5.5.1 andPackageValidationBaselineVersionto 5.5.0. In SECURITY.md, change the table to5.5.x ✅/< 5.5 ❌.SecurityPolicyConsistencyTestsholds that row to the baseline, so it moves in the same commit.5.
mainbecomes the SchemaKit line (#38)From here
maintakes no more 5.x work. #38 lists what changes there: the ids,net11.0, the version, docs and publishing. Two things from #62 that #38 has to handle onmain:EfCoreVersionGuardrefuses every EF Core major except 10. Onmainit has to go, or move to the SchemaKit major.10.x-only "EF Core version" field point at SchemaKit. Onmainthey belong to SchemaKit's own README and form.CONTRIBUTING.md's "Branches and releases" section and AGENTS.md still describe the old 10.0.0 rename and the
net11branch. #38 lists CONTRIBUTING's branch section; AGENTS.md's "Branches" bullet needs the same rewrite.49 remaining items
CaffeinatedCoder commentedon Oct 20, 2026
Pre-tag gate, 5.5.0 (
v5.4.1..934ec55)Verdict: hold the tag until #150 and #151 are settled, and #141, #142, #144 and #145 (with #143) have landed. Their PRs #146–#149 are open.
Hold the tag
UseComplexIndexes()on Npgsql or SQL Server still drops the exclusion constraint, the temporal constraint, the temporal FK and SQL Server: a unique complex index over nullable columns admits only one row without a value #88'sIS NOT NULLfilter, and applies cleanly. The core differ silently drops SQL Server and Npgsql index options when it diffs a model a satellite should #92 refuses only index options. Fixing this later changes an answer, whichrelease/5.xcannot ship.blob/main, which becomes SchemaKit after the tag. Published nupkgs cannot be changed.Before the tag, but not blocking it: docs #152, #153, #154; tests #155, #156, #157. The tests are the three seeded defects the 569-test unit suite did not catch.
Clean
docs/upgrading.mdexactly, and the second was empty. On PostgreSQL 18, the 5.4.1 create script, then Up → Down → Up, all applied, and the derived TPC table enforced its index and constraint (23505, 23P01).Not covered: SQL Server live apply (amd64 image), Windows MSBuild
.targets.Doubts, not filed
PRAGMA foreign_keys. EF's own indexes have the same limitation.release/5.xrun shares a concurrency group with pushes, so a cancelled run might open a spurious "Nightly CI failed" issue.CodoMetis.EFCore.SchemaKit.SqlServer, the guard message saysCodoMetis.EFCore.SchemaKit.CaffeinatedCoder commentedon Oct 20, 2026
Pre-tag sweep, 5.5.0 (
934ec55..eff80b4)I ran five lenses over the fixes since the gate (#146–#149, #162), #158, and the docs and tests (#159, #160, #165, #166). I reproduced every issue below on eff80b4 myself.
Verdict: hold the tag for #167 and #170. Settle #168 and #169 before the tag too, because the answer goes into the published packages.
Holds the tag
Trim/Substringare re-created, and theTrimfilter changes which rows it covers. The guide and the### Changed answersrow mention expression indexes only. The changelog is packed as the release notes.Decide before the tag
migrations add. The guide says these copies are shortened. An explicit name works around it.UseNpgsqlComplexIndexes(). The satellites'>=dependency on core goes into the 5.5.0 nuspecs. A pin to[5.5.0]is cheap now and impossible later.Before the tag, not blocking
IsCreatedConcurrently()copies, whose commands run outside the transaction.migrations addfails. A 5.5.x patch can move the refusal earlier.Clean
v5.5.0and resolve, anchors included.consumer-smoke-test.shpassed in both modes.ImplicitFilterall agree.Not covered: SQL Server live apply (none of the findings needed it, so nothing was dispatched), Windows MSBuild, an EF Core 11 refusal from a packed consumer, and the README's C# samples compiled verbatim.
Doubts, not filed
~to~1when a sibling table sorts first. That rebuilds a copy through drop/create, which is correct but unneeded.…_not_nullconstraint name would pass every check. Not reproduced.CaffeinatedCoder commentedon Oct 20, 2026
5.5.0 released (2026-10-20)
v5.5.0on 490b4de. The release run passed every lane (unit, PostgreSQL 16 and 18, SQL Server 2022, newest EF Core patch, consumer smoke test, pack), then verify, publish and the GitHub release.v5.5.0. The satellites pin the core at exactly[5.5.0].v5.5.0is Latest, with the three CycloneDX SBOMs attached.release/5.x: cut at the tag and protected likemain, with the single required checkCI(strict, admins enforced, no force pushes or deletions). It prepares 5.5.1 since chore: open 5.5.1 on release/5.x #178 (Open 5.5.1 on release/5.x #177).Done-when, checked:
release/5.xis cut atv5.5.0and protected likemain.Next on this line: 5.5.1 takes fixes only (#137, #161).
mainbecomes the SchemaKit line (#38).