# 주제: Debezium 커넥터 설정이 두 곳에 있고, 운영자가 실제로 배포하는 쪽이 수정 이전 버전이다
# revision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916
# severity: P2

# ---- 표현 1: Java ----
# DebeziumOutboxEventRouter.java:35-85
#   public static final String KEY_COLUMN = "routing_key";
#   public Map<String, String> connectorConfiguration(String topicPrefix) {
#     configuration.put("transforms.outbox.table.field.event.key", KEY_COLUMN);      // routing_key
#     configuration.put("transforms.outbox.route.by.field", ROUTE_BY_COLUMN);        // destination
#     configuration.put("transforms.outbox.route.topic.replacement", topicPrefix + "${routedByValue}");
#     configuration.put("transforms.outbox.table.fields.additional.placement", <15개>);
#   }
#
# 클래스 javadoc:21-26 이 고친 결함을 명시한다:
#   "The message key and the topic are two different questions and used to be answered by one
#    column. `destination` routed the topic *and* became the key, so every message on a topic
#    carried the same key, landed on one partition, and made keyed ordering a claim with no
#    mechanism behind it. The key now comes from `routing_key` …"

# ---- 표현 2: 배포되는 리소스 ----
# src/main/resources/debezium/outbox-event-router.properties:28
#   transforms.outbox.table.field.event.key=destination        <-- 수정 이전 값
# :33
#   transforms.outbox.route.topic.replacement=${routedByValue}  <-- 프리픽스 없음
# :30
#   transforms.outbox.table.field.event.timestamp=created_at    <-- Java 에는 없는 키
# :37
#   transforms.outbox.table.fields.additional.placement=
#     message_type:header:msg.type,
#     schema_version:header:msg.schema-version,
#     content_type:header:msg.content-type,
#     message_id:header:msg.id                                  <-- 4개

# ---- 측정 ----
# command: (Java) sed -n "66,83p" DebeziumOutboxEventRouter.java | grep -c "header:"
#   15
# command: (properties) grep "additional.placement" …properties | tr "," "\n" | grep -c "header:"
#   4
# command: grep "event.key" …properties
#   transforms.outbox.table.field.event.key=destination

# properties 에 없는 11개 헤더: created_at(PRODUCED_AT), destination(ORIGIN_DESTINATION),
#   producer, occurred_at, correlation_id, causation_id, tenant, partition_key, ordering_key,
#   traceparent, tracestate, baggage
#   (= V4__messaging_outbox_canonical_metadata.sql 이 추가한 정경 메타데이터 전부)
# V4 주석:6-9 "Everything else the envelope carries … had nowhere to go, so it was either lost
#   when the relay rebuilt the envelope or smuggled through the header map"
#   -> 그 손실을 막으려고 컬럼을 만들었는데, CDC 배포 파일은 그 컬럼들을 헤더로 옮기지 않는다.

# ---- 두 표현을 잇는 것이 없다 ----
# command: git grep -rn "outbox-event-router" -- src
# exit: 1  (출력 없음)
# => properties 파일을 읽는 코드도, 그 내용을 Java 설정과 대조하는 테스트도 없다.

# ---- 테스트는 Java 쪽만 검증하며, 그 테스트는 의도적으로 견고하게 작성되어 있다 ----
# DebeziumOutboxRecordMapperTest.java:154-162
#   @Test
#   void theRoutedKeyIsNotTheTopicName() {
#     // Literals, not the class's own constants: comparing a configuration value against the
#     // constant that produced it asserts that the router agrees with itself, which it always will.
#     assertThat(new DebeziumOutboxEventRouter().connectorConfiguration("prod."))
#         .as("keying by destination puts every message on a topic onto one partition")
#         .containsEntry("transforms.outbox.table.field.event.key", "routing_key")
#         .containsEntry("transforms.outbox.route.by.field", "destination");
#   }
# => 리터럴 대조까지 하는 테스트가 Java 를 지키고 있고, 운영자가 배포하는 파일은 아무도 지키지 않는다.

# ---- 부수 발견: aggregateIdAsPartitionKey 는 커넥터에 도달할 수 없다 ----
# DebeziumOutboxProfile 은 aggregateIdAsPartitionKey 필드를 갖는다(:20).
# DebeziumOutboxRecordMapper 는 그것으로 분기한다(:70-78):
#   if (!aggregateIdAsPartitionKey) { return Optional.empty(); }
# 그러나 connectorConfiguration(String topicPrefix) 는 프로필을 받지 않으며(:55),
# event.key 를 항상 routing_key 로 고정한다(:60).
# => 플래그가 false 여도 실제 Debezium 은 키를 붙인다. 모델(mapper)은 "키 없음" 을 예측한다.
#    mapper 의 존재 이유가 "Produces what Debezium's Event Router will emit"(:11) 인데,
#    기본값(polling() -> false)에서 그 예측이 커넥터 설정과 불일치한다.
