Skip to content

Release v4.0.0-preview-5 - #184

Merged
chullybun merged 2 commits into
mainfrom
v4.0.0-preview-5
Aug 22, 2026
Merged

Release v4.0.0-preview-5#184
chullybun merged 2 commits into
mainfrom
v4.0.0-preview-5

Conversation

@chullybun

Copy link
Copy Markdown
Collaborator

Summary

Publishes v4.0.0-preview-5. There is no milestone or set of merged PRs behind this one — it's a fixing/massaging release: accumulated small fixes plus a documentation/reality-gap correction pass, bundled together and versioned.

What's in this release

Feature/fix work:

  • Added WithIfMatchRequired() so a POST/DELETE that is conditional on a related (parent) resource's state can assert If-Match explicitly — independent of the automatic PUT/PATCH IETag-based concurrency check. WebApiOptionsBase ETag capture now also applies to POST/DELETE. Covered by new unit tests (WebApiTestsBase.Post.cs/.Delete.cs — missing vs. present If-Match) and documented in coreex-api-controllers.instructions.md and CoreEx.AspNetCore/AGENTS.md.
  • Expanded EventAction with additional lifecycle values: Confirmed, Started, Paused, Stopped, Restarted, Suspended, Reinstated, Closed, Reopened, Expired, Renewed, Acknowledged, Declined.

Documentation / AI workflow asset corrections (found while reviewing header names and generated-asset behaviour against the actual source):

  • Idempotency-Key header — several READMEs/AGENTS.md files described it as x-idempotency-key. The real constant (HttpNames.IdempotencyKeyHeaderName) is Idempotency-Key, matching both the code and the IETF standard for this header (the x- prefix convention was deprecated by RFC 6648).
  • Paging headers/query string — removed a fabricated $page query parameter and X-Paging-Page response header that don't exist anywhere in the framework (PagingArgs has no Page property), and corrected a wrongly shortened X-Paging-Count to the real X-Paging-Total-Count.
  • RFC number fixdocs/capabilities.md cited RFC 7386 for JSON Merge Patch; the correct spec is RFC 7396 (matches every other reference in the repo).
  • $inactive vs. soft-delete — closed a gap in coreex-test-api's workflow where $inactive (reference-data IsActive/IsInactive, wired up only for reference-data endpoints) was conflated with soft-delete (IsDeleted) on regular entities, including a worked example showing a soft-deleted row reappearing via $inactive — which the framework does not support. Added explicit guardrails against ever bypassing the logical-delete filter (EfDbArgs.BypassFilters / WithLogicalDeleteFilter(allowFilterBypass: true) / IgnoreQueryFilters()) to satisfy a test.
  • No throwaway smoke tests — added guardrails against inserting a manual/scratch verification pass between implementing an API or service and authoring its real test (coreex-api, coreex-app-service workflows) — hand off straight to the real test, which is the actual verification step.
  • Reference-data property on request DTOs — closed a gap where coreex-contract's Path B (subordinate/request contracts) had no property-type-resolution step for reference-data properties, unlike Path A. A request DTO (e.g. XxxAddRequest) could end up with a plain {Name}Code string property instead of the required [Contract]+partial class / [ReferenceData<T>]+partial property pattern — which compiles but serializes with the wrong JSON name and has no typed navigation for validation.
  • A handful of smaller clarifications: a Domain/Contract/Persistence naming-collision note, a Result<T>.ThrowOnError() target-typing note, an aggregate OnCheckCanMutate() heterogeneous-precondition note, and a repository parent/child EF navigation cross-reference.

Test plan

  • dotnet build CoreEx.slnx -c Release — succeeds, 0 warnings, 0 errors; Version.props bump (4.0.0-preview-5) confirmed reflected in generated NuGet package filenames.
  • dotnet test tests/CoreEx.AspNetCore.Test.Unit --filter FullyQualifiedName~IfMatchRequired — all 8 new tests pass across net8.0/net9.0/net10.0.
  • Repo-wide grep confirms no remaining stale references to x-idempotency-key, $page/X-Paging-Page, X-Paging-Count, or RFC 7386.

Bumps Version.props to 4.0.0-preview-5. A fixing/massaging release: no new
milestone, just accumulated fixes and doc/reality-gap corrections found
while reviewing the codebase and its AI workflow assets.

Feature/fix work:
- Add WithIfMatchRequired() extension so a POST/DELETE that is conditional
  on a related (parent) resource's state can assert If-Match explicitly,
  independent of the automatic PUT/PATCH IETag-based check. ETag capture
  in WebApiOptionsBase now also applies to POST/DELETE. Covered by new
  WebApiTestsBase.Post.cs / .Delete.cs unit tests (missing + present
  If-Match cases), and documented in coreex-api-controllers.instructions.md
  and CoreEx.AspNetCore/AGENTS.md.
- Expand EventAction with additional lifecycle action values (Confirmed,
  Started, Paused, Stopped, Restarted, Suspended, Reinstated, Closed,
  Reopened, Expired, Renewed, Acknowledged, Declined).

Documentation / AI workflow asset corrections:
- Idempotency-Key header: several READMEs/AGENTS.md described the header
  as x-idempotency-key; the real constant (HttpNames.IdempotencyKeyHeaderName)
  is Idempotency-Key, matching both the actual code and the IETF standard
  for this header (RFC 6648 deprecated the x- prefix convention).
- Paging headers/query string: removed a fabricated $page query parameter
  and X-Paging-Page response header that don't exist anywhere in the
  framework (PagingArgs has no Page property), and corrected a wrongly
  shortened X-Paging-Count to the real X-Paging-Total-Count.
- Fixed RFC 7386 -> RFC 7396 (JSON Merge Patch) in docs/capabilities.md.
- Closed a gap where $inactive (reference-data IsActive/IsInactive,
  wired up only for reference-data endpoints) was conflated with
  soft-delete (IsDeleted) on regular entities in coreex-test-api's
  workflow, including a worked example that showed a soft-deleted row
  reappearing via $inactive - which the framework does not support.
  Added explicit guardrails in coreex-tests.instructions.md and
  coreex-repositories.instructions.md against ever bypassing the
  logical-delete filter (EfDbArgs.BypassFilters /
  WithLogicalDeleteFilter(allowFilterBypass: true) / IgnoreQueryFilters())
  to satisfy a test.
- Added guardrails against writing throwaway smoke tests between
  implementing an API/service and authoring its real test
  (coreex-api, coreex-app-service workflows) - hand off straight to the
  real test.
- Closed a gap where coreex-contract's Path B (subordinate/request
  contracts) had no property-type-resolution step for reference-data
  properties, unlike Path A - so a request DTO could end up with a plain
  {Name}Code string property instead of the required [Contract]+partial
  class / [ReferenceData<T>]+partial property pattern, which serializes
  with the wrong JSON name and has no typed navigation for validation.
- Domain naming-collision note (Contracts/Domain/Persistence sharing a
  short type name), Result<T>.ThrowOnError() target-typing note,
  aggregate OnCheckCanMutate() heterogeneous-precondition note, and a
  repository parent/child EF navigation cross-reference.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Eric Sibly <eric.sibly@avanade.com>
Copilot AI lite review requested due to automatic review settings August 22, 2026 23:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Publishes v4.0.0-preview-5 of CoreEx, bundling a small framework enhancement (explicit If-Match requirement for conditional POST/DELETE + broader request ETag capture) plus a broad “docs vs reality” correction pass across README/AGENTS/instructions/skills.

Changes:

  • Bump version to 4.0.0-preview-5.
  • Add WithIfMatchRequired() and extend WebApiOptionsBase ETag capture to POST/DELETE; add unit tests for missing/present If-Match.
  • Correct documentation and AI workflow assets around idempotency header name, paging headers/query parameters, merge-patch RFC, and $inactive vs soft-delete guidance; expand EventAction.

Reviewed changes

Copilot reviewed 31 out of 31 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
Version.props Version bump to 4.0.0-preview-5.
tests/CoreEx.AspNetCore.Test.Unit/WebApiTestsBase.Post.cs Adds POST tests for WithIfMatchRequired() behavior.
tests/CoreEx.AspNetCore.Test.Unit/WebApiTestsBase.Delete.cs Adds DELETE tests for WithIfMatchRequired() behavior.
src/CoreEx/Http/README.md Corrects paging/idempotency header documentation to match HttpNames.
src/CoreEx.Events/EventAction.cs Adds additional lifecycle EventAction enum values.
src/CoreEx.AspNetCore/WebApiRequestOptions.cs Centralizes concurrency message; clarifies PUT/PATCH verification remarks.
src/CoreEx.AspNetCore/README.md Corrects idempotency header name in documentation.
src/CoreEx.AspNetCore/Mvc/README.md Corrects paging parameters and idempotency header name in docs.
src/CoreEx.AspNetCore/Idempotency/README.md Corrects idempotency header name references and examples.
src/CoreEx.AspNetCore/AspNetCoreExtensions.cs Adds WithIfMatchRequired() extension and improves WithLocationUri docs.
src/CoreEx.AspNetCore/AGENTS.md Documents POST/DELETE related-resource concurrency pattern using WithIfMatchRequired().
src/CoreEx.AspNetCore/Abstractions/WebApiOptionsBase.cs Captures If-Match ETag for POST/DELETE; adds shared concurrency message.
src/CoreEx.AspNetCore/Abstractions/README.md Updates docs for ETag capture/paging header names.
src/CoreEx.AspNetCore.NSwag/README.md Corrects paging params and idempotency header name docs.
src/CoreEx.AspNetCore.NSwag/AGENTS.md Corrects paging params and idempotency header name in the attribute matrix.
docs/capabilities.md Fixes Merge Patch RFC references (7396).
.github/skills/coreex-test-api/SKILL.md Refines test workflow guidance (seed precondition state; clarifies 428 assertions; outbox expectations).
.github/skills/coreex-test-api/references/workflow.md Expands detailed testing workflow guardrails, esp. $inactive vs soft-delete and event expectations.
.github/skills/coreex-repository/references/workflow.md Adds guidance on hand-authoring EF parent/child navigation properties.
.github/skills/coreex-contract/references/workflow.md Adds reference-data property resolution requirements for request/subordinate DTOs and conditional If-Match DTO pattern.
.github/skills/coreex-app-service/SKILL.md Adds guidance to prefer EventAction enum before raw string actions.
.github/skills/coreex-app-service/references/workflow.md Documents ThrowOnError() target-typing nuance and EventAction enum preference; discourages throwaway smoke tests.
.github/skills/coreex-api/SKILL.md Updates workflow guidance to go straight to real integration tests (no throwaway smoke tests).
.github/skills/coreex-api/references/workflow.md Adds controller pattern for conditional nested-resource POST/DELETE using WithIfMatchRequired().
.github/skills/coreex-aggregate/references/workflow.md Clarifies OnCheckCanMutate() limitations for heterogeneous preconditions.
.github/instructions/coreex-tests.instructions.md Adds guardrails for outbox expectations, seeded preconditions, $inactive vs soft-delete, and conditional POST/DELETE If-Match tests.
.github/instructions/coreex-repositories.instructions.md Adds EF navigation guidance and reinforces “don’t bypass soft-delete filter” rule.
.github/instructions/coreex-domain.instructions.md Adds guidance about intentional naming collisions across Contracts/Domain/Persistence and qualification strategy.
.github/instructions/coreex-contracts.instructions.md Adds conditional If-Match command/request DTO pattern (IETag + [JsonIgnore]).
.github/instructions/coreex-application-services.instructions.md Documents ThrowOnError() target-typing behavior to avoid var pitfalls.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/CoreEx.AspNetCore/Abstractions/README.md Outdated
Comment thread tests/CoreEx.AspNetCore.Test.Unit/WebApiTestsBase.Post.cs Outdated
- Abstractions/README.md: reword the ETag/If-Match bullet so it no longer
  implies a missing ETag can fail with either 412 or 428 - missing is
  always 428 (Precondition Required); 412 (Precondition Failed) is a
  separate, later failure for a stale/mismatched ETag against the
  persisted value once the operation actually runs.
- WebApiTestsBase.Post.cs: the new
  Post_Body_With_Response_IfMatchRequired_Present test only proved
  WithIfMatchRequired() doesn't throw when If-Match is present - it never
  asserted the header value was actually captured onto ro.ETag and
  stamped onto the deserialized body (ro.Value.ETag), which is the actual
  production behaviour this PR added to WebApiOptionsBase for POST. Added
  the same ro.ETag / ro.Value.ETag assertions the existing PUT tests use.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Eric Sibly <eric.sibly@avanade.com>
Copilot AI review requested due to automatic review settings August 22, 2026 23:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 31 out of 31 changed files in this pull request and generated 1 comment.

Comment thread src/CoreEx.Events/EventAction.cs
@chullybun
chullybun merged commit 229cfb6 into main Aug 22, 2026
3 of 4 checks passed
@chullybun
chullybun deleted the v4.0.0-preview-5 branch August 22, 2026 23:51
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.

2 participants