Skip to content

GH-5133 6.x prep for 7.0's one chain per handler type: obsolete ClassicCombine, fix latent Separated bugs, per-handler OTel tag, per-chain dedup scoping - #5184

Merged
jeremydmiller merged 9 commits into
mainfrom
gh-5133-separated-prep
Oct 23, 2026
Merged

jeremydmiller merged 9 commits into
mainfrom
gh-5133-separated-prep

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

The 6.x prep for Wolverine 7.0 removing MultipleHandlerBehavior. Each bullet is its own commit.

1. ClassicCombineIntoOneLogicalHandler obsolete, plus a startup warning and AssertNoCombinedHandlers()

  • [Obsolete] on the enum value, with a message that points at Separated and the 7.0 change. It is still the default. The repo's global NoWarn already includes 0618, so nothing in the repo needed pragmas.
  • When an app actually has message types whose handlers come from more than one class, Wolverine logs one warning at startup that lists them. Several methods on one class, like a saga's Start/Handle, don't count.
  • New opts.AssertNoCombinedHandlers() (on WolverineOptions, next to AssertNoBatchHandlerConflicts()) turns that warning into a startup failure for CI. Added a short docs section in handlers/index.md.

2. Latent Separated bugs: these consumers read HandlerGraph.Chains, so they never saw per-endpoint chains (new internal HandlerGraph.EveryChain() / SagaChains())

  • Requeue-policy listener validation (Pulsar hot-tail listeners silently drop deferred messages in every mode #4060), and the failure-rules section of describe.
  • MessagePartitioning.UseInferredMessageGrouping() / MaybeInferGrouping.
  • HandlerGraph.ConfigureHandlerForMessage() now also applies to every ByEndpoint chain, sticky ones included.
  • describe-routing <message> now lists the separated handlers along with their endpoints.
  • The saga store diagnostics (EF Core, RavenDB, RDBMS, Marten) and the CosmosDB saga validator.
  • Bobcat HandlerWarmUp compiles the per-endpoint chains through HandlerFor(type, endpoint).

3. Per-handler OTel tag. TagHandlerPolicy now captures the distinct handler type names when the policy runs. Before, the frame re-checked the call count during codegen, after SagaChain had already cleared its calls, so no saga ever got handler.type. A combined chain is now tagged with all of its handler types. Regenerated the committed Wolverine.AotSmoke.Saga output (it gains the two tags). I ran codegen write on all 11 drift-gate projects, and only those two files changed.

4. Per-chain dedup scoping. When a message type has more than one running chain, each chain claims id + "|h:<fnv1a of handler type names>". Before, the first claim won and the other handlers dropped the message. A message type with a single chain keeps storing its ids unchanged. I used a short hash instead of the type name because the id column is varchar(250).

Tests run locally (net9.0, Release)

  • Full wolverine.slnx build with -f net9.0: 0 errors. The only warnings are the existing NU1902 MessagePack ones. The first two passes hit a transient sourcelink race in WolverineWebApiFSharp, which builds cleanly by itself, and the third pass was clean.
  • CoreTests full suite: 3832 passed, 8 skipped, 0 failed. The new tests are combined_handlers_warning (5), separated_handler_chains_are_not_skipped + separated_saga_chains_are_not_skipped (8) and handler_type_activity_tagging* (6).
  • MessageRoutingTests: 25/25.
  • PostgresqlTests: the new deduplication_with_separated_handlers and logical_message_deduplication, 16/16.
  • Wolverine.Bobcat.Tests: 269/270 on the first run. The one failure was a Polecat TrackedSession timeout in polecat_consistency_boundaries, which passed 2/2 on rerun. The new warming_separated_handlers passed.
  • The new tests for inferred grouping, OTel tagging, Bobcat warm-up and dedup were confirmed red before their fixes.

Closes #5133

🤖 Generated with Claude Code

https://claude.ai/code/session_01DCggXgxnG3EBXoR9rrq37U

jeremydmiller and others added 9 commits October 23, 2026 14:00
… on combined handlers, add AssertNoCombinedHandlers()

ClassicCombineIntoOneLogicalHandler stays the 6.x default but is marked [Obsolete] (pointing at
Separated and the 7.0 one-chain-per-handler-type change). While it is in use, Wolverine logs one
warning at startup listing every message type whose handlers from more than one class were
combined. opts.AssertNoCombinedHandlers() turns that into a startup failure for CI rehearsal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCggXgxnG3EBXoR9rrq37U
…arated handler chains

Both read HandlerGraph.Chains, which under Separated holds only the empty placeholder root for a
message type with several handlers. A requeue policy on a separated handler's own chain was
invisible to the GH-4060 listener validation, and its failure rules were missing from the
describe output. New internal HandlerGraph.EveryChain() walks roots plus per-endpoint chains.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCggXgxnG3EBXoR9rrq37U
…ed handler chains

MaybeInferGrouping read only the root chains, so a message type whose saga (or aggregate) handlers
were all moved into per-endpoint chains under Separated got no inferred group id. It now asks the
root and then each per-endpoint chain, first match wins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCggXgxnG3EBXoR9rrq37U
…ssage type

It configured ChainFor(messageType) only, which under Separated is the empty placeholder root for a
message type with several handlers, so the configuration never reached a handler that runs. It now
also applies to each per-endpoint chain (Separated or sticky).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCggXgxnG3EBXoR9rrq37U
"wolverine-diagnostics describe-routing <message>" printed ChainFor(messageType).Handlers, which is
empty under Separated for a message type with several handlers. It now lists the root chain's
handlers plus every per-endpoint chain's handlers with the endpoint(s) each is bound to.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCggXgxnG3EBXoR9rrq37U
… saga chains

The EF Core, RavenDB, RDBMS and Marten saga store diagnostics and the CosmosDB saga serialization
validator collected saga types from HandlerGraph.Chains. Under Separated, when two saga types handle
the same messages, the second saga type only appears in per-endpoint chains and was skipped. All
five now read the new internal HandlerGraph.SagaChains(), which SagaDescriptorBuilder also uses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCggXgxnG3EBXoR9rrq37U
HandlerWarmUp only called HandlerFor(messageType) on each root chain. Under Separated a message type
with several handlers has no default handler, so the call threw NoHandlerForEndpointException and
the message type was reported as skipped, leaving every one of its handlers to compile inside the
first act. Warm-up now also compiles each per-endpoint chain through HandlerFor(messageType, endpoint).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCggXgxnG3EBXoR9rrq37U
TagHandlerPolicy only added the handler.type / message.handler Activity tags to a chain with exactly
one handler call, and the frame re-checked the call count at codegen time -- after SagaChain had
cleared its calls -- so sagas, including single-method ones, never got the tag, nor did a chain
combining several handler types. The policy now captures the distinct handler type names when it
runs: one type tags that type, a combined chain tags all of them. Separated chains each carry their
own type. Regenerated the committed Wolverine.AotSmoke.Saga output, which gains the two tags.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCggXgxnG3EBXoR9rrq37U
When a message type has more than one handler chain (one per handler type under Separated, or
sticky handlers), every chain claimed the same [Deduplicated] id, so the first claim won and the
other handlers dropped the message as a duplicate. Each such chain now claims the id with a short
stable suffix ("|h:" + an FNV-1a hash of its handler type names, kept short for the varchar(250)
id column). Message types with a single chain keep storing their ids exactly as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DCggXgxnG3EBXoR9rrq37U
@jeremydmiller
jeremydmiller merged commit 20f5611 into main Oct 23, 2026
@jeremydmiller jeremydmiller mentioned this pull request Oct 23, 2026
This was referenced Oct 25, 2026
github-actions Bot pushed a commit to MrD4rkne/oweme-ecosystem that referenced this pull request Oct 30, 2026
Updated [Aspire.Hosting.AppHost](https://github.com/microsoft/aspire)
from 13.6.3 to 13.6.4.

<details>
<summary>Release notes</summary>

_Sourced from [Aspire.Hosting.AppHost's
releases](https://github.com/microsoft/aspire/releases)._

## 13.6.4

## What's New in Aspire 13.6.4

Patch release for Aspire 13.6 that improves resource startup
reliability, fixes Azure publishing with parameterized enum properties
in TypeScript AppHosts, and tightens CLI diagnostic log permissions on
Unix.

### 🐛 Fixes

- 🖥️ **Resources could fail to start after a DCP create request timed
out** — AppHost now checks whether a resource was created before
retrying a timed-out or HTTP 504 request, avoiding a premature
`FailedToStart` state when DCP completed the operation. API operations
default to a 40-second timeout with an additional 20-second allowance
before the first successful operation, and resource creation has a
two-minute recovery budget. These limits can be configured through
`DcpPublisher:KubernetesApiTimeout`,
`DcpPublisher:KubernetesInitializationAdditionalTimeout`, and
`DcpPublisher:KubernetesCreateRecoveryTimeout`. Established watch and
log streams are not limited by these operation timeouts. Addresses
startup timeouts reported in 13.6. Fixes
[#​20691](https://github.com/microsoft/aspire/issues/20691).
([#​20868](https://github.com/microsoft/aspire/pull/20868), backport of
[#​20752](https://github.com/microsoft/aspire/pull/20752), @​danegsta)

- ☁️ **TypeScript AppHosts could fail to publish parameterized Azure
enum properties** — Assigning a `bicep().parameter(...)` expression to
an enum-valued provisioning property, such as an Azure Storage SKU name,
now works instead of failing with a type-assignment error. Type checking
for literal values and incompatible expression types is preserved. Fixes
a scenario introduced with the Azure provisioning proxy feature in 13.6.
([#​20767](https://github.com/microsoft/aspire/pull/20767), backport of
[#​20557](https://github.com/microsoft/aspire/pull/20557),
@​sebastienros)

- 🔒 **CLI diagnostic logs now use owner-only permissions on Unix** — Log
files are restricted to owner read/write access (`0600`), including
reused files, and the dedicated Aspire logs directory uses owner-only
access (`0700`), repairing existing permissions when needed. Newly
created custom log directories also use `0700`; existing custom parent
directories and Windows permission behavior are unchanged. Diagnostic
logs can contain sensitive data, including dashboard login URLs, so
review them before sharing.
([#​21282](https://github.com/microsoft/aspire/pull/21282), backport of
[#​21276](https://github.com/microsoft/aspire/pull/21276), @​mitchdenny)

---

*Full Changelog:
[v13.6.3...v13.6.4](https://github.com/microsoft/aspire/compare/v13.6.3...v13.6.4)*

*Full commit:
[c89352703f78ae46de90fbf751ed8b52b77b89bf](https://github.com/microsoft/aspire/commit/c89352703f78ae46de90fbf751ed8b52b77b89bf)*


Commits viewable in [compare
view](https://github.com/microsoft/aspire/compare/v13.6.3...v13.6.4).
</details>

Updated [Aspire.Hosting.PostgreSQL](https://github.com/microsoft/aspire)
from 13.6.3 to 13.6.4.

<details>
<summary>Release notes</summary>

_Sourced from [Aspire.Hosting.PostgreSQL's
releases](https://github.com/microsoft/aspire/releases)._

## 13.6.4

## What's New in Aspire 13.6.4

Patch release for Aspire 13.6 that improves resource startup
reliability, fixes Azure publishing with parameterized enum properties
in TypeScript AppHosts, and tightens CLI diagnostic log permissions on
Unix.

### 🐛 Fixes

- 🖥️ **Resources could fail to start after a DCP create request timed
out** — AppHost now checks whether a resource was created before
retrying a timed-out or HTTP 504 request, avoiding a premature
`FailedToStart` state when DCP completed the operation. API operations
default to a 40-second timeout with an additional 20-second allowance
before the first successful operation, and resource creation has a
two-minute recovery budget. These limits can be configured through
`DcpPublisher:KubernetesApiTimeout`,
`DcpPublisher:KubernetesInitializationAdditionalTimeout`, and
`DcpPublisher:KubernetesCreateRecoveryTimeout`. Established watch and
log streams are not limited by these operation timeouts. Addresses
startup timeouts reported in 13.6. Fixes
[#​20691](https://github.com/microsoft/aspire/issues/20691).
([#​20868](https://github.com/microsoft/aspire/pull/20868), backport of
[#​20752](https://github.com/microsoft/aspire/pull/20752), @​danegsta)

- ☁️ **TypeScript AppHosts could fail to publish parameterized Azure
enum properties** — Assigning a `bicep().parameter(...)` expression to
an enum-valued provisioning property, such as an Azure Storage SKU name,
now works instead of failing with a type-assignment error. Type checking
for literal values and incompatible expression types is preserved. Fixes
a scenario introduced with the Azure provisioning proxy feature in 13.6.
([#​20767](https://github.com/microsoft/aspire/pull/20767), backport of
[#​20557](https://github.com/microsoft/aspire/pull/20557),
@​sebastienros)

- 🔒 **CLI diagnostic logs now use owner-only permissions on Unix** — Log
files are restricted to owner read/write access (`0600`), including
reused files, and the dedicated Aspire logs directory uses owner-only
access (`0700`), repairing existing permissions when needed. Newly
created custom log directories also use `0700`; existing custom parent
directories and Windows permission behavior are unchanged. Diagnostic
logs can contain sensitive data, including dashboard login URLs, so
review them before sharing.
([#​21282](https://github.com/microsoft/aspire/pull/21282), backport of
[#​21276](https://github.com/microsoft/aspire/pull/21276), @​mitchdenny)

---

*Full Changelog:
[v13.6.3...v13.6.4](https://github.com/microsoft/aspire/compare/v13.6.3...v13.6.4)*

*Full commit:
[c89352703f78ae46de90fbf751ed8b52b77b89bf](https://github.com/microsoft/aspire/commit/c89352703f78ae46de90fbf751ed8b52b77b89bf)*


Commits viewable in [compare
view](https://github.com/microsoft/aspire/compare/v13.6.3...v13.6.4).
</details>

Updated
[Microsoft.AspNetCore.Authentication.JwtBearer](https://github.com/dotnet/dotnet)
from 10.0.13 to 10.0.14.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.AspNetCore.Authentication.JwtBearer's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated
[Microsoft.AspNetCore.Mvc.Testing](https://github.com/dotnet/dotnet)
from 10.0.13 to 10.0.14.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.AspNetCore.Mvc.Testing's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated [Microsoft.AspNetCore.OpenApi](https://github.com/dotnet/dotnet)
from 10.0.13 to 10.0.14.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.AspNetCore.OpenApi's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated [Microsoft.Bcl.TimeProvider](https://github.com/dotnet/dotnet)
from 10.0.13 to 10.0.14.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Bcl.TimeProvider's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated
[Microsoft.EntityFrameworkCore](https://github.com/dotnet/dotnet) from
10.0.13 to 10.0.14.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.EntityFrameworkCore's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated
[Microsoft.EntityFrameworkCore.Abstractions](https://github.com/dotnet/dotnet)
from 10.0.13 to 10.0.14.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.EntityFrameworkCore.Abstractions's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated
[Microsoft.EntityFrameworkCore.Design](https://github.com/dotnet/dotnet)
from 10.0.13 to 10.0.14.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.EntityFrameworkCore.Design's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated
[Microsoft.EntityFrameworkCore.Tools](https://github.com/dotnet/dotnet)
from 10.0.13 to 10.0.14.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.EntityFrameworkCore.Tools's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated
[Microsoft.Extensions.ApiDescription.Server](https://github.com/dotnet/dotnet)
from 10.0.13 to 10.0.14.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Extensions.ApiDescription.Server's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated
[Microsoft.Extensions.Caching.Memory](https://github.com/dotnet/dotnet)
from 10.0.13 to 10.0.14.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Extensions.Caching.Memory's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated
[Microsoft.Extensions.Configuration.EnvironmentVariables](https://github.com/dotnet/dotnet)
from 10.0.13 to 10.0.14.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Extensions.Configuration.EnvironmentVariables's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated
[Microsoft.Extensions.Configuration.Json](https://github.com/dotnet/dotnet)
from 10.0.13 to 10.0.14.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Extensions.Configuration.Json's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated
[Microsoft.Extensions.DependencyInjection.Abstractions](https://github.com/dotnet/dotnet)
from 10.0.13 to 10.0.14.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Extensions.DependencyInjection.Abstractions's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated
[Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore](https://github.com/dotnet/dotnet)
from 10.0.13 to 10.0.14.

<details>
<summary>Release notes</summary>

_Sourced from
[Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated
[Microsoft.Extensions.Hosting.Abstractions](https://github.com/dotnet/dotnet)
from 10.0.13 to 10.0.14.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Extensions.Hosting.Abstractions's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated [Microsoft.Extensions.Http](https://github.com/dotnet/dotnet)
from 10.0.13 to 10.0.14.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Extensions.Http's
releases](https://github.com/dotnet/dotnet/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/dotnet/dotnet/commits).
</details>

Updated
[Microsoft.Testing.Extensions.TrxReport](https://github.com/microsoft/testfx)
from 2.5.1 to 2.5.2.

<details>
<summary>Release notes</summary>

_Sourced from [Microsoft.Testing.Extensions.TrxReport's
releases](https://github.com/microsoft/testfx/releases)._

No release notes found for this version range.

Commits viewable in [compare
view](https://github.com/microsoft/testfx/commits).
</details>

Updated [WolverineFx](http://github.com/jasperfx/wolverine) from 6.51.3
to 6.56.0.

<details>
<summary>Release notes</summary>

_Sourced from [WolverineFx's
releases](http://github.com/jasperfx/wolverine/releases)._

## 6.56.0

## New

- **GH-5238** (#​5242): `opts.UseHttpTransport()` registers the HTTP
transport inside `UseWolverine()`. `http`/`https` URIs then resolve in
`ListenForMessagesFrom()`, `PublishMessage<T>().To(uri)`, and runtime
`EndpointFor()` / `ToDestination()`. Before this, the transport was only
registered by `ToHttpEndpoint()`, and any other `http` URI failed with
`Unknown Transport scheme 'http'`. `/_wolverine/invoke` now answers 415
instead of 500 for a content type with no registered serializer.

## Fixes

- **GH-5235** (#​5239): Host shutdown now stops the durability metrics
sweeper and waits for any query it has in flight before stores are
disposed. Removing a durability agent also waits for its in-flight
query. A metrics query could previously outlive `IHost.StopAsync()` and
throw `ObjectDisposedException` against a disposed `NpgsqlDataSource`.
- **GH-5236** (#​5240): A Kafka listener with a durable inbox no longer
crashes the process with a stack overflow when the inbox database is
unavailable. `DeferAsync()` used to call back into the receiver inline,
so the failed inbox write and the defer recursed. A deferred Kafka
envelope now goes back to the receiver on its own task after a short
pause, and only while the listener is running. After a stop or
inbox-recovery pause, its uncommitted offset brings it back. Because
Kafka has no native requeue, a `Requeue` error policy on a Kafka
endpoint now redelivers after about one second instead of immediately.
- **GH-5237** (#​5241): A CloudEvents HTTP endpoint now fails a
single-envelope send that the receiver rejects. It used to count the
send as delivered, so a durable endpoint aimed at `/_wolverine/invoke`
could delete an outgoing envelope that was never received. HTTP
transport responses are now disposed.


## 6.55.1

## Fixes

- **GH-5230** (#​5232): A database operation batch cancelled by
Wolverine's own shutdown is no longer wrapped in
`DatabaseBatchCommandException` and logged as an Error. Genuine
SQL/connection failures are still reported.
- **GH-5231** (#​5233): An `HttpEndpoint` aimed at `/_wolverine/invoke`
in its default (buffered) mode now delivers by posting each envelope
individually, instead of receiving a 415 for every batch and retrying
forever. `/batch/{queue}` and `.SendInline()` endpoints are unchanged.


## 6.55.0

## Highlights

**WolverineFx.Bobcat is out of alpha, on Bobcat 1.0.0** (#​5222,
#​5229). Bobcat 1.0.0 shipped tonight, and `WolverineFx.Bobcat` and
`WolverineFx.Bobcat.EventModel` now publish as stable **6.55.0** instead
of `-alpha.1`. `WolverineFx.Bobcat.Http` stays `6.55.0-alpha.1` until
Alba 9 ships stable, because a stable package cannot depend on Alba
9.0.0-rc.2. A spec project that `write-specs` generates with no
`--wolverine-version` pins the stable `WolverineFx.Bobcat` (#​5222,
#​5223).

**`MessageCausedBy` names your handler** (#​5224, #​5225).
`IWolverineObserver.MessageCausedBy` reported the generated handler
class
(`Internal.Generated.WolverineHandlers.StartTripHandler939323516`). It
now reports the handler you wrote (`TripService.StartTripHandler`), the
same string as the `message.handler` span tag, resolved at codegen time.
Code generated by an earlier version keeps working through the old
overload.

**CosmosDB sagas start with a conditional create** (#​5221, thanks
@​thechucklingatom). A second start message for an existing saga id used
to silently overwrite the running saga. It now fails with the
`SagaConcurrencyException` that Marten, Azure Blob and S3 already raise,
so one `OnException<SagaConcurrencyException>()` policy covers every
provider.

## Fixes
* GH-5217: `ListeningAgent.StartAsync` is serialized, and deliveries are
deferred to a drained `BufferedReceiver` (#​5228)
* GH-5218: an unresolvable tenant is treated as tenant-scoped on the
single-envelope inbox write (#​5227)
* GH-5220: Azure Service Bus listeners join their receive loop before
disposing the `CancellationTokenSource` (#​5226)
* GH-5215: reserved-word schema names are quoted in the remaining RDBMS
and PostgreSQL SQL (#​5216, thanks @​marc-RocketRez)
* GH-5213: a later pause supersedes an earlier pause's restart (#​5214)
* GH-5209: the dead letter history table round-trips with no schema
drift (#​5212)

## Dependencies
* JasperFx 2.96.0 (jasperfx#​1083: an Observed vs Derived `Origin` no
longer raises a `SourceDisagreement`)
* Weasel 9.47.0 (#​5219)
* Bobcat 1.0.0

**Full Changelog**:
https://github.com/JasperFx/wolverine/compare/V6.54.0...V6.55.0


## 6.54.0

## Highlights

**Dead letter failure groups** (#​5209, #​5210). Wolverine now
fingerprints every message as it moves to dead letter storage, so dead
letters can be managed one failure group at a time:

* The default `IDeadLetterFingerprinter` hashes the exception type and
the first stack frame from application code. Register your own to
replace it.
* `DeadLetterEnvelopeQuery` gains `FailureGroup`,
`ExceptionMessageMatch` (Exact / Contains), `TenantId` and `Archived`.
* A new `SummarizeAllAsync` overload groups by failure group, message
type or endpoint, with first and last failure times.
* `ReplayMatchingAsync`, `DiscardMatchingAsync`, `ArchiveMatchingAsync`
and `RestoreMatchingAsync` report how many dead letters they affected.
* A message that fails again after a replay reports its `ReplayCount`,
`LastReplayedAt` and `FirstFailedAt`.
* Archived dead letters drop out of summaries, queries and replays until
restored, and can be expired separately with
`DurabilitySettings.ArchivedDeadLetterRetention`.
* `IDeadLetters.Capabilities` tells you what a store supports.

All changes are additive. The relational stores pick up seven nullable
columns on `wolverine_dead_letters`, an index and a new
`wolverine_dead_letter_history` table through the normal schema
migration. See the [dead letter storage
guide](https://wolverinefx.net/guide/durability/dead-letter-storage.html).

**Deduplication fixes** (#​5205, #​5206, #​5208), and **Bobcat
1.0.0-rc.4** dependency pins (#​5211). The `WolverineFx.Bobcat*`
packages remain alpha (`6.54.0-alpha.1`).


## What's Changed
* GH-5205, GH-5206: [DeduplicatedWithResponse] claim-in-transaction gaps
([WriteAggregate] T / [BoundaryModel], and repeats refused over
committed work) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5208
* Bobcat 1.0.0-rc.4 by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5211
* GH-5209 Dead letters: failure fingerprints, operation counts, replay
history, archive/restore and tenant scoping by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5210


**Full Changelog**:
https://github.com/JasperFx/wolverine/compare/V6.53.0...V6.54.0

## 6.53.0

## What's Changed
* GH-5202: keep the ASB response queue identity stable during startup by
@​DeandreT in https://github.com/JasperFx/wolverine/pull/5203

## New Contributors
* @​DeandreT made their first contribution in
https://github.com/JasperFx/wolverine/pull/5203

**Full Changelog**:
https://github.com/JasperFx/wolverine/compare/V6.52.0...V6.53.0

## 6.52.0

Wolverine 6.52.0 is a feature release. The headline items are
Aspire-style registration by connection-string name for every transport
and every message store, timer agents for short-cadence recurring
schedules, and the 6.x groundwork for Wolverine 7.0's
one-chain-per-handler model. There are no breaking API changes. Two
behavior changes are worth knowing about up front: recurring schedules
that fire more often than every 15 minutes now run on a timer agent (opt
out per schedule with `UseScheduledMessages()`), and outgoing envelopes
a transport cannot map are dead-lettered instead of being logged and
deleted.

Many thanks to everyone who reported issues and sent fixes: @​uniquelau,
@​johnkaram02, @​erdtsieck, @​ahmetvayhan and @​pritamrao.

## Aspire parity: named connections

* Named-connection overloads for every transport (Aspire parity,
GH-5126) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5159
* Message storage by connection-string name for every RDBMS provider
(PostgreSQL, SQL Server, MySQL, SQLite, Oracle), `NpgsqlDataSource` /
`MySqlDataSource` from the container, named static tenants, a Named
Connection Strings table in `describe`, and docs that lead with the
named form (GH-5127, GH-5156) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5174
* Aspire samples moved to Aspire 13.6.3, added to `wolverine.slnx`, with
a ServiceDefaults project for traces, metrics and `/health` (GH-5124) by
@​jeremydmiller in https://github.com/JasperFx/wolverine/pull/5182

## Messaging and error handling

* Timer agents for short-cadence recurring schedules: one agent per
schedule under `opts.Schedules.TimerThreshold` (15 minutes), same dedup
id as the scheduled path, pause and resume through
`IRecurringScheduleControl` (GH-5168) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5183
* `DoThenRetry(action, maxAttempts)` error policy that works both inline
and from a queue (GH-5068) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5179
* Unmappable outgoing envelopes are dead-lettered on Azure Service Bus,
SNS and Kafka instead of being reported as sent (GH-5055) by
@​jeremydmiller in https://github.com/JasperFx/wolverine/pull/5185
* Durable outbox coalesces stores and deletes per tenant database, so
one slow tenant no longer holds back every tenant's sends (GH-5171) by
@​jeremydmiller in https://github.com/JasperFx/wolverine/pull/5180
* 6.x prep for HandlerChain 1:1 in 7.0:
`MultipleHandlerBehavior.ClassicCombineIntoOneLogicalHandler` is
`[Obsolete]` (still the default), a startup warning for combined
handlers, opt-in `AssertNoCombinedHandlers()`, fixes for latent
`Separated` bugs, a `handler.type` OpenTelemetry tag on every chain, and
logical deduplication scoped per chain (GH-5133) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5184

## HTTP

* `[DeduplicatedWithResponse]` `ClaimInTransaction`, plus two Marten
commit-failure fixes (GH-5160, GH-5165, GH-5166) by @​jeremydmiller with
@​uniquelau in https://github.com/JasperFx/wolverine/pull/5169
* `WolverineHttpOptions.DefaultClaimInTransaction`, an application-wide
default (GH-5160) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5173
* A string response declares its UTF-8 byte count as `Content-Length`
(GH-5187) by @​johnkaram02 in
https://github.com/JasperFx/wolverine/pull/5188
* Bind array and list query parameters whose `[FromQuery]` name is not a
C# identifier (GH-5189) by @​johnkaram02 in
https://github.com/JasperFx/wolverine/pull/5190

## Operability and diagnostics

* `ServiceCapabilities` reads each store on its own and reports
`FailedSections`, so a failed section is distinguishable from an empty
one (GH-5162) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5175
* `AssignmentGrid.Agent.UnplacedReason` (`AwaitingCapacity`,
`NoCapableNode`, `Paused`, `TakeoverHold`, `Superseded`), a capacity log
line and an optional `NodeAcceptThreshold` (GH-5163) by @​jeremydmiller
in https://github.com/JasperFx/wolverine/pull/5176 and
https://github.com/JasperFx/wolverine/pull/5186
* Header-equality filter on `DeadLetterEnvelopeQuery`, honored by bulk
replay and discard, across every dead letter store (GH-5164) by
@​jeremydmiller in https://github.com/JasperFx/wolverine/pull/5181
* `db-list` / `db-dump` / `db-patch` discover the Oracle message store
(GH-5172) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5177

## Documentation

* The remaining serverless and Cosmos DB documentation (GH-5054) by
@​jeremydmiller in https://github.com/JasperFx/wolverine/pull/5178
* Memory sizing for managed event subscription distribution at tenants x
projections scale: set `MaximumHopperSize` to about 2 x `BatchSize`
(GH-5170, follow-up JasperFx/jasperfx#​1076) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5199

**Full Changelog**:
https://github.com/JasperFx/wolverine/compare/V6.51.3...V6.52.0


Commits viewable in [compare
view](http://github.com/jasperfx/wolverine/compare/V6.51.3...V6.56.0).
</details>

Updated
[WolverineFx.FluentValidation](http://github.com/jasperfx/wolverine)
from 6.51.3 to 6.56.0.

<details>
<summary>Release notes</summary>

_Sourced from [WolverineFx.FluentValidation's
releases](http://github.com/jasperfx/wolverine/releases)._

## 6.56.0

## New

- **GH-5238** (#​5242): `opts.UseHttpTransport()` registers the HTTP
transport inside `UseWolverine()`. `http`/`https` URIs then resolve in
`ListenForMessagesFrom()`, `PublishMessage<T>().To(uri)`, and runtime
`EndpointFor()` / `ToDestination()`. Before this, the transport was only
registered by `ToHttpEndpoint()`, and any other `http` URI failed with
`Unknown Transport scheme 'http'`. `/_wolverine/invoke` now answers 415
instead of 500 for a content type with no registered serializer.

## Fixes

- **GH-5235** (#​5239): Host shutdown now stops the durability metrics
sweeper and waits for any query it has in flight before stores are
disposed. Removing a durability agent also waits for its in-flight
query. A metrics query could previously outlive `IHost.StopAsync()` and
throw `ObjectDisposedException` against a disposed `NpgsqlDataSource`.
- **GH-5236** (#​5240): A Kafka listener with a durable inbox no longer
crashes the process with a stack overflow when the inbox database is
unavailable. `DeferAsync()` used to call back into the receiver inline,
so the failed inbox write and the defer recursed. A deferred Kafka
envelope now goes back to the receiver on its own task after a short
pause, and only while the listener is running. After a stop or
inbox-recovery pause, its uncommitted offset brings it back. Because
Kafka has no native requeue, a `Requeue` error policy on a Kafka
endpoint now redelivers after about one second instead of immediately.
- **GH-5237** (#​5241): A CloudEvents HTTP endpoint now fails a
single-envelope send that the receiver rejects. It used to count the
send as delivered, so a durable endpoint aimed at `/_wolverine/invoke`
could delete an outgoing envelope that was never received. HTTP
transport responses are now disposed.


## 6.55.1

## Fixes

- **GH-5230** (#​5232): A database operation batch cancelled by
Wolverine's own shutdown is no longer wrapped in
`DatabaseBatchCommandException` and logged as an Error. Genuine
SQL/connection failures are still reported.
- **GH-5231** (#​5233): An `HttpEndpoint` aimed at `/_wolverine/invoke`
in its default (buffered) mode now delivers by posting each envelope
individually, instead of receiving a 415 for every batch and retrying
forever. `/batch/{queue}` and `.SendInline()` endpoints are unchanged.


## 6.55.0

## Highlights

**WolverineFx.Bobcat is out of alpha, on Bobcat 1.0.0** (#​5222,
#​5229). Bobcat 1.0.0 shipped tonight, and `WolverineFx.Bobcat` and
`WolverineFx.Bobcat.EventModel` now publish as stable **6.55.0** instead
of `-alpha.1`. `WolverineFx.Bobcat.Http` stays `6.55.0-alpha.1` until
Alba 9 ships stable, because a stable package cannot depend on Alba
9.0.0-rc.2. A spec project that `write-specs` generates with no
`--wolverine-version` pins the stable `WolverineFx.Bobcat` (#​5222,
#​5223).

**`MessageCausedBy` names your handler** (#​5224, #​5225).
`IWolverineObserver.MessageCausedBy` reported the generated handler
class
(`Internal.Generated.WolverineHandlers.StartTripHandler939323516`). It
now reports the handler you wrote (`TripService.StartTripHandler`), the
same string as the `message.handler` span tag, resolved at codegen time.
Code generated by an earlier version keeps working through the old
overload.

**CosmosDB sagas start with a conditional create** (#​5221, thanks
@​thechucklingatom). A second start message for an existing saga id used
to silently overwrite the running saga. It now fails with the
`SagaConcurrencyException` that Marten, Azure Blob and S3 already raise,
so one `OnException<SagaConcurrencyException>()` policy covers every
provider.

## Fixes
* GH-5217: `ListeningAgent.StartAsync` is serialized, and deliveries are
deferred to a drained `BufferedReceiver` (#​5228)
* GH-5218: an unresolvable tenant is treated as tenant-scoped on the
single-envelope inbox write (#​5227)
* GH-5220: Azure Service Bus listeners join their receive loop before
disposing the `CancellationTokenSource` (#​5226)
* GH-5215: reserved-word schema names are quoted in the remaining RDBMS
and PostgreSQL SQL (#​5216, thanks @​marc-RocketRez)
* GH-5213: a later pause supersedes an earlier pause's restart (#​5214)
* GH-5209: the dead letter history table round-trips with no schema
drift (#​5212)

## Dependencies
* JasperFx 2.96.0 (jasperfx#​1083: an Observed vs Derived `Origin` no
longer raises a `SourceDisagreement`)
* Weasel 9.47.0 (#​5219)
* Bobcat 1.0.0

**Full Changelog**:
https://github.com/JasperFx/wolverine/compare/V6.54.0...V6.55.0


## 6.54.0

## Highlights

**Dead letter failure groups** (#​5209, #​5210). Wolverine now
fingerprints every message as it moves to dead letter storage, so dead
letters can be managed one failure group at a time:

* The default `IDeadLetterFingerprinter` hashes the exception type and
the first stack frame from application code. Register your own to
replace it.
* `DeadLetterEnvelopeQuery` gains `FailureGroup`,
`ExceptionMessageMatch` (Exact / Contains), `TenantId` and `Archived`.
* A new `SummarizeAllAsync` overload groups by failure group, message
type or endpoint, with first and last failure times.
* `ReplayMatchingAsync`, `DiscardMatchingAsync`, `ArchiveMatchingAsync`
and `RestoreMatchingAsync` report how many dead letters they affected.
* A message that fails again after a replay reports its `ReplayCount`,
`LastReplayedAt` and `FirstFailedAt`.
* Archived dead letters drop out of summaries, queries and replays until
restored, and can be expired separately with
`DurabilitySettings.ArchivedDeadLetterRetention`.
* `IDeadLetters.Capabilities` tells you what a store supports.

All changes are additive. The relational stores pick up seven nullable
columns on `wolverine_dead_letters`, an index and a new
`wolverine_dead_letter_history` table through the normal schema
migration. See the [dead letter storage
guide](https://wolverinefx.net/guide/durability/dead-letter-storage.html).

**Deduplication fixes** (#​5205, #​5206, #​5208), and **Bobcat
1.0.0-rc.4** dependency pins (#​5211). The `WolverineFx.Bobcat*`
packages remain alpha (`6.54.0-alpha.1`).


## What's Changed
* GH-5205, GH-5206: [DeduplicatedWithResponse] claim-in-transaction gaps
([WriteAggregate] T / [BoundaryModel], and repeats refused over
committed work) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5208
* Bobcat 1.0.0-rc.4 by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5211
* GH-5209 Dead letters: failure fingerprints, operation counts, replay
history, archive/restore and tenant scoping by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5210


**Full Changelog**:
https://github.com/JasperFx/wolverine/compare/V6.53.0...V6.54.0

## 6.53.0

## What's Changed
* GH-5202: keep the ASB response queue identity stable during startup by
@​DeandreT in https://github.com/JasperFx/wolverine/pull/5203

## New Contributors
* @​DeandreT made their first contribution in
https://github.com/JasperFx/wolverine/pull/5203

**Full Changelog**:
https://github.com/JasperFx/wolverine/compare/V6.52.0...V6.53.0

## 6.52.0

Wolverine 6.52.0 is a feature release. The headline items are
Aspire-style registration by connection-string name for every transport
and every message store, timer agents for short-cadence recurring
schedules, and the 6.x groundwork for Wolverine 7.0's
one-chain-per-handler model. There are no breaking API changes. Two
behavior changes are worth knowing about up front: recurring schedules
that fire more often than every 15 minutes now run on a timer agent (opt
out per schedule with `UseScheduledMessages()`), and outgoing envelopes
a transport cannot map are dead-lettered instead of being logged and
deleted.

Many thanks to everyone who reported issues and sent fixes: @​uniquelau,
@​johnkaram02, @​erdtsieck, @​ahmetvayhan and @​pritamrao.

## Aspire parity: named connections

* Named-connection overloads for every transport (Aspire parity,
GH-5126) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5159
* Message storage by connection-string name for every RDBMS provider
(PostgreSQL, SQL Server, MySQL, SQLite, Oracle), `NpgsqlDataSource` /
`MySqlDataSource` from the container, named static tenants, a Named
Connection Strings table in `describe`, and docs that lead with the
named form (GH-5127, GH-5156) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5174
* Aspire samples moved to Aspire 13.6.3, added to `wolverine.slnx`, with
a ServiceDefaults project for traces, metrics and `/health` (GH-5124) by
@​jeremydmiller in https://github.com/JasperFx/wolverine/pull/5182

## Messaging and error handling

* Timer agents for short-cadence recurring schedules: one agent per
schedule under `opts.Schedules.TimerThreshold` (15 minutes), same dedup
id as the scheduled path, pause and resume through
`IRecurringScheduleControl` (GH-5168) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5183
* `DoThenRetry(action, maxAttempts)` error policy that works both inline
and from a queue (GH-5068) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5179
* Unmappable outgoing envelopes are dead-lettered on Azure Service Bus,
SNS and Kafka instead of being reported as sent (GH-5055) by
@​jeremydmiller in https://github.com/JasperFx/wolverine/pull/5185
* Durable outbox coalesces stores and deletes per tenant database, so
one slow tenant no longer holds back every tenant's sends (GH-5171) by
@​jeremydmiller in https://github.com/JasperFx/wolverine/pull/5180
* 6.x prep for HandlerChain 1:1 in 7.0:
`MultipleHandlerBehavior.ClassicCombineIntoOneLogicalHandler` is
`[Obsolete]` (still the default), a startup warning for combined
handlers, opt-in `AssertNoCombinedHandlers()`, fixes for latent
`Separated` bugs, a `handler.type` OpenTelemetry tag on every chain, and
logical deduplication scoped per chain (GH-5133) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5184

## HTTP

* `[DeduplicatedWithResponse]` `ClaimInTransaction`, plus two Marten
commit-failure fixes (GH-5160, GH-5165, GH-5166) by @​jeremydmiller with
@​uniquelau in https://github.com/JasperFx/wolverine/pull/5169
* `WolverineHttpOptions.DefaultClaimInTransaction`, an application-wide
default (GH-5160) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5173
* A string response declares its UTF-8 byte count as `Content-Length`
(GH-5187) by @​johnkaram02 in
https://github.com/JasperFx/wolverine/pull/5188
* Bind array and list query parameters whose `[FromQuery]` name is not a
C# identifier (GH-5189) by @​johnkaram02 in
https://github.com/JasperFx/wolverine/pull/5190

## Operability and diagnostics

* `ServiceCapabilities` reads each store on its own and reports
`FailedSections`, so a failed section is distinguishable from an empty
one (GH-5162) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5175
* `AssignmentGrid.Agent.UnplacedReason` (`AwaitingCapacity`,
`NoCapableNode`, `Paused`, `TakeoverHold`, `Superseded`), a capacity log
line and an optional `NodeAcceptThreshold` (GH-5163) by @​jeremydmiller
in https://github.com/JasperFx/wolverine/pull/5176 and
https://github.com/JasperFx/wolverine/pull/5186
* Header-equality filter on `DeadLetterEnvelopeQuery`, honored by bulk
replay and discard, across every dead letter store (GH-5164) by
@​jeremydmiller in https://github.com/JasperFx/wolverine/pull/5181
* `db-list` / `db-dump` / `db-patch` discover the Oracle message store
(GH-5172) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5177

## Documentation

* The remaining serverless and Cosmos DB documentation (GH-5054) by
@​jeremydmiller in https://github.com/JasperFx/wolverine/pull/5178
* Memory sizing for managed event subscription distribution at tenants x
projections scale: set `MaximumHopperSize` to about 2 x `BatchSize`
(GH-5170, follow-up JasperFx/jasperfx#​1076) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5199

**Full Changelog**:
https://github.com/JasperFx/wolverine/compare/V6.51.3...V6.52.0


Commits viewable in [compare
view](http://github.com/jasperfx/wolverine/compare/V6.51.3...V6.56.0).
</details>

Updated
[WolverineFx.RuntimeCompilation](http://github.com/jasperfx/wolverine)
from 6.51.3 to 6.56.0.

<details>
<summary>Release notes</summary>

_Sourced from [WolverineFx.RuntimeCompilation's
releases](http://github.com/jasperfx/wolverine/releases)._

## 6.56.0

## New

- **GH-5238** (#​5242): `opts.UseHttpTransport()` registers the HTTP
transport inside `UseWolverine()`. `http`/`https` URIs then resolve in
`ListenForMessagesFrom()`, `PublishMessage<T>().To(uri)`, and runtime
`EndpointFor()` / `ToDestination()`. Before this, the transport was only
registered by `ToHttpEndpoint()`, and any other `http` URI failed with
`Unknown Transport scheme 'http'`. `/_wolverine/invoke` now answers 415
instead of 500 for a content type with no registered serializer.

## Fixes

- **GH-5235** (#​5239): Host shutdown now stops the durability metrics
sweeper and waits for any query it has in flight before stores are
disposed. Removing a durability agent also waits for its in-flight
query. A metrics query could previously outlive `IHost.StopAsync()` and
throw `ObjectDisposedException` against a disposed `NpgsqlDataSource`.
- **GH-5236** (#​5240): A Kafka listener with a durable inbox no longer
crashes the process with a stack overflow when the inbox database is
unavailable. `DeferAsync()` used to call back into the receiver inline,
so the failed inbox write and the defer recursed. A deferred Kafka
envelope now goes back to the receiver on its own task after a short
pause, and only while the listener is running. After a stop or
inbox-recovery pause, its uncommitted offset brings it back. Because
Kafka has no native requeue, a `Requeue` error policy on a Kafka
endpoint now redelivers after about one second instead of immediately.
- **GH-5237** (#​5241): A CloudEvents HTTP endpoint now fails a
single-envelope send that the receiver rejects. It used to count the
send as delivered, so a durable endpoint aimed at `/_wolverine/invoke`
could delete an outgoing envelope that was never received. HTTP
transport responses are now disposed.


## 6.55.1

## Fixes

- **GH-5230** (#​5232): A database operation batch cancelled by
Wolverine's own shutdown is no longer wrapped in
`DatabaseBatchCommandException` and logged as an Error. Genuine
SQL/connection failures are still reported.
- **GH-5231** (#​5233): An `HttpEndpoint` aimed at `/_wolverine/invoke`
in its default (buffered) mode now delivers by posting each envelope
individually, instead of receiving a 415 for every batch and retrying
forever. `/batch/{queue}` and `.SendInline()` endpoints are unchanged.


## 6.55.0

## Highlights

**WolverineFx.Bobcat is out of alpha, on Bobcat 1.0.0** (#​5222,
#​5229). Bobcat 1.0.0 shipped tonight, and `WolverineFx.Bobcat` and
`WolverineFx.Bobcat.EventModel` now publish as stable **6.55.0** instead
of `-alpha.1`. `WolverineFx.Bobcat.Http` stays `6.55.0-alpha.1` until
Alba 9 ships stable, because a stable package cannot depend on Alba
9.0.0-rc.2. A spec project that `write-specs` generates with no
`--wolverine-version` pins the stable `WolverineFx.Bobcat` (#​5222,
#​5223).

**`MessageCausedBy` names your handler** (#​5224, #​5225).
`IWolverineObserver.MessageCausedBy` reported the generated handler
class
(`Internal.Generated.WolverineHandlers.StartTripHandler939323516`). It
now reports the handler you wrote (`TripService.StartTripHandler`), the
same string as the `message.handler` span tag, resolved at codegen time.
Code generated by an earlier version keeps working through the old
overload.

**CosmosDB sagas start with a conditional create** (#​5221, thanks
@​thechucklingatom). A second start message for an existing saga id used
to silently overwrite the running saga. It now fails with the
`SagaConcurrencyException` that Marten, Azure Blob and S3 already raise,
so one `OnException<SagaConcurrencyException>()` policy covers every
provider.

## Fixes
* GH-5217: `ListeningAgent.StartAsync` is serialized, and deliveries are
deferred to a drained `BufferedReceiver` (#​5228)
* GH-5218: an unresolvable tenant is treated as tenant-scoped on the
single-envelope inbox write (#​5227)
* GH-5220: Azure Service Bus listeners join their receive loop before
disposing the `CancellationTokenSource` (#​5226)
* GH-5215: reserved-word schema names are quoted in the remaining RDBMS
and PostgreSQL SQL (#​5216, thanks @​marc-RocketRez)
* GH-5213: a later pause supersedes an earlier pause's restart (#​5214)
* GH-5209: the dead letter history table round-trips with no schema
drift (#​5212)

## Dependencies
* JasperFx 2.96.0 (jasperfx#​1083: an Observed vs Derived `Origin` no
longer raises a `SourceDisagreement`)
* Weasel 9.47.0 (#​5219)
* Bobcat 1.0.0

**Full Changelog**:
https://github.com/JasperFx/wolverine/compare/V6.54.0...V6.55.0


## 6.54.0

## Highlights

**Dead letter failure groups** (#​5209, #​5210). Wolverine now
fingerprints every message as it moves to dead letter storage, so dead
letters can be managed one failure group at a time:

* The default `IDeadLetterFingerprinter` hashes the exception type and
the first stack frame from application code. Register your own to
replace it.
* `DeadLetterEnvelopeQuery` gains `FailureGroup`,
`ExceptionMessageMatch` (Exact / Contains), `TenantId` and `Archived`.
* A new `SummarizeAllAsync` overload groups by failure group, message
type or endpoint, with first and last failure times.
* `ReplayMatchingAsync`, `DiscardMatchingAsync`, `ArchiveMatchingAsync`
and `RestoreMatchingAsync` report how many dead letters they affected.
* A message that fails again after a replay reports its `ReplayCount`,
`LastReplayedAt` and `FirstFailedAt`.
* Archived dead letters drop out of summaries, queries and replays until
restored, and can be expired separately with
`DurabilitySettings.ArchivedDeadLetterRetention`.
* `IDeadLetters.Capabilities` tells you what a store supports.

All changes are additive. The relational stores pick up seven nullable
columns on `wolverine_dead_letters`, an index and a new
`wolverine_dead_letter_history` table through the normal schema
migration. See the [dead letter storage
guide](https://wolverinefx.net/guide/durability/dead-letter-storage.html).

**Deduplication fixes** (#​5205, #​5206, #​5208), and **Bobcat
1.0.0-rc.4** dependency pins (#​5211). The `WolverineFx.Bobcat*`
packages remain alpha (`6.54.0-alpha.1`).


## What's Changed
* GH-5205, GH-5206: [DeduplicatedWithResponse] claim-in-transaction gaps
([WriteAggregate] T / [BoundaryModel], and repeats refused over
committed work) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5208
* Bobcat 1.0.0-rc.4 by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5211
* GH-5209 Dead letters: failure fingerprints, operation counts, replay
history, archive/restore and tenant scoping by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5210


**Full Changelog**:
https://github.com/JasperFx/wolverine/compare/V6.53.0...V6.54.0

## 6.53.0

## What's Changed
* GH-5202: keep the ASB response queue identity stable during startup by
@​DeandreT in https://github.com/JasperFx/wolverine/pull/5203

## New Contributors
* @​DeandreT made their first contribution in
https://github.com/JasperFx/wolverine/pull/5203

**Full Changelog**:
https://github.com/JasperFx/wolverine/compare/V6.52.0...V6.53.0

## 6.52.0

Wolverine 6.52.0 is a feature release. The headline items are
Aspire-style registration by connection-string name for every transport
and every message store, timer agents for short-cadence recurring
schedules, and the 6.x groundwork for Wolverine 7.0's
one-chain-per-handler model. There are no breaking API changes. Two
behavior changes are worth knowing about up front: recurring schedules
that fire more often than every 15 minutes now run on a timer agent (opt
out per schedule with `UseScheduledMessages()`), and outgoing envelopes
a transport cannot map are dead-lettered instead of being logged and
deleted.

Many thanks to everyone who reported issues and sent fixes: @​uniquelau,
@​johnkaram02, @​erdtsieck, @​ahmetvayhan and @​pritamrao.

## Aspire parity: named connections

* Named-connection overloads for every transport (Aspire parity,
GH-5126) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5159
* Message storage by connection-string name for every RDBMS provider
(PostgreSQL, SQL Server, MySQL, SQLite, Oracle), `NpgsqlDataSource` /
`MySqlDataSource` from the container, named static tenants, a Named
Connection Strings table in `describe`, and docs that lead with the
named form (GH-5127, GH-5156) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5174
* Aspire samples moved to Aspire 13.6.3, added to `wolverine.slnx`, with
a ServiceDefaults project for traces, metrics and `/health` (GH-5124) by
@​jeremydmiller in https://github.com/JasperFx/wolverine/pull/5182

## Messaging and error handling

* Timer agents for short-cadence recurring schedules: one agent per
schedule under `opts.Schedules.TimerThreshold` (15 minutes), same dedup
id as the scheduled path, pause and resume through
`IRecurringScheduleControl` (GH-5168) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5183
* `DoThenRetry(action, maxAttempts)` error policy that works both inline
and from a queue (GH-5068) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5179
* Unmappable outgoing envelopes are dead-lettered on Azure Service Bus,
SNS and Kafka instead of being reported as sent (GH-5055) by
@​jeremydmiller in https://github.com/JasperFx/wolverine/pull/5185
* Durable outbox coalesces stores and deletes per tenant database, so
one slow tenant no longer holds back every tenant's sends (GH-5171) by
@​jeremydmiller in https://github.com/JasperFx/wolverine/pull/5180
* 6.x prep for HandlerChain 1:1 in 7.0:
`MultipleHandlerBehavior.ClassicCombineIntoOneLogicalHandler` is
`[Obsolete]` (still the default), a startup warning for combined
handlers, opt-in `AssertNoCombinedHandlers()`, fixes for latent
`Separated` bugs, a `handler.type` OpenTelemetry tag on every chain, and
logical deduplication scoped per chain (GH-5133) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5184

## HTTP

* `[DeduplicatedWithResponse]` `ClaimInTransaction`, plus two Marten
commit-failure fixes (GH-5160, GH-5165, GH-5166) by @​jeremydmiller with
@​uniquelau in https://github.com/JasperFx/wolverine/pull/5169
* `WolverineHttpOptions.DefaultClaimInTransaction`, an application-wide
default (GH-5160) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5173
* A string response declares its UTF-8 byte count as `Content-Length`
(GH-5187) by @​johnkaram02 in
https://github.com/JasperFx/wolverine/pull/5188
* Bind array and list query parameters whose `[FromQuery]` name is not a
C# identifier (GH-5189) by @​johnkaram02 in
https://github.com/JasperFx/wolverine/pull/5190

## Operability and diagnostics

* `ServiceCapabilities` reads each store on its own and reports
`FailedSections`, so a failed section is distinguishable from an empty
one (GH-5162) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5175
* `AssignmentGrid.Agent.UnplacedReason` (`AwaitingCapacity`,
`NoCapableNode`, `Paused`, `TakeoverHold`, `Superseded`), a capacity log
line and an optional `NodeAcceptThreshold` (GH-5163) by @​jeremydmiller
in https://github.com/JasperFx/wolverine/pull/5176 and
https://github.com/JasperFx/wolverine/pull/5186
* Header-equality filter on `DeadLetterEnvelopeQuery`, honored by bulk
replay and discard, across every dead letter store (GH-5164) by
@​jeremydmiller in https://github.com/JasperFx/wolverine/pull/5181
* `db-list` / `db-dump` / `db-patch` discover the Oracle message store
(GH-5172) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5177

## Documentation

* The remaining serverless and Cosmos DB documentation (GH-5054) by
@​jeremydmiller in https://github.com/JasperFx/wolverine/pull/5178
* Memory sizing for managed event subscription distribution at tenants x
projections scale: set `MaximumHopperSize` to about 2 x `BatchSize`
(GH-5170, follow-up JasperFx/jasperfx#​1076) by @​jeremydmiller in
https://github.com/JasperFx/wolverine/pull/5199

**Full Changelog**:
https://github.com/JasperFx/wolverine/compare/V6.51.3...V6.52.0


Commits viewable in [compare
view](http://github.com/jasperfx/wolverine/compare/V6.51.3...V6.56.0).
</details>

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

<!-- coderabbit-ai-generated:v1 -->

## Summary by CodeRabbit

* **Chores**
* Updated versions of platform and application components, along with
testing tools. Other package settings remain unchanged. These updates do
not add or remove user-facing features.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant