Architecture Decision Record
ADR-118: Message Transport Library Policy (MassTransit v8 Pin and Exit Strategy)
Status
Accepted (2026-09-11). Promotes the MassTransit clause inside
ADR-016 into a decision of its own: ADR-016 owns the
release policy that the pin is enforced under, this record owns the choice of transport library, the
conditions that end it, and the ordered list of what replaces it.
Amended (2026-09-19): the pinned-entry count is restated workspace-wide (five entries, three in
MMCA.Common plus one each in MMCA.ADC and MMCA.Store) and the build gate's reach is scoped to
MMCA.Common; the using MassTransit surface is recounted from source as nine files; ADC's nightly
Service Bus emulator smoke is restated as authoritative rather than advisory; the external v9 and
support-horizon dates gain the hedge ADR-016 already carries; and the unreconciled overlap with
ADR-016's still-live Transport exit options section is recorded under Related. The pin, the
decision and the replacement order are unchanged. Revised 2026-10-07: anchors refreshed after the
v1.233.0 release. Revised 2026-10-21: the circuit-breaker description now matches source (it wraps
the IMessageBus publish, which is the broker hop only in broker mode), and anchors are refreshed.
Revised 2026-10-24: MassTransit.AmazonSQS 8.5.11 joins the pinned set for the SQS adapter transport, the pin and its gate unchanged (ADR-134); the trial point and the surface inventory are corrected in place. See Revision (2026-10-24) at the end.
Revised 2026-10-25: MassTransit.SqlTransport.PostgreSQL 8.5.11 (Apache-2.0) joins the pinned set for the built-in PostgreSQL transport and reaches every consumer of MMCA.Common.Infrastructure with Dapper; Decision 1 now records that the build gate covers three of MMCA.Common's five MassTransit entries. See Revision (2026-10-25) at the end.
Revised 2026-10-26: every MassTransit entry is at the 8.5.12 v8 patch, the build gate now covers all five MMCA.Common entries, MMCA.Common's using MassTransit surface is recounted as fifteen files and the swap surface is restated to include the consumer service hosts' MassTransit-typed consumer registration, and the Azure.Messaging.ServiceBus pin is restated as also serving the Azure transport; anchors refreshed.
Revised 2026-10-28: anchors refreshed after later MMCA.Common releases moved the CHANGELOG entries and an ADC Engagement host edit moved its consumer registration.
Context
MassTransit is the only message-broker library in this workspace, and it is pinned to 8.5.12 across
all five of MMCA.Common's MassTransit packages (MMCA.Common/Directory.Packages.props:125-127,
:130, :136, the pin comment at :120-124). Two consumers declare a
MassTransit.Azure.ServiceBus.Core entry of their own at the same 8.5.12 patch for their Service Bus
emulator test tier (MMCA.ADC/Directory.Packages.props:73,
MMCA.Store/Directory.Packages.props:97), so the workspace carries seven pinned MassTransit entries.
The pin is a policy
rather than a lag: v9 was announced in April 2025 and shipped in January 2026 as a commercial,
source-available product with a runtime licence key (those two dates are the vendor's own public
record, not something this repository can assert). A v9 bus fails its startup licence check and
every broker-enabled service host crashes, which is a failure mode a build cannot see because CI
never starts a broker. That is why the ceiling is a fitness function rather than a comment:
MassTransit_MustNotExceed_MajorVersion8
(MMCA.Common/Source/Hosting/MMCA.Common.Testing.Architecture/Bases/Governance/DependencyVersionTestsBase.cs:28)
parses Directory.Packages.props and fails the build at an exclusive major ceiling of 9 (:34),
and MMCA.Common subclasses it
(MMCA.Common/Tests/Architecture/MMCA.Common.Architecture.Tests/Governance/DependencyVersionTests.cs:9).
A blanket package update bumped the version to 9.1.2 once before and reintroduced the crash. The
gate reads the props file found by walking up from the running test assembly, and MMCA.Common is the
only repo that subclasses the base (the base's own doc comment tells consumers not to), so the build
gate covers Common's five entries and nothing else. What holds the two consumer entries at v8 is
the lockstep sweep plus a dependabot.yml in each repo that manages only the github-actions and docker
ecosystems (MMCA.ADC/.github/dependabot.yml:28, MMCA.Store/.github/dependabot.yml:32), whose
comment says NuGet is excluded and MassTransit must stay v8 (MMCA.ADC/.github/dependabot.yml:1-4,
MMCA.Store/.github/dependabot.yml:6-8).
A pin with no horizon is a decision that expires quietly, so the real question is not "which version" but "what does this workspace actually owe MassTransit, and what would it cost to leave". The answer is narrower than the usual framework-lock-in story, because the durable parts of the messaging design are not MassTransit's:
- The outbox is ours.
OutboxMessage(MMCA.Common/Source/Core/MMCA.Common.Infrastructure/Persistence/Outbox/OutboxMessage.cs) is a plain EF entity holding the serializedPayload(:43) keyed byEventType(:40), with the claim lease (LockedUntil:60,LockToken:67), the retry counter (:52), the propagatedTraceId/SpanId(:73,:76) and the optionalOrderingKey(:88). None of those columns is a broker concept (ADR-003). - The inbox is ours.
IInboxStore(.../Persistence/Inbox/IInboxStore.cs:16),InboxMessage(keyed onMessageId,.../Persistence/Inbox/InboxMessage.cs:14) andEfInboxStorededup redeliveries in the consumer's own database, andTryBeginAsync(.../Persistence/Inbox/IInboxStore.cs:38) stages the row into the handler's own unit of work (ADR-021). A broker supplies the redelivery; nothing else here is the broker's. - The publish and consume leg is the only part MassTransit owns.
OutboxProcessorresolvesIMessageBusfrom the per-row scope (.../Persistence/Outbox/Processing/OutboxProcessor.cs:776) and publishes every integration event through it (PublishAsyncat:785), and only thatIMessageBuspublish is wrapped in the circuit breaker (:783-787, the comment saying so at:778-782). In broker mode that publish is the broker hop; on a monolith the defaultInProcessMessageBusruns the integration-event handlers inside the same breaker (the field doc at:103-110) (ADR-087).
The abstractions that stand between application code and the library are already in place and are
this workspace's own types: IMessageBus
(MMCA.Common/Source/Core/MMCA.Common.Application/Messaging/IMessageBus.cs:28) and IEventBus
(MMCA.Common/Source/Core/MMCA.Common.Application/Interfaces/Events/IEventBus.cs:11). BrokerMessageBus
implements the first over a MassTransit IPublishEndpoint
(.../Infrastructure/Messaging/BrokerMessageBus.cs:43-44); BrokerEventBus implements the second and
does not reference MassTransit at all (.../Infrastructure/Messaging/BrokerEventBus.cs:31), because
in broker mode its whole job is to write the outbox row and signal the processor. MMCA.Common's
using MassTransit surface is fifteen files: eleven inside MMCA.Common.Infrastructure
(DependencyInjection.Messaging.cs, Messaging/BrokerMessageBus.cs, four files of the
Messaging/Transports/ extension point (IBrokerTransport.cs, BrokerTransportPolicies.cs,
RabbitMqBrokerTransport.cs, PostgreSqlBrokerTransport.cs) and the five consumer files under
Messaging/Consumers/: IntegrationEventConsumer.cs, IntegrationEventConsumerExtensions.cs,
UpcastingIntegrationEventConsumer.cs, FaultIntegrationEventConsumer.cs and
ConsumerOriginRestore.cs), three in the adapter packages (MMCA.Common.Azure's
Messaging/AzureServiceBusTransport.cs and Messaging/ServiceBusEmulatorSupport.cs,
MMCA.Common.Aws's Messaging/AmazonSqsTransport.cs; see the Revision (2026-10-24)), plus the
emulator test fixture
MMCA.Common/Source/Hosting/MMCA.Common.Testing.Azure/Fixtures/ServiceBusEmulatorFixtureBase.cs:54.
The surface does not stop at MMCA.Common. Its public consumer-registration API is typed on
MassTransit: AddBrokerMessaging takes an Action<IBusRegistrationConfigurator>
(MMCA.Common/Source/Core/MMCA.Common.Infrastructure/DependencyInjection.Messaging.cs:48-50) and
RegisterIntegrationEventConsumer an Action<IEndpointRegistrationConfigurator>
(.../Messaging/Consumers/IntegrationEventConsumerExtensions.cs:60-62). Every consumer service host
that runs broker consumers passes such a lambda (for example
MMCA.Store/Source/Services/MMCA.Store.Sales.Service/Program.cs:269-283,
MMCA.ADC/Source/Services/MMCA.ADC.Engagement.Service/Program.cs:304-310), ADC's Conference host
names MassTransit directly
(MMCA.ADC/Source/Services/MMCA.ADC.Conference.Service/ConferenceBrokerConsumers.cs:1, :32-37),
and each consumer's Service Bus emulator fixture does too
(MMCA.ADC/Tests/Integration/MMCA.ADC.ServiceBusEmulator.IntegrationTests/Infrastructure/ServiceBusEmulatorFixture.cs:1,
MMCA.Store/Tests/Integration/MMCA.Store.ServiceBusEmulator.IntegrationTests/Infrastructure/ServiceBusEmulatorFixture.cs:1).
Domain, Application and Shared hold the interfaces alone, and that is build-gated:
MicroserviceExtractionTestsBase
(MMCA.Common/Source/Hosting/MMCA.Common.Testing.Architecture/Bases/Layering/MicroserviceExtractionTestsBase.cs:8)
bans MassTransit, gRPC and Protobuf from the Domain, Application and Shared layers
(.../Rules/Layering/ArchitectureRules.Transport.cs:21); other layers are not checked, and
Infrastructure, *.Service and *.Contracts are the edges the transport is meant to live at
(:6-8).
The comparison landscape is also public rather than internal: the August 2025 Visual Studio Magazine article "Messaging Made Simple: Choosing the Right Framework for .NET" surveys the same shift, and the two candidates below are the ones that survive this workspace's constraints. That article, the v9 release dates above and the v8 support horizon below are all external statements cited as published: none of them is verifiable from this repository, which is the same hedge ADR-016 applies to the support horizon.
Decision
Stay on MassTransit v8 behind IMessageBus, and keep the outbox and inbox custom precisely because
that is what keeps a transport swap cheap. Record the exit triggers now, and the replacement order,
so the pin is a dated decision rather than an open-ended hold.
The pin stands; the build gate in MMCA.Common covers all five of its entries. MassTransit remains on v8 (8.5.12 today) on all five MMCA.Common entries:
MassTransit,MassTransit.RabbitMQandMassTransit.Azure.ServiceBus.Core(MMCA.Common/Directory.Packages.props:125-127),MassTransit.AmazonSQS(:130) andMassTransit.SqlTransport.PostgreSQL(:136), the last two commented as tracking the same v8 line and version as the rest (:129,:134).DependencyVersionTestsBaseremains the enforcement point, and itsMassTransitPackageIdslist names all five (MMCA.Common/Source/Hosting/MMCA.Common.Testing.Architecture/Bases/Governance/DependencyVersionTestsBase.cs:18-25, the two transport ids at:23-24), which MMCA.Common's subclass inherits without an override (MMCA.Common/Tests/Architecture/MMCA.Common.Architecture.Tests/Governance/DependencyVersionTests.cs:9). The two consumer-declaredMassTransit.Azure.ServiceBus.Coreentries are held at the same patch by the lockstep sweep and the NuGet-excluded dependabot config, not by a build gate, and a consumer that wants its own guard overridesMassTransitPackageIdsrather than subclassing the base as shipped. The ceiling is the major version only: v8 patch and minor updates are ordinary dependency work.No durable messaging mechanism may move into the library. The outbox, the inbox, the claim lease, the retry and dead-letter policy, the ordering key and the trace propagation columns stay framework code on framework tables. MassTransit's own transactional-outbox feature is not adopted, and adopting it later would be a reversal of this clause, not a refactor.
The exit triggers are named. Any one of these opens the replacement work, and none of them is a version number on its own:
- a security advisory against MassTransit v8 with no patched v8 release;
- a .NET major version (11 and onward) that v8 does not support;
- the close of the v8 maintenance window (community support for the v8 line is stated to end at the end of 2026).
The replacement order is decided in advance. Both candidates implement the existing
IMessageBus, so no consumer handler, module or contract changes; the consumer service hosts' MassTransit-typed consumer registration (see Context) is the part a swap does touch:- First: Wolverine (Apache 2.0). Message handling is plain methods rather than a consumer class per message, and its transports cover the two this workspace runs (RabbitMQ, Azure Service Bus) plus SQS and Kafka. Its own durable-inbox and outbox features would be left off, because decision 2 already owns that layer.
- Second: a raw-SDK adapter.
RabbitMQ.ClientplusAzure.Messaging.ServiceBus, the latter already pinned at 7.21.0 for theMMCA.Common.AzureService Bus transport and its emulator test tier (MMCA.Common/Directory.Packages.props:141; the comment at:137-140names 7.20.2 as the first line with working emulator admin-plane support). This is the floor option: no third-party abstraction at all, at the cost of hand-writing consumer dispatch, retry and delayed redelivery.
Two options are rejected outright, and recorded so they are not re-proposed.
- MassTransit v9. Commercial with a runtime licence key. Buying it retires the gate rather than answering it, at a recurring cost, and leaves the transport decision where it is today.
- MediatR. Not used anywhere in this workspace (the CQRS pipeline is the framework's own
ICommandHandler/IQueryHandlerchain, ADR-014), and commercial since 2025 for the same reason. It is named here only because it is the library most often suggested in the same breath, and it would be a new dependency rather than a replacement.
A trial ships beside the incumbent. The trial point is one more
IBrokerTransportregistered by name throughAddBrokerTransport(MMCA.Common/Source/Core/MMCA.Common.Infrastructure/DependencyInjection.Messaging.cs:159, resolved byResolveBrokerTransportat:188, beside the built-in RabbitMQ and PostgreSQL transports it returns at:188-197and the adapter transports in MMCA.Common.Azure and MMCA.Common.Aws), so a candidate is exercised by configuration without removing anything, and ADC's nightly Service Bus emulator smoke is where it runs first. That job is authoritative rather than advisory: it has carried nocontinue-on-errorsince 2026-08-31 (TD-17), anddeploy.yml's cross-service-freshness gate requires it to have concluded success alongside thecross-servicejob in the same qualifying nightly (MMCA.ADC/.github/workflows/cross-service-tests.yml:142, the gating rationale at:116-126; the gate'srequired-jobsatMMCA.ADC/.github/workflows/deploy.yml:901-903), so a candidate arm that regresses Service Bus topology or the AMQP round-trip blocks the next deploy.
Rationale
- The pin is enforceable, so it is honest. A comment beside a version number is a hope; a fitness
function that parses
Directory.Packages.propsis the reason the v9 crash was reintroduced exactly once. Making the ceiling a build gate is the same invariant-over-discipline posture as the layer rules (ADR-015). - Custom durable machinery is what makes the transport replaceable. A library that owned the outbox would own the lease semantics, the ordering guarantee, the dead-letter retention window and the replay API, and every one of those would have to be re-earned against a new library's model. Owning them means a swap is a publish-and-consume adapter: MMCA.Common's fifteen-file surface above, plus the MassTransit-typed consumer registration in each consumer service host and emulator fixture.
- Wolverine ahead of raw SDKs because it keeps retry, delayed redelivery and consumer dispatch as library concerns on both transports this workspace runs, which is precisely the part the raw-SDK option hand-writes. It is ordered first on licence and transport coverage, not on a benchmark run here: neither candidate has been evaluated against a running broker in this workspace.
- Rejecting v9 is a licence decision, not a quality one. The v9 line is a reasonable product; a per-deployment runtime key across seven service hosts plus every test tier is the cost that does not fit.
Trade-offs
- The workspace sits on a library version with a finite support horizon. Nothing forces a move today, and the exit triggers above are what convert "we should look at this sometime" into a dated check. The cost of being wrong about the horizon is a rushed adapter rather than a rewrite, which is the whole point of decision 2.
- A v8 security advisory has no patch path but the exit. There is no commercial support contract on the v8 line, so an advisory with no community patch moves straight to the replacement list.
- An adapter spike is mostly a Common change, but not only one. No consumer handler, module or
contract changes, because the candidate ships behind
IMessageBusand the ban inMicroserviceExtractionTestsBasekeeps the library out of consumer Domain, Application and Shared layers. The ban does not reach service hosts or test fixtures, though: the consumer hosts register consumers through MassTransit'sIBusRegistrationConfiguratorandIEndpointRegistrationConfigurator(see Context), so a swap that changes theAddBrokerMessagingsignature also edits those hosts and the consumer emulator fixtures. The cost lands in one Common release plus that host-level change per consumer, swept under ADR-016's lockstep policy. - The PostgreSQL transport is core, so its package reaches every consumer.
PostgreSqlBrokerTransportships in MMCA.Common.Infrastructure because any PostgreSQL is the broker (MMCA.Common/Source/Core/MMCA.Common.Infrastructure/Messaging/Transports/PostgreSqlBrokerTransport.cs:10-14,:40), so every consumer of that package restoresMassTransit.SqlTransport.PostgreSQLand the Dapper it brings (MMCA.Common/CHANGELOG.md:129,MMCA.Common/Directory.Packages.props:134-135) whether or not it selects the transport. - The emulator test tier is coupled to the choice.
ServiceBusEmulatorFixtureBaseuses the MassTransit v8 custom-clientsHost()overload, so a transport swap re-writes that fixture and re-checks theAzure.Messaging.ServiceBus7.21.0 pin it shares with theMMCA.Common.AzureService Bus transport. - Ordering the candidates without running them is deliberate but partial. The list narrows what a spike has to evaluate; it does not stand in for the spike.
Revision (2026-10-01)
No decision, trigger, replacement order or rationale changed. Facts restated from source: all five
pinned MassTransit entries are at the v8 patch 8.5.11 (MMCA.Common/Directory.Packages.props:128-130,
MMCA.ADC/Directory.Packages.props:65, MMCA.Store/Directory.Packages.props:93), an ordinary v8
patch update under decision 1, and Azure.Messaging.ServiceBus is at 7.21.0
(MMCA.Common/Directory.Packages.props:135). Both consumer dependabot.yml files also manage a
docker ecosystem (MMCA.ADC/.github/dependabot.yml:28, MMCA.Store/.github/dependabot.yml:32);
NuGet is still excluded. The transport fitness rule checks Domain, Application and Shared only
(ArchitectureRules.Transport.cs:21), not every layer outside API and Infrastructure. ADR-016's
Related section now links back to this record without ceding the exit-options list. The broker
transport configuration moved to DependencyInjection.Messaging.cs (:258), which is also the ninth
using MassTransit file in place of DependencyInjection.cs; the count of nine is unchanged. The
OutboxProcessor, BrokerMessageBus and ADC workflow citations are re-anchored.
Revision (2026-10-06)
No decision, trigger, replacement order or rationale changed, and no fact changed: every corrected
item is a moved line. The 2026-10-01 anchors above now sit at: the three Common MassTransit entries
MMCA.Common/Directory.Packages.props:124-126 (still 8.5.11), Azure.Messaging.ServiceBus 7.21.0 at
:131, and ConfigureBrokerTransport at DependencyInjection.Messaging.cs:264. Anchors in Context
and Decision were re-verified against current source (the OutboxMessage columns, the
OutboxProcessor publish leg and breaker, the transport switch arms, and ADC deploy.yml's
required-jobs).
Revision (2026-10-07)
Re-verified against current source. No decision, trigger, replacement order or rationale changed, and no fact changed: all five MassTransit entries are still at 8.5.11 and the Service Bus emulator smoke is still authoritative and deploy-gated. Four groups of anchors in Context and Decision moved after the 2026-10-06 revision and are re-pointed in place.
- Anchors re-verified against current source: the Store
MassTransit.Azure.ServiceBus.CoreentryMMCA.Store/Directory.Packages.props:89(still 8.5.11; the ADC entry stays atMMCA.ADC/Directory.Packages.props:65); theOutboxProcessorpublish leg insideDeliverAsync, withIMessageBusresolved atOutboxProcessor.cs:680, the breaker call at:685-689,PublishAsyncat:687and the only-the-broker-hop comment at:682-684; the ADCservicebus-emulator-smokejob atMMCA.ADC/.github/workflows/cross-service-tests.yml:142with its AUTHORITATIVE SINCE 2026-08-31 (TD-17) rationale at:116-126(continue-on-errorappears there only in comments, never as a key); and thecross-service-freshnessgate'srequired-jobsatMMCA.ADC/.github/workflows/deploy.yml:885-887(required-jobs-mode: same-runat:888). The Store anchor inside the 2026-10-01 revision is left as written.
Revision (2026-10-21)
Re-verified against current source. No decision, trigger, replacement order or rationale changed:
all five MassTransit entries are still at 8.5.11, the build gate's ceiling is still major 9, and
the Service Bus emulator smoke is still authoritative and deploy-gated. One description in Context
moved with the code. Three of the four anchor groups the 2026-10-07 revision re-pointed have moved
again (the Store entry, the OutboxProcessor publish leg and the deploy.yml gate); the ADC
servicebus-emulator-smoke job is still at cross-service-tests.yml:142 with its TD-17 rationale
at :116-126. That revision is left as written.
- The publish-leg bullet in Context no longer says only the broker hop is wrapped. The breaker in
OutboxProcessor.DeliverAsyncwraps theIMessageBuspublish (MMCA.Common/Source/Core/MMCA.Common.Infrastructure/Persistence/Outbox/Processing/OutboxProcessor.cs:781-785), and its comment (:776-780) and field doc (:102-105) state that with broker messaging this is the broker hop, while on a monolith the defaultInProcessMessageBusruns the integration-event handlers inside the same breaker, so failing handlers can open it too. - Anchors re-verified against current source: the Store
MassTransit.Azure.ServiceBus.CoreentryMMCA.Store/Directory.Packages.props:92(still 8.5.11; ADC still atMMCA.ADC/Directory.Packages.props:65);MassTransit_MustNotExceed_MajorVersion8atDependencyVersionTestsBase.cs:26withexclusiveMajorCeiling: 9at:32;IMessageBusresolved atOutboxProcessor.cs:774,PublishAsyncat:783; and thecross-service-freshnessgate'srequired-jobsatMMCA.ADC/.github/workflows/deploy.yml:900-902(required-jobs-mode: same-runat:903). TheMicroserviceExtractionTestsBasecitation in Context now names the class declaration (MicroserviceExtractionTestsBase.cs:8) rather than theCoreLayers_ShouldNotDependOn_Transporttest at:13; neither line moved.
Revision (2026-10-24)
ADR-134 moves the vendor transports into adapter packages. The library choice, the v8 pin, the exit triggers and the replacement order are unchanged.
MassTransit.AmazonSQSstays on the v8 pin. It is pinned at 8.5.11, documented as the same version as every MassTransit entry above it (MMCA.Common/Directory.Packages.props:129-:130), besideMassTransit,MassTransit.RabbitMQandMassTransit.Azure.ServiceBus.Coreat 8.5.11 (:125-:127). MMCA.Common therefore carries four MassTransit entries; the five-entry workspace count in the 2026-09-19 amendment is left as recorded. OnlyMMCA.Common.Awsconsumes the new entry, throughAmazonSqsTransport(MMCA.Common/Source/Hosting/MMCA.Common.Aws/Messaging/AmazonSqsTransport.cs:37).- The vendor transports left the core. The Azure Service Bus transport and its emulator helper
are in
MMCA.Common.Azure(MMCA.Common/Source/Hosting/MMCA.Common.Azure/Messaging/AzureServiceBusTransport.cs:16,Messaging/ServiceBusEmulatorSupport.cs:32), and the build gate refuses a vendor MassTransit transport in any core project (MMCA.Common/Source/Build/MMCA.Common.LayerEnforcement.targets:108-111,:126). - Corrected in place: Decision item 6, which placed the trial point in a
MessageBusProviderswitch insideConfigureBrokerTransport(neither exists now; a trial is one more registeredIBrokerTransport), and the Context surface inventory, which listedMessaging/ServiceBusEmulatorSupport.csin Infrastructure and the fixture underMMCA.Common.Testing.
Revision (2026-10-25)
The library choice, the v8 pin, the exit triggers and the replacement order are unchanged.
MassTransit.SqlTransport.PostgreSQLjoins the v8 pin. It is pinned at 8.5.11 (MMCA.Common/Directory.Packages.props:136) under a comment tying it to the same v8 line and version as every MassTransit entry and noting that it brings Dapper (:134-135); its license is Apache-2.0 (MMCA.Common/CHANGELOG.md:24). It backs the built-inPostgreSqlBrokerTransport(MMCA.Common/Source/Core/MMCA.Common.Infrastructure/Messaging/Transports/PostgreSqlBrokerTransport.cs:40), selected byMessageBus:Provider=PostgreSql(ADR-066). Because that transport is core, every consumer of MMCA.Common.Infrastructure now restores it and Dapper (MMCA.Common/CHANGELOG.md:24), recorded as a new Trade-offs bullet.- The build gate does not cover it.
MassTransitPackageIdsstill listsMassTransit,MassTransit.RabbitMQandMassTransit.Azure.ServiceBus.Coreonly (DependencyVersionTestsBase.cs:20-22), with no override in Common's subclass (DependencyVersionTests.cs:9), so neitherMassTransit.SqlTransport.PostgreSQLnor theMassTransit.AmazonSQSentry the 2026-10-24 revision added is checked against the major-9 ceiling (DependencyVersionTestsBase.cs:32). Decision 1 now says so; the 2026-10-24 revision's "the pin and its gate unchanged" describes the gate's list, not its reach over the new entry. - Corrected in place: Decision 1 (three packages, now five MMCA.Common entries with three gated)
and Decision 6's
DependencyInjection.Messaging.csanchors (:148,:177,:179-181, now:159,:188,:188-197). The three-entry and five-entry counts in Context and their props anchors are left as recorded, Decision 1 carrying the current figures, and theusing MassTransitfile count in Context was not recounted in this pass.
Revision (2026-10-26)
Re-verified against current source. The library choice, the v8 pin, the major-9 ceiling, the exit
triggers and the replacement order are unchanged. What moved: every MassTransit entry took the
8.5.12 v8 patch, the build gate's list now covers all five MMCA.Common entries, and the
using MassTransit surface is recounted, with the swap surface restated to reach the consumer
service hosts. The earlier revisions are left as written.
- All seven MassTransit entries are at 8.5.12, an ordinary v8 patch update under decision 1:
MMCA.Common's five (
MMCA.Common/Directory.Packages.props:125-127,:130,:136) and the two consumerMassTransit.Azure.ServiceBus.Coreentries (MMCA.ADC/Directory.Packages.props:73,MMCA.Store/Directory.Packages.props:97). Context now states the five MMCA.Common entries and the seven-entry workspace count in place of the three-package and five-entry wording. - The build gate covers every MMCA.Common MassTransit entry.
MassTransitPackageIdsnow namesMassTransit.AmazonSQSandMassTransit.SqlTransport.PostgreSQLbeside the original three (DependencyVersionTestsBase.cs:18-25, the two at:23-24; recorded inMMCA.Common/CHANGELOG.md:65, release 1.258.0), and Common's subclass still inherits the list (DependencyVersionTests.cs:9). Decision 1 and Context now say the gate covers all five; the 2026-10-25 revision's "three gated" describes the list as it was. - The
using MassTransitsurface is fifteen files, not nine: eleven inMMCA.Common.Infrastructure(the fourMessaging/Transports/filesIBrokerTransport.cs,BrokerTransportPolicies.cs,RabbitMqBrokerTransport.csandPostgreSqlBrokerTransport.csamong them),AzureServiceBusTransport.csandServiceBusEmulatorSupport.csinMMCA.Common.Azure,AmazonSqsTransport.csinMMCA.Common.Aws, and theServiceBusEmulatorFixtureBasefixture. That count is MMCA.Common's own. Context and Rationale are corrected in place. - The swap surface reaches the consumer service hosts.
AddBrokerMessagingtakes anAction<IBusRegistrationConfigurator>(DependencyInjection.Messaging.cs:48-50) andRegisterIntegrationEventConsumeranAction<IEndpointRegistrationConfigurator>(IntegrationEventConsumerExtensions.cs:60-62); the consumer hosts pass such lambdas (MMCA.Store/Source/Services/MMCA.Store.Sales.Service/Program.cs:269-283,MMCA.Store/Source/Services/MMCA.Store.Catalog.Service/Program.cs:279-301,MMCA.ADC/Source/Services/MMCA.ADC.Engagement.Service/Program.cs:303-307), ADC's Conference host references MassTransit directly (ConferenceBrokerConsumers.cs:1,:32-37, wired atMMCA.ADC/Source/Services/MMCA.ADC.Conference.Service/Program.cs:432), and both consumer emulator fixtures carryusing MassTransit(ServiceBusEmulatorFixture.cs:1in each). Context, Decision 4, Rationale and the adapter-spike Trade-offs bullet no longer say a swap is Common-only or leaves consumers untouched; theMicroserviceExtractionTestsBaseban covers Domain, Application and Shared only. Azure.Messaging.ServiceBus7.21.0 also serves theMMCA.Common.AzureService Bus transport, not only the emulator test tier (MMCA.Common/Directory.Packages.props:137-141). Decision 4 and the emulator Trade-offs bullet now say so.- Anchors re-verified against current source:
MassTransit_MustNotExceed_MajorVersion8atDependencyVersionTestsBase.cs:28withexclusiveMajorCeiling: 9at:34; the props pin comment atMMCA.Common/Directory.Packages.props:120-124;IMessageBusresolved atOutboxProcessor.cs:776, the breaker at:783-787,PublishAsyncat:785, the comment at:778-782and the field doc at:103-110; thecross-service-freshnessgate'srequired-jobsatMMCA.ADC/.github/workflows/deploy.yml:901-903(required-jobs-mode: same-runat:904); and the PostgreSQL transport entry in the Trade-offs bullet atMMCA.Common/CHANGELOG.md:86(release 1.257.0). TheMMCA.Common.LayerEnforcement.targetsandCHANGELOG.md:24anchors inside the 2026-10-24 and 2026-10-25 revisions are left as written; the vendor-transport refusal now sits in targetEnforceCloudVendorBoundary(:130, conditions at:144-145, error at:151).
Revision (2026-10-28)
Re-verified against current source. The library choice, the v8 pin, the major-9 ceiling, the exit
triggers, the replacement order and every fact are unchanged: all five MMCA.Common MassTransit
entries are still at 8.5.12 (MMCA.Common/Directory.Packages.props:125-127, :130, :136) under
the pin comment at :120-124, and the ADC Engagement host still passes a MassTransit-typed
consumer-registration lambda. Only anchors moved. The anchors inside the 2026-10-26 and earlier
revisions are left as written.
- Anchors re-verified against current source: the ADC Engagement host's
AddBrokerMessaginglambda atMMCA.ADC/Source/Services/MMCA.ADC.Engagement.Service/Program.cs:304-310(its fourRegisterIntegrationEventConsumercalls at:306-309), re-pointed in Context; the PostgreSQL transport entry ("every consumer of MMCA.Common.Infrastructure now restores this package and Dapper") atMMCA.Common/CHANGELOG.md:129, release 1.257.0, re-pointed in the Trade-offs bullet (the companionMMCA.Common/Directory.Packages.props:134-135still holds); and theMassTransitPackageIdswidening the 2026-10-26 revision cites atCHANGELOG.md:65now atMMCA.Common/CHANGELOG.md:108, still under release 1.258.0.
Related
ADR-016 (the lockstep release policy this pin is
enforced under; its 2026-08-28 amendment first sketched exit options, and this record owns the
ordered list. ADR-016's Transport exit options section now defers to this record: it keeps the
surface inventory, the trial point and the proving ground, and records its OpenTransit-fork,
commercial-v9 and raw-SDK candidates only as first sketched, so where the two lists differ this
record governs),
ADR-066 (which broker runs where, the axis orthogonal to which
library talks to it),
ADR-003 (the outbox this record refuses to hand to a library),
ADR-021 (the inbox, for the same reason),
ADR-087 (the circuit breaker around the IMessageBus
publish, which is the library-owned broker hop in broker mode),
ADR-010 and
ADR-090 (the contract and upcaster rules a transport swap must
not disturb),
ADR-015 (the gate the pin is enforced by).