diff --git a/docs/adr/0066-infrastructure-provisioner.md b/docs/adr/0066-infrastructure-provisioner.md
new file mode 100644
index 0000000000..ee03e7eacb
--- /dev/null
+++ b/docs/adr/0066-infrastructure-provisioner.md
@@ -0,0 +1,459 @@
+---
+id: 0066-infrastructure-provisioner
+title: "Infrastructure Provisioner for Messaging Gateways"
+status: Proposed
+author:
+ - "Rafael Lillo"
+created: 2026-07-28
+summary: "Introduces IAmAInfrastructureProvisioner with per-gateway Assume/Validate/Create/CreateOrUpdate implementations, attached to Publication and Subscription, to standardize how gateways provision broker infrastructure. Ships opt-in in V10 alongside deprecated legacy provisioning members; becomes the single mechanism in V11."
+tags:
+ - "transports"
+ - "provisioning"
+ - "api-design"
+---
+
+# 66. Infrastructure Provisioner for Messaging Gateways
+
+Date: 2026-07-28
+
+## Status
+
+Proposed
+
+## Context
+
+Brighter supports multiple messaging gateways (RabbitMQ, Kafka, AWS SNS/SQS, Azure Service Bus, GCP Pub/Sub, Redis, MsSql, Postgres, RocketMQ; MQTT excluded — no broker-side infrastructure). Today, the infrastructure a gateway depends on — exchanges, topics, queues, subscriptions, dead-letter queues — is provisioned inconsistently:
+
+- Some gateways auto-create infrastructure at channel open time, others assume it exists and fail at runtime.
+- DevOps teams must hand-maintain gateway-specific scripts or Terraform to stand up infrastructure outside the application.
+- There is no unified way to **validate** that required infrastructure exists before a consumer starts, which makes startup failures hard to diagnose (missing topic vs. wrong credentials vs. network issue).
+
+We want a single, gateway-agnostic abstraction for provisioning, with **distinct implementations per gateway** — Assume, Validate, Create, and CreateOrUpdate — rather than one implementation switching behavior internally. Not every gateway/side ships all four: each ships only the strategies the broker actually supports.
+
+## Decision
+
+Introduce a narrow interface, `IAmAInfrastructureProvisioner`, in `Paramore.Brighter`, taking the gateway it operates on:
+
+```csharp
+///
+/// Provisions (or checks) the infrastructure — exchanges, topics, queues,
+/// subscriptions — required by a messaging gateway. Each gateway ships
+/// implementations of the strategies it supports: Assume, Validate,
+/// Create, CreateOrUpdate.
+///
+public interface IAmAInfrastructureProvisioner
+{
+ /// Executes the provisioning strategy synchronously.
+ /// The messaging gateway whose infrastructure is provisioned.
+ void Provision(IAmAMessageGateway gateway);
+
+ /// Executes the provisioning strategy asynchronously.
+ /// The messaging gateway whose infrastructure is provisioned.
+ Task ProvisionAsync(IAmAMessageGateway gateway, CancellationToken cancellationToken = default);
+}
+```
+
+The interface stays minimal by design: **everything a given strategy needs is a property of that implementation**, configured at construction/registration time — not parameters on the interface.
+
+### Strategy implementations per gateway — short names
+
+Naming is `{Gateway}[{Side}]{Strategy}`, keeping names short (no `InfrastructureProvisioner` suffix on classes).
+
+Each class implements `IAmAInfrastructureProvisioner` and carries **only the properties its strategy needs**:
+
+- **Assume** — does **nothing**; a pure no-op. It simply declares "the infrastructure exists and is managed externally" (e.g. Terraform) and returns immediately — no connectivity check, no SDK calls. Zero properties.
+- **Validate** — a few properties: the expected resource (topic/queue/subscription) to check, and how to report findings. Read-only; never mutates.
+- **Create** — the most properties: full resource specifications (DLQs, policies, delivery settings, tags, etc.) needed to materialize the infrastructure. Create-only: existing resources are never modified.
+- **CreateOrUpdate** — same property surface as Create, plus update behavior: existing resources are **converged** to the declared configuration. Only implemented where the broker supports in-place updates; opt-in, for dev/test or app-owned infrastructure. Production guidance remains Assume/Validate.
+
+**General rule:** whenever the publication side and the subscription side own **different resource types**, the gateway gets two sets — one per side. Where both sides share a single resource, one set suffices. Each set ships only the strategies the broker supports (Assume / Validate / Create / CreateOrUpdate).
+
+| Gateway (package) | Side | Assume | Validate | Create | CreateOrUpdate | Resources handled |
+|---|---|---|---|---|---|---|
+| RabbitMQ (`RMQ.Sync` / `RMQ.Async`) | Publication | `RmqExchangeAssume` | `RmqExchangeValidate` | `RmqExchangeCreate` | — (exchange properties immutable) | exchanges, type, durability |
+| | Subscription | `RmqQueueAssume` | `RmqQueueValidate` | `RmqQueueCreate` | `RmqQueueCreateOrUpdate` (policies/re-declare where legal) | queues, bindings to exchanges, DLX, TTL, quorum |
+| Kafka | Both (shared) | `KafkaAssume` | `KafkaValidate` | `KafkaCreate` | `KafkaCreateOrUpdate` (AlterConfigs; no partition decrease) | topics (AdminClient), partitions, replication factor |
+| AWS SNS (`AWSSQS` / `AWSSQS.V4`) | Publication | `SnsAssume` | `SnsValidate` | `SnsCreate` | `SnsCreateOrUpdate` (SetTopicAttributes, Tag/Untag) | topics, FIFO, KMS, tags |
+| AWS SQS (`AWSSQS` / `AWSSQS.V4`) | Subscription | `SqsAssume` | `SqsValidate` | `SqsCreate` | `SqsCreateOrUpdate` (SetQueueAttributes, Tag/UntagQueue) | queues, DLQs, redrive, SNS subscription wiring |
+| Azure Service Bus | Publication | `AsbTopicAssume` | `AsbTopicValidate` | `AsbTopicCreate` | `AsbTopicCreateOrUpdate` | topics, partitioning, duplicate detection |
+| | Subscription | `AsbSubscriptionAssume` | `AsbSubscriptionValidate` | `AsbSubscriptionCreate` | `AsbSubscriptionCreateOrUpdate` | subscriptions, rules/filters, queues (for direct), DLQ settings, lock duration |
+| GCP Pub/Sub | Publication | `GcpTopicAssume` | `GcpTopicValidate` | `GcpTopicCreate` | `GcpTopicCreateOrUpdate` (UpdateTopic) | topics, message retention, schema, KMS |
+| | Subscription | `GcpSubscriptionAssume` | `GcpSubscriptionValidate` | `GcpSubscriptionCreate` | `GcpSubscriptionCreateOrUpdate` (UpdateSubscription) | subscriptions, ack deadline, dead-letter policy, retry policy, filters, ordering |
+| Redis | Publication | `RedisStreamAssume` | `RedisStreamValidate` | `RedisStreamCreate` | `RedisStreamCreateOrUpdate` (XADD MAXLEN / XSETID where applicable) | streams (MKSTREAM), max length / trimming |
+| | Subscription | `RedisGroupAssume` | `RedisGroupValidate` | `RedisGroupCreate` | — (no group update API) | consumer groups on streams |
+| MsSql | Both (shared) | `MsSqlAssume` | `MsSqlValidate` | `MsSqlCreate` | `MsSqlCreateOrUpdate` (idempotent ALTER/migration DDL) | queue tables, indexes, stored procs (DDL scripts) |
+| Postgres | Both (shared) | `PostgresAssume` | `PostgresValidate` | `PostgresCreate` | `PostgresCreateOrUpdate` (idempotent ALTER/migration DDL) | queue tables, indexes, LISTEN/NOTIFY triggers (DDL scripts) |
+| RocketMQ | Publication | `RocketMqTopicAssume` | — | — | — | **Assume only** — topics cannot be created in flight by the client |
+| | Subscription | `RocketMqGroupAssume` | `RocketMqGroupValidate` | `RocketMqGroupCreate` | — | consumer groups, retry/DLQ topics |
+
+**CreateOrUpdate rules:**
+- Same property surface as the corresponding `Create` class; the difference is purely behavioral (converge vs. leave-alone).
+- Only ships where the broker exposes a real update API (see table). Where updates are impossible or unsafe (RabbitMQ exchange re-declaration with different type, Redis consumer groups, RocketMQ), the strategy is omitted rather than faked.
+- Updates are **additive/convergent, never destructive**: CreateOrUpdate never deletes resources, removes subscriptions, or drops data (e.g. no Kafka partition decrease, no queue purge). Destructive change belongs to IaC.
+- Still idempotent: running it repeatedly converges to the same state.
+
+### Which providers need the split, and which don't
+
+**Need the split (different resources per side):**
+- **GCP Pub/Sub** — yes: `GcpTopic*` (publication) vs `GcpSubscription*` (subscription). Topics and subscriptions are fully independent resources with different property sets (schema/KMS vs ack deadline/dead-letter/retry), managed by different admin clients (`PublisherServiceApiClient` vs `SubscriberServiceApiClient`).
+- **AWS** — split: `Sns*` / `Sqs*`.
+- **Azure Service Bus** — yes: `AsbTopic*` (publication) vs `AsbSubscription*` (subscription; also covers plain queues for direct-to-queue scenarios).
+- **RabbitMQ** — yes: `RmqExchange*` (publication) vs `RmqQueue*` (subscription). Exchanges and queues/bindings are distinct declarations with distinct properties; a publication shouldn't need queue/DLX settings.
+- **Redis** — yes, lightly: `RedisStream*` (publication, incl. trimming policy) vs `RedisGroup*` (subscription, consumer groups only).
+- **RocketMQ** — yes: `RocketMqTopic*` vs `RocketMqGroup*`.
+
+**Don't need the split (one shared resource):**
+- **Kafka** — the topic *is* the infrastructure for both sides; consumer groups are implicit and not provisionable. One set.
+- **MsSql / Postgres** — both sides share the same queue table; one set running idempotent DDL.
+
+### Per-gateway notes (checked against the actual gateway packages in the repo)
+
+- **AWS SNS vs SQS — separate provisioners.** The two services have genuinely different resource models: SNS owns topics, subscriptions, and topic-level policies/encryption; SQS owns queues, queue attributes, DLQs and redrive policies. A combined implementation would force both SDK clients into every scenario. Typically a **publication uses the SNS provisioner, a subscription uses the SQS provisioner** (with `SqsCreate` optionally subscribing its queue to the SNS topic). The provisioner classes live once in the AWS gateway code and are shared by the `AWSSQS` (SDK v3) and `AWSSQS.V4` packages, parameterized by the SDK-version-specific client — same pattern as the gateway itself.
+- **RabbitMQ — one provisioner set, shared by `RMQ.Sync` and `RMQ.Async`.** The exchange/queue split applies to both packages identically; the sync/async difference is in message flow, not infrastructure.
+- **Azure Service Bus — split into `AsbTopic*` / `AsbSubscription*`.** One admin SDK, but topic properties (partitioning, duplicate detection) and subscription properties (rules, lock duration, DLQ) are disjoint enough to warrant separate classes rather than one bag.
+- **GCP Pub/Sub — split into `GcpTopic*` / `GcpSubscription*`.** Mirrors the AWS split: separate admin clients and disjoint property sets.
+- **Kafka — Create is thin.** Only topics (with partitions/replication); consumer groups are created implicitly by the broker on first consume, so `KafkaValidate` can't validate them meaningfully. Validation depth is limited to topic existence and config via `AdminClient`.
+- **MsSql / Postgres — Create runs DDL.** "Infrastructure" is queue tables/indexes/triggers; `MsSqlCreate`/`PostgresCreate` apply idempotent DDL scripts (`IF NOT EXISTS`), `Validate` checks table/schema presence. Assume remains a no-op.
+- **MQTT — out of scope.** MQTT brokers hold no durable per-topic infrastructure to provision, so the MQTT gateway is explicitly excluded from this ADR; it keeps its current behavior and gets no provisioner set.
+- **Redis — streams + consumer groups.** `RedisStreamCreate` issues `XADD`/`XGROUP CREATE ... MKSTREAM` (idempotent via `BUSYGROUP` tolerance); `RedisStreamValidate` uses `XINFO`.
+- **RocketMQ — topic side is Assume-only.** RocketMQ topics cannot be created in flight from the client (broker-side `autoCreateTopicEnable` is discouraged/disabled in production and not a supported provisioning path for Brighter), so the publication side ships `RocketMqTopicAssume` only — no Validate, no Create. The subscription side (consumer groups, retry/DLQ topics) keeps Validate/Create via the admin API. This also establishes the precedent that **a side may ship a subset of the strategies** when the broker doesn't support the operation.
+
+### Current AWS behavior (baseline, verified against `AWSSQS.V4`)
+
+Today's `AWSMessagingGateway` is driven by an `OnMissingChannel` setting (`Create` / `Validate` / `Assume` — the conceptual ancestor of this ADR's strategies) and is **create-only, never update**:
+
+- `CreateTopic` is called because it is idempotent (returns the existing ARN), with attributes/tags supplied at call time.
+- `CreateQueue` is called only when the queue is missing.
+- There are **no** `SetQueueAttributes`, `SetTopicAttributes`, `TagResource`, or `TagQueue` calls — Brighter **does not update or converge** existing SNS/SQS resources. If a topic/queue already exists with different attributes, the current code silently keeps the existing configuration.
+
+**Decision carried into this ADR:** the `*Create` implementations preserve this **create-only, no-in-place-update** semantics — they create what is missing and leave existing resources untouched. This keeps `Create` backward-compatible and avoids Brighter silently mutating infrastructure.
+
+For users who *do* want Brighter to manage infrastructure actively, a fourth strategy ships alongside it: **`*CreateOrUpdate`** — creates missing resources and **updates existing ones** to the declared configuration (e.g. `SnsCreateOrUpdate` uses `SetTopicAttributes`/`TagResource`; `SqsCreateOrUpdate` uses `SetQueueAttributes`/`TagQueue`). It is strictly opt-in, only implemented where the broker supports updates, and never destructive. Drift detection remains `*Validate`'s job; `CreateOrUpdate` is the opt-in cure.
+
+## Sample: AWS SNS & SQS
+
+SNS and SQS get separate provisioner sets, used on different sides of the message flow. **Each provisioner instance serves exactly one `Publication` or one `Subscription`** — it is constructed for (and attached to) that single publication/subscription, so it provisions the one topic or one queue that publication/subscription routes to. There are no "all topics" / "all queues" god-provisioners; two subscriptions to different queues get two `SqsCreate` instances, each with its own settings.
+
+### SNS (publication side — one provisioner per Publication)
+
+```csharp
+using Paramore.Brighter;
+
+namespace Paramore.Brighter.MessagingGateway.AWSSNS;
+
+///
+/// Assumes this publication's SNS topic already exists (managed externally,
+/// e.g. Terraform). Does nothing — a pure no-op marker.
+///
+public sealed class SnsAssume : IAmAInfrastructureProvisioner
+{
+ public void Provision(IAmAMessageGateway gateway) { }
+
+ public Task ProvisionAsync(IAmAMessageGateway gateway, CancellationToken ct = default)
+ => Task.CompletedTask;
+}
+
+///
+/// Validates that this publication's SNS topic exists and is correctly
+/// configured. Never mutates anything.
+///
+public sealed class SnsValidate : IAmAInfrastructureProvisioner
+{
+ /// The topic this publication routes to; must exist.
+ public required string Topic { get; init; }
+
+ /// Whether topic attributes (FIFO, KMS encryption) must match the publication config.
+ public bool CheckAttributes { get; set; } = true;
+
+ public void Provision(IAmAMessageGateway gateway)
+ => ProvisionAsync(gateway).GetAwaiter().GetResult();
+
+ public async Task ProvisionAsync(IAmAMessageGateway gateway, CancellationToken ct = default)
+ {
+ // GetTopicAttributes for Topic. Throws a ProvisioningException if the
+ // topic is missing or (when CheckAttributes) misconfigured.
+ }
+}
+
+///
+/// Creates this publication's SNS topic if missing. Idempotent (CreateTopic
+/// returns the existing ARN). Requires SNS write permissions.
+///
+public sealed class SnsCreate : IAmAInfrastructureProvisioner
+{
+ /// The topic this publication routes to.
+ public required string Topic { get; init; }
+
+ /// Create the topic as a FIFO topic.
+ public bool UseFifo { get; set; }
+
+ /// KMS key id for topic server-side encryption (optional).
+ public string? KmsKeyId { get; set; }
+
+ /// Tags applied to the created topic.
+ public IDictionary Tags { get; set; } = new Dictionary();
+
+ public void Provision(IAmAMessageGateway gateway)
+ => ProvisionAsync(gateway).GetAwaiter().GetResult();
+
+ public async Task ProvisionAsync(IAmAMessageGateway gateway, CancellationToken ct = default)
+ {
+ // CreateTopic for Topic (idempotent — returns existing ARN),
+ // with FIFO/KMS attributes and Tags supplied at creation time.
+ // Create-only: an existing topic is left untouched (no
+ // SetTopicAttributes/TagResource), matching current Brighter behavior.
+ }
+}
+```
+
+### SQS (subscription side — one provisioner per Subscription)
+
+```csharp
+namespace Paramore.Brighter.MessagingGateway.AWSSQS;
+
+///
+/// Assumes this subscription's SQS queue already exists. Does nothing — a
+/// pure no-op marker.
+///
+public sealed class SqsAssume : IAmAInfrastructureProvisioner
+{
+ public void Provision(IAmAMessageGateway gateway) { }
+
+ public Task ProvisionAsync(IAmAMessageGateway gateway, CancellationToken ct = default)
+ => Task.CompletedTask;
+}
+
+///
+/// Validates that this subscription's SQS queue (and DLQ) exists, is correctly
+/// configured, and is subscribed to the expected SNS topic.
+/// Never mutates anything.
+///
+public sealed class SqsValidate : IAmAInfrastructureProvisioner
+{
+ /// The queue this subscription consumes from; must exist.
+ public required string Queue { get; init; }
+
+ /// Whether queue attributes (visibility timeout, redrive policy) must match the subscription config.
+ public bool CheckAttributes { get; set; } = true;
+
+ /// The SNS topic the queue must be subscribed to (optional check).
+ public string? SubscribedTopic { get; init; }
+
+ public void Provision(IAmAMessageGateway gateway)
+ => ProvisionAsync(gateway).GetAwaiter().GetResult();
+
+ public async Task ProvisionAsync(IAmAMessageGateway gateway, CancellationToken ct = default)
+ {
+ // GetQueueUrl / GetQueueAttributes for Queue; ListSubscriptionsByTopic
+ // when SubscribedTopic is set. Throws a ProvisioningException listing
+ // every mismatch found.
+ }
+}
+
+///
+/// Creates this subscription's SQS queue and DLQ if missing, attaches the
+/// redrive policy, and optionally subscribes the queue to its SNS topic.
+/// Idempotent. Requires SQS write permissions (plus SNS Subscribe if wiring).
+///
+public sealed class SqsCreate : IAmAInfrastructureProvisioner
+{
+ // ---- Queue ----
+ /// The queue this subscription consumes from.
+ public required string Queue { get; init; }
+
+ public TimeSpan VisibilityTimeout { get; set; } = TimeSpan.FromSeconds(30);
+ public TimeSpan MessageRetentionPeriod { get; set; } = TimeSpan.FromDays(4);
+ public TimeSpan ReceiveMessageWaitTime { get; set; } = TimeSpan.FromSeconds(20); // long polling
+ public bool UseFifo { get; set; }
+
+ // ---- Dead-letter queue ----
+ /// Create a DLQ named "{Queue}-DLQ" and attach a redrive policy.
+ public bool CreateDeadLetterQueue { get; set; } = true;
+ public int MaxReceiveCount { get; set; } = 3;
+
+ // ---- SNS wiring ----
+ /// The SNS topic to subscribe the queue to (null = plain queue, no SNS).
+ public string? SubscribeToTopic { get; init; }
+ public bool RawMessageDelivery { get; set; } = true;
+
+ /// Tags applied to the created queue.
+ public IDictionary Tags { get; set; } = new Dictionary();
+
+ public void Provision(IAmAMessageGateway gateway)
+ => ProvisionAsync(gateway).GetAwaiter().GetResult();
+
+ public async Task ProvisionAsync(IAmAMessageGateway gateway, CancellationToken ct = default)
+ {
+ // 1. CreateQueue for Queue and its DLQ, with attributes above, only
+ // when missing. Existing queues are left untouched (create-only,
+ // matching current Brighter behavior).
+ // 2. Redrive policy and tags are applied as part of creation.
+ // 3. When SubscribeToTopic is set: SNS Subscribe queue ARN → topic
+ // ARN with RawMessageDelivery; queue access policy allowing the
+ // topic to send (subscription creation is idempotent).
+ // No SetQueueAttributes/TagQueue on pre-existing resources — drift is
+ // surfaced by SqsValidate instead of being silently corrected.
+ }
+}
+```
+
+Note the separation of concerns: `SnsCreate` knows nothing about queues; `SqsCreate` only touches SNS to subscribe. A publication that produces directly to an SQS queue can attach `SqsCreate` with no SNS properties at all. And because each instance is scoped to one publication/subscription, settings are per-route: two subscriptions to different queues each get their own `SqsCreate` with independent visibility timeouts, DLQ policies, and tags.
+
+### CreateOrUpdate variants
+
+Where updates are supported, each `Create` class has a `CreateOrUpdate` sibling with the same properties and different behavior:
+
+```csharp
+///
+/// Creates this publication's SNS topic when missing AND updates an existing
+/// topic to the declared configuration. Opt-in; never destructive.
+///
+public sealed class SnsCreateOrUpdate : IAmAInfrastructureProvisioner
+{
+ // Same properties as SnsCreate: Topic, UseFifo, KmsKeyId, Tags.
+
+ public void Provision(IAmAMessageGateway gateway)
+ => ProvisionAsync(gateway).GetAwaiter().GetResult();
+
+ public async Task ProvisionAsync(IAmAMessageGateway gateway, CancellationToken ct = default)
+ {
+ // 1. CreateTopic for Topic (idempotent).
+ // 2. For an EXISTING topic: SetTopicAttributes where the current value
+ // differs from the declared one (e.g. KmsMasterKeyId).
+ // Immutable properties (FIFO on a standard topic) are reported as
+ // errors, not forced.
+ // 3. TagResource/UntagResource to converge Tags.
+ }
+}
+
+///
+/// Creates this subscription's SQS queue when missing AND updates an existing
+/// queue to the declared configuration (attributes, redrive policy, tags).
+/// Opt-in; never destructive — never purges or deletes the queue.
+///
+public sealed class SqsCreateOrUpdate : IAmAInfrastructureProvisioner
+{
+ // Same properties as SqsCreate.
+
+ public void Provision(IAmAMessageGateway gateway)
+ => ProvisionAsync(gateway).GetAwaiter().GetResult();
+
+ public async Task ProvisionAsync(IAmAMessageGateway gateway, CancellationToken ct = default)
+ {
+ // 1. CreateQueue for Queue/DLQ when missing.
+ // 2. For an EXISTING queue: GetQueueAttributes, then SetQueueAttributes
+ // for any attribute that differs (visibility timeout, retention,
+ // redrive policy, access policy).
+ // 3. Subscribe wiring as in SqsCreate (idempotent).
+ // 4. TagQueue/UntagQueue to converge Tags.
+ // Immutable differences (standard vs FIFO) are reported, not forced.
+ }
+}
+```
+
+Immutable or unsafe changes (e.g. converting a standard queue to FIFO, decreasing Kafka partitions) are **reported, never applied** — CreateOrUpdate converges what can be converged and fails loudly on the rest.
+
+### Wiring: provisioner on Publication and Subscription
+
+The provisioner is attached where provisioning decisions actually belong — the `Publication` (producer side) and the `Subscription` (consumer side):
+
+```csharp
+public class Publication
+{
+ // ... existing members ...
+
+ ///
+ /// How this publication's infrastructure is provisioned before the
+ /// producer is used. Null in V10 (not yet mandatory).
+ ///
+ public IAmAInfrastructureProvisioner? Provisioner { get; set; }
+}
+
+public class Subscription
+{
+ // ... existing members ...
+
+ ///
+ /// How this subscription's infrastructure is provisioned before the
+ /// channel is opened. Null in V10 (not yet mandatory).
+ ///
+ public IAmAInfrastructureProvisioner? Provisioner { get; set; }
+}
+```
+
+Because the provisioner is a property on `Publication`/`Subscription`, users can also **mix strategies in one app**: e.g. `SqsCreate` for a dev subscription, `SnsAssume` for a production publication managed by Terraform — no global mode switch.
+
+#### Workflow
+
+The workflow stays the same as today — provisioning still happens at producer creation and at channel open — but instead of **each provider doing it its own way** (ad-hoc inline code scattered across gateways), every gateway follows **one pattern**: resolve the provisioner from the `Publication`/`Subscription` and call the interface.
+
+```
+Producer path: build producer → publication.Provisioner?.ProvisionAsync(gateway) → send
+Consumer path: open channel → subscription.Provisioner?.ProvisionAsync(gateway) → receive
+```
+
+- Gateways implement the pattern once in their channel/producer factory base; no per-gateway provisioning logic anymore.
+
+#### Default provisioner resolution
+
+If the user doesn't supply a provisioner, the gateway **creates one from the current configuration** instead of running separate legacy logic:
+
+```csharp
+var provisioner = subscription.Provisioner
+ ?? gateway.CreateDefaultProvisioner(subscription); // built from existing config
+
+await provisioner.ProvisionAsync(gateway);
+```
+
+- Each gateway implements `CreateDefaultProvisioner(Publication|Subscription)`, which maps the existing (V10-deprecated) config onto the matching implementation — e.g. if the legacy config says "create queues on startup", it builds an `SqsCreate` populated from those settings; if it says nothing, it builds an `SqsAssume`.
+- This means there is **only ever one execution path** — `IAmAInfrastructureProvisioner` — even for users who never touch the new API. The legacy config becomes just another way to construct a provisioner, which keeps V10 safe and makes V11 removal a matter of deleting the mapping code, not untangling two provisioning pipelines.
+
+### Migration plan: V10 → V11
+
+**V10 (non-breaking, opt-in)**
+- `IAmAInfrastructureProvisioner` and the per-gateway `*Assume` / `*Validate` / `*Create` / `*CreateOrUpdate` implementations ship as new public API.
+- `Publication.Provisioner` / `Subscription.Provisioner` are added as **optional** (nullable). Not mandatory — existing code keeps working unchanged.
+- The existing per-gateway provisioning members on `Publication`/`Subscription` that become unnecessary (e.g. flags like "create topic/queue on startup", inline infrastructure settings now owned by `*Create`-style implementations) are marked `[Obsolete]` with a message pointing at the corresponding provisioner implementation.
+
+**V11 (breaking cleanup)**
+- The `[Obsolete]` properties are **removed** from `Publication`/`Subscription`.
+- `Provisioner` becomes the single, standard mechanism; gateways drop their legacy inline provisioning code paths entirely.
+
+This gives users a full major version to migrate: set a provisioner, delete usage of the deprecated flags, done.
+
+### Naming
+
+- Interface follows Brighter's `IAmA*` convention (`IAmAChannelFactory`, `IAmAMessageProducer`, `IAmACommandProcessor`).
+- Class names stay short: `RmqQueueCreate`, `SnsValidate`, etc. — the strategy is the name; the implemented interface supplies the "infrastructure provisioner" context.
+- "Provisioner" rather than "Manager" signals narrow scope: assume / validate / create / create-or-update only. Destruction and drift reconciliation are explicitly out of scope.
+
+## Consequences
+
+**Positive**
+- One consistent lifecycle for gateway infrastructure across all transports.
+- Fast, diagnosable startup failures via the Validate implementations.
+- Idempotent Create implementations simplify local dev and integration testing.
+- Assume implementations are no-ops supporting "infra managed by Terraform" environments — no SDK calls, no credentials required for provisioning at all, and creation code is not even present.
+- Per-strategy properties keep each class's surface proportional to its job; no god-object options bag shared by all four strategies.
+- CreateOrUpdate offers an opt-in convergence path for teams that want Brighter to actively manage dev/test infrastructure, without changing Create's backward-compatible behavior.
+
+**Negative / Risks**
+- Class count: up to 4 classes × sides × gateways (a shared abstract base per gateway can hold common resource-descriptor logic to keep them thin).
+- V10 carries dual provisioning paths (legacy inline + provisioner) until V11 removes the legacy ones — gateways must be careful the two never both run. (Mitigated by default-provisioner resolution: legacy config is translated into a provisioner, so only one pipeline ever executes.)
+- Some admin APIs (e.g. older Kafka clients) have limited validation capability, so Validate depth will vary per gateway.
+- New dependency on admin APIs (AWS SDK SNS/SQS, Confluent AdminClient, etc.) increases package surface for each gateway package.
+- `Create`/`CreateOrUpdate` with broad cloud permissions is a security footgun — `CreateOrUpdate` doubly so, since it mutates existing resources. Documentation must recommend least-privilege, opt-in use, and default `Assume`/`Validate` in production.
+
+## Alternatives Considered
+
+1. **One interface with `AssumeAsync`/`ValidateAsync`/`CreateAsync` methods** — rejected: forces every implementation to carry all strategy code paths (and their SDK dependencies/permissions), invites internal `switch` behavior, and blurs least-privilege boundaries. Separate implementations of a small interface is cleaner.
+2. **One options bag on the interface** — rejected: `Create`'s large property surface would pollute `Assume`/`Validate`; per-implementation properties keep each class honest.
+3. **Keep per-gateway ad-hoc provisioning** — rejected: inconsistent behavior and poor diagnostics; the problem this ADR solves.
+4. **Infrastructure-as-Code only (document Terraform/Pulumi)** — rejected as the sole answer: still the recommended production path (Assume), but doesn't help the dev/test inner loop or startup validation.
+5. **Single generic provisioner driven by declarative config** — rejected: each broker's resource model differs too much; a leaky abstraction would result.
+
+## Open Questions
+
+- Should there be a shared abstract base per gateway (holding the resource descriptor) that the strategy implementations derive from?
+- Do we expose a CLI/health-check endpoint that runs the registered provisioner on demand?
+- Should the sync `Provision` exist at all for gateways whose SDKs are async-only (AWS SDK is async)? Keep it for interface parity with the gateway, or drop it?