# Experimental 정책 ## Stable과 Experimental의 차이 **Stable**은 공통 Contract Suite(`MessagingAdapterContract`)를 변경 없이 통과한 어댑터다. 컴파일되는 어댑터가 아니라, 아래 7가지를 실제로 증명한 어댑터다. ```text publishesAndConfirms returnsAmbiguousWhenConfirmIsLost redeliversWhenSettlementIsLost preservesMessageIdAcrossRetryAndDlq keepsSourceUnsettledWhenDlqPublishFails rejectsOversizedPayloadBeforeTransport stopsAcceptingNewWorkDuringShutdown ``` **Experimental**은 아직 그 증명이 끝나지 않은 어댑터다. ## 규칙 ### 1. 기본 비활성 ```yaml messaging.experimental.kafka-share: false messaging.experimental.pulsar: false messaging.experimental.nats: false ``` 활성화하지 않으면 validator가 `MessagingCapabilityUnavailableException`을 던진다. Contract Suite가 아직 증명 중인 어댑터가 누군가의 기본 설정 때문에 load-bearing이 되어서는 안 된다. ### 2. Stable 모듈이 Experimental 모듈에 의존하지 않는다 Gradle 의존 그래프로 강제된다. `messaging-spring-boot-starter`의 `allowed_dependencies`에 `messaging-kafka-share-experimental`, `messaging-pulsar-experimental`, `messaging-nats-experimental`, `messaging-spring-cloud-stream-bridge`가 **없다**. `verifyCleanArchitectureDependencies`가 위반을 빌드 실패로 만든다. ### 3. Core 계약을 바꾸지 않는다 Experimental 어댑터는 브로커의 차이를 `MessagingCapabilities`로 표현할 뿐, `messaging-core-api`의 타입을 바꾸지 않는다. ### 4. 없는 기능을 광고하지 않는다 | 어댑터 | 광고하지 않는 것 | 이유 | |---|---|---| | Kafka Share Group | orderedStream, keyedOrdering, replay, brokerTransaction | 경쟁 소비자 + 개별 ack는 partition 순서를 유지할 수 없다 | | Pulsar | brokerTransaction | Pulsar에 있지만 플랫폼 Contract Suite로 증명되지 않았다 | | Pulsar (Shared) | keyedOrdering | round-robin 분배 | | NATS JetStream | nativeDeadLetter | delivery limit 초과 시 terminate할 뿐 라우팅하지 않는다 | | NATS JetStream | keyedOrdering | subject 기반 모델에 per-key 순서가 없다 | `false`인 capability를 요구하는 profile은 startup에서 실패한다. 조용히 약화되지 않는다. ### 5. 명시적 거부 | 조합 | 결과 | |---|---| | Kafka Share Group + ordering != NONE | 거부 | | Kafka Share Group + pause/resume | `MessagingCapabilityUnavailableException` | | Pulsar Shared + ordering=KEY | 거부 (Key_Shared 필요) | | Pulsar + ordering=DESTINATION | 거부 | | NATS Core + AT_LEAST_ONCE | 거부 (JetStream 필요) | | NATS ordered consumer + 경쟁 워커 > 1 | 거부 | | NATS + ordering=KEY | 거부 | ## Spring Cloud Stream bridge Experimental이 아니라 **Optional**이다. 위험이 다르다. Stream은 자체 binder 설정을 소유하므로, binding이 destination profile이 모르는 serializer·error handling·acknowledgement mode를 조용히 획득할 수 있다. 따라서 브리지는 **플랫폼 보장에 의존하지 않는 destination에만** 허용한다. ```text ordering scope 선언 → 거부 retry policy 선언 → 거부 dead letter 선언 → 거부 ``` 이 셋 중 하나라도 필요하면 native adapter를 쓴다. 거기서만 실제로 강제되기 때문이다. ## 승격 조건 Experimental → Stable로 올리려면 전부 필요하다. 1. `MessagingAdapterContract` 7개 테스트를 변경 없이 통과 2. 장애 주입(연결 끊김, confirm 유실, settlement 유실) 하에서 통과 3. 지원 브로커 버전 범위 명시 및 CI 검증 4. `support-matrix.md`의 capability 표 갱신 5. ADR 작성 6. 기본 활성화 여부에 대한 별도 결정