Skip to content

Migrate solution net7.0 β†’ net9.0 with six-gate parity report - #72

Open
devin-ai-integration[bot] wants to merge 7 commits into
mainfrom
devin/1787837283-net9-parity-migration
Open

devin-ai-integration[bot] wants to merge 7 commits into
mainfrom
devin/1787837283-net9-parity-migration

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Aug 27, 2026

Copy link
Copy Markdown

Summary

Migrates all six projects from net7.0 to net9.0 and proves parity via a self-contained parity-report/index.html covering six gates: build, unit tests, static analyser, smoke test, golden snapshot diff (20 itemised flows), and EF migration SQL parity. Legacy baselines were captured on the untouched net7 code and committed before any migration edit; every gate was re-run on net9 and diffed against them. All gates are green β€” the only differences are documented, inherent .NET 9 framework changes (no integration test project added).

Key changes beyond the TFM/package bumps (EF Core 9.0.19, Npgsql 9.x, Mapster 10, xunit 2.9.3, FakeItEasy 9, test SDK 18.9):

  • Directory.Build.props (new): EnableNETAnalyzers + AnalysisLevel=latest + TreatWarningsAsErrors β€” the static-analyser gate. Net9 builds with 0 warnings/0 errors (legacy had 3 warnings).
  • Swashbuckle.AspNetCore pinned to 9.0.6, not 10.x: v10 pulls Microsoft.OpenApi 2.x, which throws TypeLoadException at runtime with Microsoft.AspNetCore.OpenApi 9.0.x.
  • Program.cs: connection string resolved once and null-guarded (?? throw new InvalidOperationException(...)) β€” fixes CS8604 under warnings-as-errors.
  • SampleDbContext: HasData seed changed from Guid.NewGuid() to the stable GUID already in the committed migration; EF Core 9 rejects nondeterministic seeds with PendingModelChangesWarning.
  • Controller signatures intentionally unchanged (non-nullable [FromBody] EducationDto) to preserve the legacy 400 ModelState bodies; the two test call sites use null! instead.
  • Dockerfile images β†’ 9.0; workflow dotnet-version fixed 6.0.x β†’ 9.0.x, actions bumped to v4.

Parity verdicts (scripts/parity/ capture/diff/report tooling, artifacts under parity-report/):

  • 20/20 flows status-identical; 10 exact body matches, 10 "justified" diffs limited to inherent .NET 9 changes (ProblemDetails type URLs RFC 7231 β†’ RFC 9110; System.Text.Json reworded its missing-required-properties message).
  • Swagger: identical endpoints/schemas; only OpenAPI 3.0.1β†’3.0.4, Successβ†’OK descriptions, explicit required[], default style omission.
  • EF DDL: semantically identical (EF9 drops redundant explicit NULL; migrations-history ProductVersion reflects the EF9 tool).

Open parity-report/index.html directly in a browser β€” single file, inline CSS, no external deps, regenerable via scripts/parity/generate_report.py.

Link to Devin session: https://app.devin.ai/sessions/5612e1dd80b241f7b8c74330e2cbc8ef
Open in Devin Desktop: https://app.devin.ai/desktop/session/5612e1dd80b241f7b8c74330e2cbc8ef?variant=devin
Requested by: @detectiveharree


Note

Devin errored when opening this Pull Request as detectiveharree.
As a fallback, Devin opened this PR as itself.


Devin Review

Status Commit
βšͺ Not started β€”

Run Devin Review

Devin Review (Staging)

devin-ai-integration Bot and others added 7 commits August 27, 2026 13:30
Co-Authored-By: harrison.reeves <harrisonreeves00@gmail.com>
Co-Authored-By: harrison.reeves <harrisonreeves00@gmail.com>
Co-Authored-By: harrison.reeves <harrisonreeves00@gmail.com>
Co-Authored-By: harrison.reeves <harrisonreeves00@gmail.com>
Co-Authored-By: harrison.reeves <harrisonreeves00@gmail.com>
Co-Authored-By: harrison.reeves <harrisonreeves00@gmail.com>
Co-Authored-By: harrison.reeves <harrisonreeves00@gmail.com>
@devin-ai-integration

Copy link
Copy Markdown
Author

πŸ€– Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

βœ… I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

βš™οΈ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

Devin Review

new Education
{
Id = Guid.NewGuid(),
Id = new Guid("c92ea179-dd5c-46ca-b7b5-b44a191b974c"),

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ“ Info: Seed GUID matches migration and snapshot

The HasData seed changed from Guid.NewGuid() to a fixed GUID that already matches both the migration and SampleDbContextModelSnapshot, so the model is consistent and no pending-model-changes warning arises.

Devin Review

Was this helpful? React with πŸ‘ or πŸ‘Ž to provide feedback.

Comment on lines +26 to +28
(re.compile(r"was missing required properties, including the following: \w+.*"
r"was missing required properties including: '\w+'\."),
"System.Text.Json reworded the missing-required-properties message in .NET 9"),

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ“ Info: Justification regexes hardcode exact framework message wording

The justify patterns hardcode the exact net7/net9 message phrasings and specific RFC section fragments. Any future wording change or new status code flips a flow to mismatch and fails the gate. Acceptable for a one-shot snapshot, but brittle if the tooling is reused.

Devin Review

Was this helpful? React with πŸ‘ or πŸ‘Ž to provide feedback.

@devin-ai-integration

Copy link
Copy Markdown
Author
βœ… net9.0 runtime verification via Swagger UI β€” full Education CRUD passed

Ran the migrated net9.0 build locally (.NET 9.0.317) against docker compose Postgres and exercised every Education endpoint through Swagger UI in the browser.

Recording: https://app.devin.ai/attachments/e4c5acc4-d74d-4958-b55c-e139aec44188/net9-swagger-e2e-edited.mp4

Swagger UI renders cleanly on the pinned Swashbuckle 9.0.6 β€” the main regression risk in this PR β€” with the WebApi v1 definition and all five operations:

Swagger UI Education operations

Full lifecycle through the UI, all green:

Check Result
GET /api/Educations β†’ seed row c92ea179-…b974c 200 βœ…
GET /{seeded id} 200 βœ…
GET /{unknown id} 204 βœ…
POST missing required degree 400 problem+json naming degree βœ…
POST valid 200 + generated guid βœ…
PUT (with matching DTO id) 200 βœ…
GET read-back persisted update via EF Core/Npgsql 9 βœ…
DELETE β†’ GET 200 β†’ 204, row gone βœ…

The update round-tripped through Postgres correctly:

GET read-back showing persisted update

⚠️ Two non-blocking observations
  1. PUT rejects Swagger's own example body. The generated example omits id, but EducationService.Update requires model.Id == route id, so the copy-paste PUT returns 400. Resending with the matching id returns 200. Pre-existing behaviour, not caused by this migration, but consider binding the id from the route.

    Initial PUT 400 without id

  2. GraphQL is not verifiable. Program.cs has no AddGraphQLServer()/MapGraphQL(); /graphql returns 404. Recorded as N/A, not a failure.

Notes
  • App listens on http://localhost:5033 per launchSettings.json, not 5070.
  • No 500s, no analyser/TreatWarningsAsErrors build failures, and no leftover test data (final GET all returned to the two pre-existing rows).

Written by Devin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants