{ "schema_version": "1.0", "document": "/home/donghyeon/workspace/chat-gpt-container/document-haness/docs/clean-architecture-backend-template/final/document.md", "document_sha256": "8071fe71b3359d9cf60b95909c26c7b50653ce2f22bbc5fcf6988719bb91236d", "line_count": 47035, "line_number_space": "canonical-source-with-managed-blocks-collapsed", "anchor": { "kind": "line", "value": 30504, "line": 30504 }, "current_section": { "heading": { "line": 30504, "level": 5, "text": "4.1 `MessagingTags` — 닫힌 6차원" }, "start_line": 30504, "end_line": 30524, "text": "##### 4.1 `MessagingTags` — 닫힌 6차원\n\n```java\n// :8-14\n *
It is a fixed record rather than an open map on purpose. Every field here is bounded by\n * configuration or by an enum, so the cardinality of the metric is known before it is ever scraped.\n * Message ids, partition keys, tenant ids, and offsets are all deliberately absent: each of them is\n * unbounded at runtime and would multiply every series by the message volume.\n```\n\n여섯 차원: `broker`, `destinationProfile`, `operation`, `outcome`, `failureCategory`, `retryStage`. 없는 값은 `NONE = \"none\"`이다 — null도 빈 문자열도 아니고 명시적 sentinel이다.\n\n**두 factory의 차이가 §12.1의 핵심이 된다.**\n\n| factory | failureCategory | retryStage |\n|---|---|---|\n| `new MessagingTags(6개 인자)` | 호출자가 지정 | 호출자가 지정 |\n| `MessagingTags.of(4개 인자)` | **`NONE` 고정** | **`NONE` 고정** |\n\n`asMap()`이 `LinkedHashMap`으로 순서를 고정하고 `Map.copyOf`로 불변화한다.\n" }, "previous_section": { "heading": { "line": 30502, "level": 4, "text": "4. 계약·불변식·상태 모델" }, "start_line": 30502, "end_line": 30503, "text": "#### 4. 계약·불변식·상태 모델\n" }, "next_section": { "heading": { "line": 30525, "level": 5, "text": "4.2 `DefaultMessagingObservationConvention` — 태그 값이 공개 계약이다" }, "start_line": 30525, "end_line": 30541, "text": "##### 4.2 `DefaultMessagingObservationConvention` — 태그 값이 공개 계약이다\n\n```java\n// :12-18\n *
Centralised because the tag values are a public contract: dashboards, alert rules, and SLOs\n * are written against these exact strings, so an adapter inventing its own spelling of \"rejected\"\n * silently breaks every alert that was watching for it. The conversion lives here, once, rather\n * than at each call site.\n *\n *
Only bounded inputs are accepted. Every parameter is an enum or a configured name, which is\n * what lets {@link CardinalityGuard} bound the resulting series.\n```\n\n네 메서드와 네 상수(`PUBLISH`, `CONSUME`, `SETTLE`, `DEAD_LETTER`). `publish(...)`는 `PublishCompletion`과 `Optional It is a fixed record rather than an open map on purpose. Every field here is bounded by"
},
{
"line": 30509,
"text": " * configuration or by an enum, so the cardinality of the metric is known before it is ever scraped."
},
{
"line": 30510,
"text": " * Message ids, partition keys, tenant ids, and offsets are all deliberately absent: each of them is"
},
{
"line": 30511,
"text": " * unbounded at runtime and would multiply every series by the message volume."
},
{
"line": 30512,
"text": "```"
},
{
"line": 30513,
"text": ""
},
{
"line": 30514,
"text": "여섯 차원: `broker`, `destinationProfile`, `operation`, `outcome`, `failureCategory`, `retryStage`. 없는 값은 `NONE = \"none\"`이다 — null도 빈 문자열도 아니고 명시적 sentinel이다."
},
{
"line": 30515,
"text": ""
},
{
"line": 30516,
"text": "**두 factory의 차이가 §12.1의 핵심이 된다.**"
},
{
"line": 30517,
"text": ""
},
{
"line": 30518,
"text": "| factory | failureCategory | retryStage |"
},
{
"line": 30519,
"text": "|---|---|---|"
},
{
"line": 30520,
"text": "| `new MessagingTags(6개 인자)` | 호출자가 지정 | 호출자가 지정 |"
},
{
"line": 30521,
"text": "| `MessagingTags.of(4개 인자)` | **`NONE` 고정** | **`NONE` 고정** |"
},
{
"line": 30522,
"text": ""
},
{
"line": 30523,
"text": "`asMap()`이 `LinkedHashMap`으로 순서를 고정하고 `Map.copyOf`로 불변화한다."
},
{
"line": 30524,
"text": ""
},
{
"line": 30525,
"text": "##### 4.2 `DefaultMessagingObservationConvention` — 태그 값이 공개 계약이다"
},
{
"line": 30526,
"text": ""
},
{
"line": 30527,
"text": "```java"
},
{
"line": 30528,
"text": "// :12-18"
},
{
"line": 30529,
"text": " * Centralised because the tag values are a public contract: dashboards, alert rules, and SLOs"
},
{
"line": 30530,
"text": " * are written against these exact strings, so an adapter inventing its own spelling of \"rejected\""
},
{
"line": 30531,
"text": " * silently breaks every alert that was watching for it. The conversion lives here, once, rather"
},
{
"line": 30532,
"text": " * than at each call site."
},
{
"line": 30533,
"text": " *"
},
{
"line": 30534,
"text": " * Only bounded inputs are accepted. Every parameter is an enum or a configured name, which is"
},
{
"line": 30535,
"text": " * what lets {@link CardinalityGuard} bound the resulting series."
},
{
"line": 30536,
"text": "```"
},
{
"line": 30537,
"text": ""
},
{
"line": 30538,
"text": "네 메서드와 네 상수(`PUBLISH`, `CONSUME`, `SETTLE`, `DEAD_LETTER`). `publish(...)`는 `PublishCompletion`과 `Optional It is a fixed record rather than an open map on purpose. Every field here is bounded by\n30509 | * configuration or by an enum, so the cardinality of the metric is known before it is ever scraped.\n30510 | * Message ids, partition keys, tenant ids, and offsets are all deliberately absent: each of them is\n30511 | * unbounded at runtime and would multiply every series by the message volume.\n30512 | ```\n30513 | \n30514 | 여섯 차원: `broker`, `destinationProfile`, `operation`, `outcome`, `failureCategory`, `retryStage`. 없는 값은 `NONE = \"none\"`이다 — null도 빈 문자열도 아니고 명시적 sentinel이다.\n30515 | \n30516 | **두 factory의 차이가 §12.1의 핵심이 된다.**\n30517 | \n30518 | | factory | failureCategory | retryStage |\n30519 | |---|---|---|\n30520 | | `new MessagingTags(6개 인자)` | 호출자가 지정 | 호출자가 지정 |\n30521 | | `MessagingTags.of(4개 인자)` | **`NONE` 고정** | **`NONE` 고정** |\n30522 | \n30523 | `asMap()`이 `LinkedHashMap`으로 순서를 고정하고 `Map.copyOf`로 불변화한다.\n30524 | \n30525 | ##### 4.2 `DefaultMessagingObservationConvention` — 태그 값이 공개 계약이다\n30526 | \n30527 | ```java\n30528 | // :12-18\n30529 | * Centralised because the tag values are a public contract: dashboards, alert rules, and SLOs\n30530 | * are written against these exact strings, so an adapter inventing its own spelling of \"rejected\"\n30531 | * silently breaks every alert that was watching for it. The conversion lives here, once, rather\n30532 | * than at each call site.\n30533 | *\n30534 | * Only bounded inputs are accepted. Every parameter is an enum or a configured name, which is\n30535 | * what lets {@link CardinalityGuard} bound the resulting series.\n30536 | ```\n30537 | \n30538 | 네 메서드와 네 상수(`PUBLISH`, `CONSUME`, `SETTLE`, `DEAD_LETTER`). `publish(...)`는 `PublishCompletion`과 `Optional