---
template: policy-doc@1
doc_id: 01-treat-providers
title: 진료 공급자 연동 — 코드가 정하는 것과 편성이 정하는 것
config: ../_meta/template-config.yaml
last_verified: 4d798f55
policies:
  - id: treat-provider:codef:timeout
    status: conditional-unknown
    evidence: [A-vendor, S-constant]
    unknown_reason: 요청 만료 시점을 정하는 층이다. 만료 뒤 호출자가 어느 분기로 가는가는 동결 stg 4d798f55 의 코드로 확정되지만, 그 분기가 발효하려면 이 벤더가 먼저 공급자 풀에 들어야 한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 재유도된 게이트 종류는 `env` 이고 닫을 경로가 이 PRD 범위 밖이다. 만료 값 자체는 이 문서가 옮기지 않는다(30-contracts-limits 소유).
    anchors:
      - insuniverse-server/libs/codef/src/codef.service.ts:98
      - insuniverse-server/libs/codef/src/codef.service.ts:153
      - insuniverse-server/libs/codef/src/codef.service.ts:176
      - insuniverse-server/libs/codef/src/codef.service.ts:215
  - id: treat-provider:codef:fallback
    status: conditional-unknown
    evidence: [A-vendor, S-constant]
    unknown_reason: 이 벤더가 멀티 디스패치 폴백의 후보인가를 정하는 층이다. 후보 목록은 코드가 정하지만 실제 풀은 편성값이 정한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 재유도된 게이트 종류는 `none` 이고 닫을 경로가 이 PRD 범위 밖이다. 게이트 종류가 `none` 인 것은 이 층의 앵커 파일에서 DB 토큰도 env 토큰도 관측되지 않았다는 뜻이지 미명세가 아니다.
    anchors:
      - insuniverse-server/apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts:73
  - id: treat-provider:codef:normalization
    status: conditional-unknown
    evidence: [A-vendor, S-constant]
    unknown_reason: 정규화 매퍼가 없다는 것이 이 층의 내용이다 — 응답을 그대로 응답 DTO 로 옮기거나 자기 형태를 정본으로 쓴다. **관측된 부재다.** 그 형태가 발효하려면 이 벤더가 풀에 들어야 한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 재유도된 게이트 종류는 `env` 이고 닫을 경로가 이 PRD 범위 밖이다.
    anchors:
      - insuniverse-server/libs/codef/src/codef.service.ts:98
      - insuniverse-server/libs/codef/src/codef.service.ts:153
      - insuniverse-server/libs/codef/src/codef.service.ts:176
      - insuniverse-server/libs/codef/src/codef.service.ts:215
  - id: treat-provider:codef:env_gates
    status: conditional-unknown
    evidence: [A-vendor, S-constant]
    unknown_reason: 이 벤더 연동이 서려면 설정 블록의 환경 키가 주입돼야 한다는 것이 이 층의 내용이다. 키 **이름**은 런타임 인덱스가 열거하지만 값은 저장소 밖이고 이 문서도 이름을 나열하지 않는다(11-index-code · 12-index-runtime 소유). 재유도된 게이트 종류는 `env` 이고 닫을 경로가 이 PRD 범위 밖이다.
    anchors:
      - insuniverse-server/apps/api/src/config/configuration.ts:16
  - id: treat-provider:coocon:timeout
    status: conditional-unknown
    evidence: [A-vendor, S-constant]
    unknown_reason: 요청 만료 시점을 정하는 층이다. 만료 뒤 호출자가 어느 분기로 가는가는 동결 stg 4d798f55 의 코드로 확정되지만, 그 분기가 발효하려면 이 벤더가 먼저 공급자 풀에 들어야 한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 재유도된 게이트 종류는 `env` 이고 닫을 경로가 이 PRD 범위 밖이다. 만료 값 자체는 이 문서가 옮기지 않는다(30-contracts-limits 소유).
    anchors:
      - insuniverse-server/libs/coocon/src/coocon-auth.service.ts:84
      - insuniverse-server/libs/coocon/src/coocon-auth.service.ts:98
  - id: treat-provider:coocon:fallback
    status: conditional-unknown
    evidence: [A-vendor, S-constant]
    unknown_reason: 이 벤더가 멀티 디스패치 폴백의 후보인가를 정하는 층이다. 후보 목록은 코드가 정하지만 실제 풀은 편성값이 정한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 재유도된 게이트 종류는 `none` 이고 닫을 경로가 이 PRD 범위 밖이다. 게이트 종류가 `none` 인 것은 이 층의 앵커 파일에서 DB 토큰도 env 토큰도 관측되지 않았다는 뜻이지 미명세가 아니다.
    anchors:
      - insuniverse-server/apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts:73
  - id: treat-provider:coocon:normalization
    status: conditional-unknown
    evidence: [A-vendor, S-constant]
    unknown_reason: 벤더 응답을 어느 DTO 형태로 접는가를 정하는 층이다. 매퍼 파일과 변환 대상은 코드로 확정되지만 그 변환이 실행되려면 이 벤더가 풀에 들어야 한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 재유도된 게이트 종류는 `none` 이고 닫을 경로가 이 PRD 범위 밖이다. 게이트 종류가 `none` 인 것은 이 층의 앵커 파일에서 DB 토큰도 env 토큰도 관측되지 않았다는 뜻이지 미명세가 아니다.
    anchors:
      - insuniverse-server/libs/coocon/src/coocon.mapper.ts:19
  - id: treat-provider:coocon:env_gates
    status: conditional-unknown
    evidence: [A-vendor, S-constant]
    unknown_reason: 이 벤더 연동이 서려면 설정 블록의 환경 키가 주입돼야 한다는 것이 이 층의 내용이다. 키 **이름**은 런타임 인덱스가 열거하지만 값은 저장소 밖이고 이 문서도 이름을 나열하지 않는다(11-index-code · 12-index-runtime 소유). 재유도된 게이트 종류는 `env` 이고 닫을 경로가 이 PRD 범위 밖이다.
    anchors:
      - insuniverse-server/apps/api/src/config/configuration.ts:49
  - id: treat-provider:hyphen:timeout
    status: conditional-unknown
    evidence: [A-vendor, S-constant]
    unknown_reason: 요청 만료 시점을 정하는 층이다. 만료 뒤 호출자가 어느 분기로 가는가는 동결 stg 4d798f55 의 코드로 확정되지만, 그 분기가 발효하려면 이 벤더가 먼저 공급자 풀에 들어야 한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 재유도된 게이트 종류는 `env` 이고 닫을 경로가 이 PRD 범위 밖이다. 만료 값 자체는 이 문서가 옮기지 않는다(30-contracts-limits 소유).
    anchors:
      - insuniverse-server/libs/hyphen/src/hyphen.service.ts:287
      - insuniverse-server/libs/hyphen/src/hyphen.service.ts:368
  - id: treat-provider:hyphen:fallback
    status: conditional-unknown
    evidence: [A-vendor, S-constant]
    unknown_reason: 이 벤더가 멀티 디스패치 폴백의 후보인가를 정하는 층이다. 후보 목록은 코드가 정하지만 실제 풀은 편성값이 정한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 재유도된 게이트 종류는 `none` 이고 닫을 경로가 이 PRD 범위 밖이다. 게이트 종류가 `none` 인 것은 이 층의 앵커 파일에서 DB 토큰도 env 토큰도 관측되지 않았다는 뜻이지 미명세가 아니다.
    anchors:
      - insuniverse-server/apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts:73
  - id: treat-provider:hyphen:normalization
    status: conditional-unknown
    evidence: [A-vendor, S-constant]
    unknown_reason: 벤더 응답을 어느 DTO 형태로 접는가를 정하는 층이다. 매퍼 파일과 변환 대상은 코드로 확정되지만 그 변환이 실행되려면 이 벤더가 풀에 들어야 한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 재유도된 게이트 종류는 `none` 이고 닫을 경로가 이 PRD 범위 밖이다. 게이트 종류가 `none` 인 것은 이 층의 앵커 파일에서 DB 토큰도 env 토큰도 관측되지 않았다는 뜻이지 미명세가 아니다.
    anchors:
      - insuniverse-server/libs/hyphen/src/hyphen.mapper.ts:16
  - id: treat-provider:hyphen:env_gates
    status: conditional-unknown
    evidence: [A-vendor, S-constant]
    unknown_reason: 이 벤더 연동이 서려면 설정 블록의 환경 키가 주입돼야 한다는 것이 이 층의 내용이다. 키 **이름**은 런타임 인덱스가 열거하지만 값은 저장소 밖이고 이 문서도 이름을 나열하지 않는다(11-index-code · 12-index-runtime 소유). 재유도된 게이트 종류는 `env` 이고 닫을 경로가 이 PRD 범위 밖이다.
    anchors:
      - insuniverse-server/apps/api/src/config/configuration.ts:67
  - id: treat-provider:inhouse:timeout
    status: conditional-unknown
    evidence: [A-vendor, S-constant]
    unknown_reason: 요청 만료 시점을 정하는 층이다. 만료 뒤 호출자가 어느 분기로 가는가는 동결 stg 4d798f55 의 코드로 확정되지만, 그 분기가 발효하려면 이 벤더가 먼저 공급자 풀에 들어야 한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 재유도된 게이트 종류는 `env` 이고 닫을 경로가 이 PRD 범위 밖이다. 만료 값 자체는 이 문서가 옮기지 않는다(30-contracts-limits 소유).
    anchors:
      - insuniverse-server/libs/inhouse/src/inhouse.service.ts:298
      - insuniverse-server/libs/inhouse/src/inhouse.service.ts:321
      - insuniverse-server/libs/inhouse/src/inhouse.service.ts:345
      - insuniverse-server/libs/inhouse/src/inhouse.service.ts:374
  - id: treat-provider:inhouse:fallback
    status: conditional-unknown
    evidence: [A-vendor, S-constant]
    unknown_reason: 이 벤더가 멀티 디스패치 폴백의 후보인가를 정하는 층이다. 후보 목록은 코드가 정하지만 실제 풀은 편성값이 정한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 재유도된 게이트 종류는 `none` 이고 닫을 경로가 이 PRD 범위 밖이다. 게이트 종류가 `none` 인 것은 이 층의 앵커 파일에서 DB 토큰도 env 토큰도 관측되지 않았다는 뜻이지 미명세가 아니다.
    anchors:
      - insuniverse-server/apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts:73
  - id: treat-provider:inhouse:normalization
    status: conditional-unknown
    evidence: [A-vendor, S-constant]
    unknown_reason: 정규화 매퍼가 없다는 것이 이 층의 내용이다 — 응답을 그대로 응답 DTO 로 옮기거나 자기 형태를 정본으로 쓴다. **관측된 부재다.** 그 형태가 발효하려면 이 벤더가 풀에 들어야 한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 재유도된 게이트 종류는 `env` 이고 닫을 경로가 이 PRD 범위 밖이다.
    anchors:
      - insuniverse-server/libs/inhouse/src/inhouse.service.ts:298
      - insuniverse-server/libs/inhouse/src/inhouse.service.ts:321
      - insuniverse-server/libs/inhouse/src/inhouse.service.ts:345
      - insuniverse-server/libs/inhouse/src/inhouse.service.ts:374
  - id: treat-provider:inhouse:env_gates
    status: conditional-unknown
    evidence: [A-vendor, S-constant]
    unknown_reason: 이 벤더 연동이 서려면 설정 블록의 환경 키가 주입돼야 한다는 것이 이 층의 내용이다. 키 **이름**은 런타임 인덱스가 열거하지만 값은 저장소 밖이고 이 문서도 이름을 나열하지 않는다(11-index-code · 12-index-runtime 소유). 재유도된 게이트 종류는 `env` 이고 닫을 경로가 이 PRD 범위 밖이다.
    anchors:
      - insuniverse-server/apps/api/src/config/configuration.ts:79
  - id: treat-provider:octover:timeout
    status: conditional-unknown
    evidence: [A-vendor, S-constant]
    unknown_reason: 요청 만료 시점을 정하는 층이다. 만료 뒤 호출자가 어느 분기로 가는가는 동결 stg 4d798f55 의 코드로 확정되지만, 그 분기가 발효하려면 이 벤더가 먼저 공급자 풀에 들어야 한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 재유도된 게이트 종류는 `env` 이고 닫을 경로가 이 PRD 범위 밖이다. 만료 값 자체는 이 문서가 옮기지 않는다(30-contracts-limits 소유).
    anchors:
      - insuniverse-server/libs/octover/src/octover.service.ts:320
  - id: treat-provider:octover:fallback
    status: conditional-unknown
    evidence: [A-vendor, S-constant]
    unknown_reason: 이 벤더가 멀티 디스패치 폴백의 후보인가를 정하는 층이다. 후보 목록은 코드가 정하지만 실제 풀은 편성값이 정한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 재유도된 게이트 종류는 `none` 이고 닫을 경로가 이 PRD 범위 밖이다. 게이트 종류가 `none` 인 것은 이 층의 앵커 파일에서 DB 토큰도 env 토큰도 관측되지 않았다는 뜻이지 미명세가 아니다.
    anchors:
      - insuniverse-server/apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts:73
  - id: treat-provider:octover:normalization
    status: conditional-unknown
    evidence: [A-vendor, S-constant]
    unknown_reason: 벤더 응답을 어느 DTO 형태로 접는가를 정하는 층이다. 매퍼 파일과 변환 대상은 코드로 확정되지만 그 변환이 실행되려면 이 벤더가 풀에 들어야 한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 재유도된 게이트 종류는 `none` 이고 닫을 경로가 이 PRD 범위 밖이다. 게이트 종류가 `none` 인 것은 이 층의 앵커 파일에서 DB 토큰도 env 토큰도 관측되지 않았다는 뜻이지 미명세가 아니다.
    anchors:
      - insuniverse-server/libs/octover/src/octover.mapper.ts:16
  - id: treat-provider:octover:env_gates
    status: conditional-unknown
    evidence: [A-vendor, S-constant]
    unknown_reason: 이 벤더 연동이 서려면 설정 블록의 환경 키가 주입돼야 한다는 것이 이 층의 내용이다. 키 **이름**은 런타임 인덱스가 열거하지만 값은 저장소 밖이고 이 문서도 이름을 나열하지 않는다(11-index-code · 12-index-runtime 소유). 재유도된 게이트 종류는 `env` 이고 닫을 경로가 이 PRD 범위 밖이다.
    anchors:
      - insuniverse-server/apps/api/src/config/configuration.ts:59
  - id: treat-provider:__pool__:membership
    status: data-dependent-unknown
    evidence: [S-constant, A-comment]
    unknown_reason: 공급자 풀의 정본은 진료공급자 설정 테이블의 활성 행이고 env `TREAT_POOL` 은 그 조회가 비었을 때의 폴백이다. 코드가 정하는 것은 후보 다섯 종이며 실제 풀이 무엇인가는 DB 행이 정한다. 그 행을 이 저장소에서 볼 수 없어 미판정이고, **닫을 경로가 이름을 갖고 있다** — `ops-40-db-snapshot` 이 그 스냅샷을 들이면 이 칸은 닫힌다. 읽는 키는 활성 공급자 행 조회이며 전역 토글은 `tn_treat_setting` 이 진다.
    anchors:
      - insuniverse-server/apps/api/src/modules/treat/provider/treat-provider.service.ts:52
      - insuniverse-server/apps/api/src/modules/treat/provider/treat-provider.service.ts:57
      - insuniverse-server/apps/api/src/config/configuration.ts:33
  - id: treat-provider:__pool__:routing
    status: data-dependent-unknown
    evidence: [S-constant, A-comment]
    unknown_reason: 우선순위가 정렬값 오름차순이고 동순위에서 단가가 tiebreaker 라는 규칙 자체는 동결 stg 4d798f55 의 코드로 확정된다. 그러나 그 규칙에 들어가는 정렬값과 단가가 DB 행의 열이라 실제 호출 순서는 이 저장소에서 확정되지 않는다. 닫을 경로는 `ops-40-db-snapshot` 이다.
    anchors:
      - insuniverse-server/apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts:60
      - insuniverse-server/apps/api/src/modules/treat/provider/treat-provider.service.ts:52
  - id: treat-provider:__car__:scope
    status: data-dependent-unknown
    evidence: [S-constant, A-comment]
    unknown_reason: 자동차 진료정보 수집 범위는 세 층으로 걸린다 — 전역 토글 `enable_treat_car`(DB `tn_treat_setting`, 미설정 시 env 폴백) · 자체엔진 카나리 `enable_inhouse_car_canary`(같은 테이블) · 공급자 다중 모드 여부. 전역 토글이 꺼져 있으면 즉시 범위 밖이고 **DB 조회가 던져도 범위 밖이다**(fail-closed). 세 값 중 둘이 DB 설정 키라 실제 범위가 이 저장소에서 확정되지 않는다. 닫을 경로는 `ops-40-db-snapshot` 이다.
    limitations:
      - 같은 환경 키를 두 메서드가 **다른 극성으로 읽는다** — 한쪽은 값이 거짓이 아니면 켜짐으로 보고 다른 쪽은 참일 때만 켜짐으로 본다. 설정 블록이 그 키를 항상 불린으로 만들기 때문에 지금은 두 식의 결과가 같다. 어느 쪽이 옳은지는 이 문서가 판정하지 않고 두 앵커를 함께 싣는다 — 코드 정정은 저장소 소유자 소관이다
    anchors:
      - insuniverse-server/apps/api/src/modules/treat/provider/treat-provider.service.ts:134
      - insuniverse-server/apps/api/src/modules/treat/provider/treat-provider.service.ts:158
      - insuniverse-server/apps/api/src/config/configuration.ts:47
      - insuniverse-server/apps/api/src/config/configuration.ts:83
---

이 문서는 진료수집 다섯 공급자의 **연동 층**을 다룬다. 벤더가 무엇을 응답하고 그 응답이 무슨
뜻인가는 `02-failure-semantics.md` 가 이미 닫았다. 여기서 여는 것은 그 앞 단계다 — 호출이
언제 끊기는가 · 실패하면 다음이 있는가 · 응답을 어느 형태로 접는가 · 그 연동이 서려면 무엇이
주입돼야 하는가.

**이 문서가 더하는 판정은 미판정이 한 종류가 아니라는 것이다.** 앞선 세 문서는 미판정 전건을
`게이트 미상` 하나로 닫았다. 그 세 창의 게이트가 전부 주입 환경값이었고, 그 값은 이 조사 범위
밖이라 **닫을 경로가 없었기** 때문이다. 진료 공급자 축은 다르다. 풀 구성도 자동차 수집 범위도
**DB 설정이 정본이고 환경값은 폴백**이다. DB 는 이 저장소 밖이지만 그것을 들일 경로는 이름을
갖고 있다. 그래서 이 문서의 부록에는 두 어휘가 함께 산다 — `게이트 미상` 과 `데이터 의존`.

---

## 정책 (기획)

**이 절에 정책 블록이 없다.** 세 문서를 통틀어 본문 배치 자격을 갖는 정책이 0건이고, 그것은
누락이 아니라 배치 규칙의 귀결이다. 본문 배치를 갖는 상태 세 종(`정상` · `게이트 활성` ·
`미정합`)은 전부 **그 정책이 지금 어딘가에 도달해 활성이라는 주장**을 담는데, 이 축에는 그
주장을 세울 근거가 저장소 안에 없다.

이 문서의 사유는 앞선 세 문서와 다르다. 앞선 문서들의 미판정은 *주입 환경값을 모른다* 였다.
여기서는 그 위에 한 겹이 더 있다 — **공급자 풀에 무엇이 들어 있는가가 관리자 설정 행이다.**
코드는 다섯 후보를 정하고 그중 무엇이 실제로 불리는지는 정하지 않는다. 그래서 이 문서의 정책
스물세 건 중 어느 것도 *지금 이 공급자가 이 순서로 불린다* 고 말할 수 없다. 말할 수 있는 것은
*이 규칙이 무엇이고 그것이 무엇에 걸려 있는가* 뿐이며, 그 구별이 부록의 두 어휘다.

부록의 격리는 판정 보류이지 부정이 아니다. 규칙 자체는 동결 stg `4d798f55` 의 코드로 확정된다.

## 연동 층 대조

첫 열은 정책 id 이고 나머지는 **게이트가 재유도한다**. `인덱스 값` 은 값이 아니라 **형태**만
옮긴다 — 열거형과 유무이며 수치는 넣지 않는다(만료 값·TTL 은 `30-contracts-limits` 소유).
`게이트 종류` 는 동결 트리 재스캔이 만들고 `미판정 종류` 는 그 종류에서 유도되며 `닫을 경로` 는
그 유도의 귀결이다. **저자가 뒤 세 열을 고르지 않는다.**

게이트 종류 네 어휘는 이렇게 나온다. 정책의 앵커가 가리키는 **파일들의 합집합**을 스캔 단위로
잡고, 그 안에서 DB 설정 조회 토큰 적중과 주입 환경값 조회 토큰 적중을 각각 참·거짓으로 만든
뒤 접는다 — 둘 다면 `both`, DB 만이면 `db`, 환경값만이면 `env`, 둘 다 없으면 `none`. `none` 은
**두 토큰이 다 없었다는 관측**이지 미명세가 아니며, 게이트가 그 판정마다 스캔한 파일 목록을
출력에 함께 낸다.

| 정책 id | 벤더 | 층 | 인덱스 값 | 게이트 종류 | 미판정 종류 | 닫을 경로 |
|---|---|---|---|---|---|---|
| `treat-provider:codef:timeout` | codef | `timeout` | vendor_side_key: 없음 · dynamic_anchors 無 | `env` | `conditional-unknown` | 없음 — 범위 밖 |
| `treat-provider:codef:fallback` | codef | `fallback` | kind: multi-dispatch · in_pool: true | `none` | `conditional-unknown` | 없음 — 범위 밖 |
| `treat-provider:codef:normalization` | codef | `normalization` | mapper 無 · target: self | `env` | `conditional-unknown` | 없음 — 범위 밖 |
| `treat-provider:codef:env_gates` | codef | `env_gates` | 키 이름만 (값 미이관) | `env` | `conditional-unknown` | 없음 — 범위 밖 |
| `treat-provider:coocon:timeout` | coocon | `timeout` | vendor_side_key: TimeoutRuntime · dynamic_anchors 有 | `env` | `conditional-unknown` | 없음 — 범위 밖 |
| `treat-provider:coocon:fallback` | coocon | `fallback` | kind: multi-dispatch · in_pool: true | `none` | `conditional-unknown` | 없음 — 범위 밖 |
| `treat-provider:coocon:normalization` | coocon | `normalization` | mapper 有 · target: codef-dto | `none` | `conditional-unknown` | 없음 — 범위 밖 |
| `treat-provider:coocon:env_gates` | coocon | `env_gates` | 키 이름만 (값 미이관) | `env` | `conditional-unknown` | 없음 — 범위 밖 |
| `treat-provider:hyphen:timeout` | hyphen | `timeout` | vendor_side_key: exeTimeout · dynamic_anchors 無 | `env` | `conditional-unknown` | 없음 — 범위 밖 |
| `treat-provider:hyphen:fallback` | hyphen | `fallback` | kind: multi-dispatch · in_pool: true | `none` | `conditional-unknown` | 없음 — 범위 밖 |
| `treat-provider:hyphen:normalization` | hyphen | `normalization` | mapper 有 · target: codef-dto | `none` | `conditional-unknown` | 없음 — 범위 밖 |
| `treat-provider:hyphen:env_gates` | hyphen | `env_gates` | 키 이름만 (값 미이관) | `env` | `conditional-unknown` | 없음 — 범위 밖 |
| `treat-provider:inhouse:timeout` | inhouse | `timeout` | vendor_side_key: 없음 · dynamic_anchors 無 | `env` | `conditional-unknown` | 없음 — 범위 밖 |
| `treat-provider:inhouse:fallback` | inhouse | `fallback` | kind: multi-dispatch · in_pool: true | `none` | `conditional-unknown` | 없음 — 범위 밖 |
| `treat-provider:inhouse:normalization` | inhouse | `normalization` | mapper 無 · target: unknown | `env` | `conditional-unknown` | 없음 — 범위 밖 |
| `treat-provider:inhouse:env_gates` | inhouse | `env_gates` | 키 이름만 (값 미이관) | `env` | `conditional-unknown` | 없음 — 범위 밖 |
| `treat-provider:octover:timeout` | octover | `timeout` | vendor_side_key: 없음 · dynamic_anchors 無 | `env` | `conditional-unknown` | 없음 — 범위 밖 |
| `treat-provider:octover:fallback` | octover | `fallback` | kind: multi-dispatch · in_pool: true | `none` | `conditional-unknown` | 없음 — 범위 밖 |
| `treat-provider:octover:normalization` | octover | `normalization` | mapper 有 · target: codef-dto | `none` | `conditional-unknown` | 없음 — 범위 밖 |
| `treat-provider:octover:env_gates` | octover | `env_gates` | 키 이름만 (값 미이관) | `env` | `conditional-unknown` | 없음 — 범위 밖 |
| `treat-provider:__pool__:membership` | — | `membership` | 풀 구성이 DB 행이고 env 는 폴백 | `both` | `data-dependent-unknown` | `ops-40-db-snapshot` |
| `treat-provider:__pool__:routing` | — | `routing` | 우선순위 = 정렬값 오름차순, 동순위 단가 tiebreaker | `both` | `data-dependent-unknown` | `ops-40-db-snapshot` |
| `treat-provider:__car__:scope` | — | `scope` | 자동차 수집 범위 3층 게이트 · DB 장애 fail-closed | `both` | `data-dependent-unknown` | `ops-40-db-snapshot` |

## 풀 진입과 라우팅

**코드가 정하는 것은 후보 다섯 종이고 실제 풀은 DB 행이다.** 공급자 조회는 활성 공급자 행을
먼저 읽고, 그 조회가 비었을 때만 환경값 목록으로 접는다. 그 환경값 폴백의 기본 목록은 두
종뿐이라 **DB 풀보다 좁다** — 설정이 비어 있는 환경에서는 다섯 후보 중 둘만 돈다는 뜻이고, 그
사실은 코드가 아니라 편성이 만든다.

조회 결과는 짧게 캐시된다. 그래서 관리자가 공급자 구성을 바꿔도 **즉시 반영이 아니다**. 캐시
길이 자체는 이 문서가 옮기지 않고(`30-contracts-limits` 소유) 여기서 적는 것은 그 성질뿐이다 —
설정 변경과 실제 라우팅 사이에 시차가 있다.

라우팅 순서는 정렬값 오름차순이고 동순위에서 단가가 tiebreaker 다. 규칙은 코드에 있지만
**규칙에 들어가는 두 값이 DB 행의 열**이라, 실제 호출 순서는 이 저장소에서 확정되지 않는다.
그것이 `treat-provider:__pool__:routing` 이 `데이터 의존` 인 이유다.

자동차 진료정보 수집 범위는 게이트가 세 층이다. 전역 토글이 꺼져 있으면 즉시 범위 밖이고,
켜져 있을 때만 자체엔진 카나리를 본다. 그 위에 공급자 다중 모드 여부가 또 걸린다. **DB 조회가
던져도 범위 밖이다** — 장애를 열림이 아니라 닫힘으로 접는 fail-closed 이며, 자동차 수집이 동의
범위와 직접 닿는 축이라 그 방향이 옳다.

**같은 환경 키를 두 메서드가 다른 극성으로 읽는다.** 한쪽은 값이 거짓이 아니면 켜짐으로 보고
(`insuniverse-server/apps/api/src/modules/treat/provider/treat-provider.service.ts:110`), 다른 쪽은
참일 때만 켜짐으로 본다(`insuniverse-server/apps/api/src/modules/treat/provider/treat-provider.service.ts:139`).
설정 블록이 그 키를 항상 불린으로 만들기 때문에
(`insuniverse-server/apps/api/src/config/configuration.ts:47`) 지금은 두 식의 결과가 같다.
**이 문서는 어느 쪽이 옳은지 판정하지 않고 두 앵커를 함께 싣는다** — 코드 정정은 저장소 소유자
소관이고, 여기서 한쪽을 정본으로 적으면 문서가 코드를 앞질러 판정하는 것이 된다.

## 벤더별 진입 형태

`자격 형태` 는 환경 키 **이름의 성격**만 적는다. 키 이름과 값은 이 문서가 나열하지 않는다
(`11-index-code` · `12-index-runtime` 소유). `풀 진입` 은 그 공급자가 풀에 드는 경로다.

| 벤더 | 정규화 대상 | 매퍼 | 자격 형태 | 풀 진입 |
|---|---|---|---|---|
| codef | 자기 형태가 정본 | 없음 | 식별자 + 시크릿으로 토큰을 받는 형태 | 단일 공급자 모드의 기본 공급자이자 다중 모드의 후보 |
| coocon | 기본 공급자 형태로 접음 | 있음 | 대칭키 + 인증키 | 환경값 폴백 기본 목록에 있고 DB 행이 정본 |
| hyphen | 기본 공급자 형태로 접음 | 있음 | API 키 | DB 행에만 의존 |
| inhouse | 미상 | 없음 | API 키 | DB 행 + 자체엔진 카나리 게이트 |
| octover | 기본 공급자 형태로 접음 | 있음 | 공개키 + API 키 | 환경값 폴백 기본 목록에 있고 DB 행이 정본 |

`inhouse` 의 정규화 대상이 `미상` 인 것은 조사 실패가 아니라 **런타임 인덱스가 그렇게 기록한
값**이다. 매퍼 파일이 없고 서비스가 응답 형태를 그대로 지는데, 그 형태가 기본 공급자 형태와
같은지는 인덱스가 판정하지 않았다.

## 강제 지점 (개발)

정책 내용을 다시 쓰지 않는다. 각 정책이 저장소 안 **어디에서** 강제되는가와 그 기제, 그리고
게이트 종류만 적는다. 배치가 부록인 정책도 이 절에 있어야 한다 — 이 절의 id 집합은 배치와
무관하게 프론트매터 전체와 결속돼 있다. 기준점은 전건 동결 stg `4d798f55` 다.

### treat-provider:codef:timeout

- 강제 방식: HTTP 클라이언트 호출 옵션. 만료가 지나면 호출이 끊기고 그 실패가 위층 분기로 간다
- 앵커: `insuniverse-server/libs/codef/src/codef.service.ts:98` · `insuniverse-server/libs/codef/src/codef.service.ts:153` · `insuniverse-server/libs/codef/src/codef.service.ts:176` · `insuniverse-server/libs/codef/src/codef.service.ts:215`
- 게이트: `env` — 주입 환경값이 정한다

### treat-provider:codef:fallback

- 강제 방식: 디스패처 루프의 공급자 순회. 이 벤더가 그 순회의 원소인가로 강제된다
- 앵커: `insuniverse-server/apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts:73`
- 게이트: `none` — 걸 게이트가 없다 — 앵커 파일에서 두 토큰이 모두 관측되지 않았다

### treat-provider:codef:normalization

- 강제 방식: 응답 변환 지점. 매퍼가 있으면 그 파일이, 없으면 서비스가 응답 형태를 그대로 진다
- 앵커: `insuniverse-server/libs/codef/src/codef.service.ts:98` · `insuniverse-server/libs/codef/src/codef.service.ts:153` · `insuniverse-server/libs/codef/src/codef.service.ts:176` · `insuniverse-server/libs/codef/src/codef.service.ts:215`
- 게이트: `env` — 주입 환경값이 정한다

### treat-provider:codef:env_gates

- 강제 방식: 설정 블록 로드. 키가 비면 연동 진입이 성립하지 않는다
- 앵커: `insuniverse-server/apps/api/src/config/configuration.ts:16`
- 게이트: `env` — 주입 환경값이 정한다

### treat-provider:coocon:timeout

- 강제 방식: HTTP 클라이언트 호출 옵션. 만료가 지나면 호출이 끊기고 그 실패가 위층 분기로 간다
- 앵커: `insuniverse-server/libs/coocon/src/coocon-auth.service.ts:84` · `insuniverse-server/libs/coocon/src/coocon-auth.service.ts:98`
- 게이트: `env` — 주입 환경값이 정한다

### treat-provider:coocon:fallback

- 강제 방식: 디스패처 루프의 공급자 순회. 이 벤더가 그 순회의 원소인가로 강제된다
- 앵커: `insuniverse-server/apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts:73`
- 게이트: `none` — 걸 게이트가 없다 — 앵커 파일에서 두 토큰이 모두 관측되지 않았다

### treat-provider:coocon:normalization

- 강제 방식: 응답 변환 지점. 매퍼가 있으면 그 파일이, 없으면 서비스가 응답 형태를 그대로 진다
- 앵커: `insuniverse-server/libs/coocon/src/coocon.mapper.ts:19`
- 게이트: `none` — 걸 게이트가 없다 — 앵커 파일에서 두 토큰이 모두 관측되지 않았다

### treat-provider:coocon:env_gates

- 강제 방식: 설정 블록 로드. 키가 비면 연동 진입이 성립하지 않는다
- 앵커: `insuniverse-server/apps/api/src/config/configuration.ts:49`
- 게이트: `env` — 주입 환경값이 정한다

### treat-provider:hyphen:timeout

- 강제 방식: HTTP 클라이언트 호출 옵션. 만료가 지나면 호출이 끊기고 그 실패가 위층 분기로 간다
- 앵커: `insuniverse-server/libs/hyphen/src/hyphen.service.ts:287` · `insuniverse-server/libs/hyphen/src/hyphen.service.ts:368`
- 게이트: `env` — 주입 환경값이 정한다

### treat-provider:hyphen:fallback

- 강제 방식: 디스패처 루프의 공급자 순회. 이 벤더가 그 순회의 원소인가로 강제된다
- 앵커: `insuniverse-server/apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts:73`
- 게이트: `none` — 걸 게이트가 없다 — 앵커 파일에서 두 토큰이 모두 관측되지 않았다

### treat-provider:hyphen:normalization

- 강제 방식: 응답 변환 지점. 매퍼가 있으면 그 파일이, 없으면 서비스가 응답 형태를 그대로 진다
- 앵커: `insuniverse-server/libs/hyphen/src/hyphen.mapper.ts:16`
- 게이트: `none` — 걸 게이트가 없다 — 앵커 파일에서 두 토큰이 모두 관측되지 않았다

### treat-provider:hyphen:env_gates

- 강제 방식: 설정 블록 로드. 키가 비면 연동 진입이 성립하지 않는다
- 앵커: `insuniverse-server/apps/api/src/config/configuration.ts:67`
- 게이트: `env` — 주입 환경값이 정한다

### treat-provider:inhouse:timeout

- 강제 방식: HTTP 클라이언트 호출 옵션. 만료가 지나면 호출이 끊기고 그 실패가 위층 분기로 간다
- 앵커: `insuniverse-server/libs/inhouse/src/inhouse.service.ts:298` · `insuniverse-server/libs/inhouse/src/inhouse.service.ts:321` · `insuniverse-server/libs/inhouse/src/inhouse.service.ts:345` · `insuniverse-server/libs/inhouse/src/inhouse.service.ts:374`
- 게이트: `env` — 주입 환경값이 정한다

### treat-provider:inhouse:fallback

- 강제 방식: 디스패처 루프의 공급자 순회. 이 벤더가 그 순회의 원소인가로 강제된다
- 앵커: `insuniverse-server/apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts:73`
- 게이트: `none` — 걸 게이트가 없다 — 앵커 파일에서 두 토큰이 모두 관측되지 않았다

### treat-provider:inhouse:normalization

- 강제 방식: 응답 변환 지점. 매퍼가 있으면 그 파일이, 없으면 서비스가 응답 형태를 그대로 진다
- 앵커: `insuniverse-server/libs/inhouse/src/inhouse.service.ts:298` · `insuniverse-server/libs/inhouse/src/inhouse.service.ts:321` · `insuniverse-server/libs/inhouse/src/inhouse.service.ts:345` · `insuniverse-server/libs/inhouse/src/inhouse.service.ts:374`
- 게이트: `env` — 주입 환경값이 정한다

### treat-provider:inhouse:env_gates

- 강제 방식: 설정 블록 로드. 키가 비면 연동 진입이 성립하지 않는다
- 앵커: `insuniverse-server/apps/api/src/config/configuration.ts:79`
- 게이트: `env` — 주입 환경값이 정한다

### treat-provider:octover:timeout

- 강제 방식: HTTP 클라이언트 호출 옵션. 만료가 지나면 호출이 끊기고 그 실패가 위층 분기로 간다
- 앵커: `insuniverse-server/libs/octover/src/octover.service.ts:320`
- 게이트: `env` — 주입 환경값이 정한다

### treat-provider:octover:fallback

- 강제 방식: 디스패처 루프의 공급자 순회. 이 벤더가 그 순회의 원소인가로 강제된다
- 앵커: `insuniverse-server/apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts:73`
- 게이트: `none` — 걸 게이트가 없다 — 앵커 파일에서 두 토큰이 모두 관측되지 않았다

### treat-provider:octover:normalization

- 강제 방식: 응답 변환 지점. 매퍼가 있으면 그 파일이, 없으면 서비스가 응답 형태를 그대로 진다
- 앵커: `insuniverse-server/libs/octover/src/octover.mapper.ts:16`
- 게이트: `none` — 걸 게이트가 없다 — 앵커 파일에서 두 토큰이 모두 관측되지 않았다

### treat-provider:octover:env_gates

- 강제 방식: 설정 블록 로드. 키가 비면 연동 진입이 성립하지 않는다
- 앵커: `insuniverse-server/apps/api/src/config/configuration.ts:59`
- 게이트: `env` — 주입 환경값이 정한다

### treat-provider:__pool__:membership

- 강제 방식: 공급자 조회 메서드. DB 활성 행을 먼저 읽고 비면 환경값 폴백으로 접는다 (조회 결과는 짧게 캐시된다)
- 앵커: `insuniverse-server/apps/api/src/modules/treat/provider/treat-provider.service.ts:52` · `insuniverse-server/apps/api/src/modules/treat/provider/treat-provider.service.ts:57` · `insuniverse-server/apps/api/src/config/configuration.ts:33`
- 게이트: `both` — DB 설정 행이 정본이고 환경값이 폴백이다

### treat-provider:__pool__:routing

- 강제 방식: 디스패처의 공급자 맵과 정렬. 코드 맵이 후보를 좁히고 DB 행의 정렬값·단가가 순서를 정한다
- 앵커: `insuniverse-server/apps/api/src/modules/treat/dispatch/treat-dispatcher.service.ts:60` · `insuniverse-server/apps/api/src/modules/treat/provider/treat-provider.service.ts:52`
- 게이트: `both` — DB 설정 행이 정본이고 환경값이 폴백이다

### treat-provider:__car__:scope

- 강제 방식: 범위 산출 메서드 3층. 전역 토글 → 카나리 → 공급자 모드 순이며 DB 조회 실패는 범위 밖으로 접는다
- 앵커: `insuniverse-server/apps/api/src/modules/treat/provider/treat-provider.service.ts:134` · `insuniverse-server/apps/api/src/modules/treat/provider/treat-provider.service.ts:158` · `insuniverse-server/apps/api/src/config/configuration.ts:47` · `insuniverse-server/apps/api/src/config/configuration.ts:83`
- 게이트: `both` — DB 설정 행이 정본이고 환경값이 폴백이다

## 적용 범위 (actor × 서비스)

`적용` 은 **그 정책의 앵커가 그 저장소에 있는 경우**에만 쓴다. 그 밖은 `—` 이며 빈 칸이 아니라
관측된 부재다. 이 규칙은 게이트가 다시 돌린다 — 저자가 칸을 고르지 않는다.

actor 다섯 열이 전건 `—` 인 데에는 축 판정이 하나 걸려 있다. `actors` 는 **로그인 주체 축**이고
이 문서의 정책은 전부 서버 안쪽의 연동 층이다. 어느 로그인 주체가 진료수집을 시작했는가와
어느 공급자가 어떤 만료값으로 불리는가는 저장소 안에서 갈리지 않는다 — 연동 층은 주체를 보지
않는다. 관리자 화면이 공급자 구성을 바꾸지만 그 화면이 읽는 것은 이 문서의 정책이 아니라 그
정책이 소비하는 설정 행이므로 같은 이유로 `—` 다.

서비스 축은 이 문서에서 갈리지 않는다. 스물세 정책의 앵커가 전건 server 저장소에 있다.

| 정책 id | 관리자 | 영업대리점 | 기업담당자 | 일반회원 | 기업회원 | server | site | admin |
|---|---|---|---|---|---|---|---|---|
| treat-provider:codef:timeout | — | — | — | — | — | 적용 | — | — |
| treat-provider:codef:fallback | — | — | — | — | — | 적용 | — | — |
| treat-provider:codef:normalization | — | — | — | — | — | 적용 | — | — |
| treat-provider:codef:env_gates | — | — | — | — | — | 적용 | — | — |
| treat-provider:coocon:timeout | — | — | — | — | — | 적용 | — | — |
| treat-provider:coocon:fallback | — | — | — | — | — | 적용 | — | — |
| treat-provider:coocon:normalization | — | — | — | — | — | 적용 | — | — |
| treat-provider:coocon:env_gates | — | — | — | — | — | 적용 | — | — |
| treat-provider:hyphen:timeout | — | — | — | — | — | 적용 | — | — |
| treat-provider:hyphen:fallback | — | — | — | — | — | 적용 | — | — |
| treat-provider:hyphen:normalization | — | — | — | — | — | 적용 | — | — |
| treat-provider:hyphen:env_gates | — | — | — | — | — | 적용 | — | — |
| treat-provider:inhouse:timeout | — | — | — | — | — | 적용 | — | — |
| treat-provider:inhouse:fallback | — | — | — | — | — | 적용 | — | — |
| treat-provider:inhouse:normalization | — | — | — | — | — | 적용 | — | — |
| treat-provider:inhouse:env_gates | — | — | — | — | — | 적용 | — | — |
| treat-provider:octover:timeout | — | — | — | — | — | 적용 | — | — |
| treat-provider:octover:fallback | — | — | — | — | — | 적용 | — | — |
| treat-provider:octover:normalization | — | — | — | — | — | 적용 | — | — |
| treat-provider:octover:env_gates | — | — | — | — | — | 적용 | — | — |
| treat-provider:__pool__:membership | — | — | — | — | — | 적용 | — | — |
| treat-provider:__pool__:routing | — | — | — | — | — | 적용 | — | — |
| treat-provider:__car__:scope | — | — | — | — | — | 적용 | — | — |

## 예외·폴백

예외가 없는 정책도 행을 둔다 — 없다는 것도 확인의 결과이며 그 확인 근거를 함께 적는다.

| 정책 id | 예외 | 폴백 | 확인 근거 |
|---|---|---|---|
| treat-provider:codef:timeout | 만료 자체가 예외 경로다 | 만료 뒤 폴백은 이 층이 정하지 않는다 — 폴백 층이 진다 | 런타임 인덱스의 이 벤더 층이 그 값을 담고, 그 층이 이 정책의 근거다 |
| treat-provider:codef:fallback | 사용자측 실패는 다음 공급자로 넘어가지 않는다 — 그 갈림은 응답 의미 축 소유다 | 공급자측 장애와 호출 예외에 한해 다음 공급자로 넘어간다 | 런타임 인덱스의 이 벤더 층이 그 값을 담고, 그 층이 이 정책의 근거다 |
| treat-provider:codef:normalization | 없음 | 없음 — 변환 없이 응답 형태를 그대로 쓴다 | 런타임 인덱스의 이 벤더 층이 그 값을 담고, 그 층이 이 정책의 근거다 |
| treat-provider:codef:env_gates | 키가 비면 연동 진입이 성립하지 않는다 | 없음 — 키 부재를 메우는 기본값이 이 층에 없다 | 런타임 인덱스의 이 벤더 층이 그 값을 담고, 그 층이 이 정책의 근거다 |
| treat-provider:coocon:timeout | 만료 자체가 예외 경로다 | 만료 뒤 폴백은 이 층이 정하지 않는다 — 폴백 층이 진다 | 런타임 인덱스의 이 벤더 층이 그 값을 담고, 그 층이 이 정책의 근거다 |
| treat-provider:coocon:fallback | 사용자측 실패는 다음 공급자로 넘어가지 않는다 — 그 갈림은 응답 의미 축 소유다 | 공급자측 장애와 호출 예외에 한해 다음 공급자로 넘어간다 | 런타임 인덱스의 이 벤더 층이 그 값을 담고, 그 층이 이 정책의 근거다 |
| treat-provider:coocon:normalization | 매퍼가 모르는 형태를 만나면 변환이 성립하지 않는다 | 없음 — 이 층에 대체 변환 경로가 없다 | 런타임 인덱스의 이 벤더 층이 그 값을 담고, 그 층이 이 정책의 근거다 |
| treat-provider:coocon:env_gates | 키가 비면 연동 진입이 성립하지 않는다 | 없음 — 키 부재를 메우는 기본값이 이 층에 없다 | 런타임 인덱스의 이 벤더 층이 그 값을 담고, 그 층이 이 정책의 근거다 |
| treat-provider:hyphen:timeout | 만료 자체가 예외 경로다 | 만료 뒤 폴백은 이 층이 정하지 않는다 — 폴백 층이 진다 | 런타임 인덱스의 이 벤더 층이 그 값을 담고, 그 층이 이 정책의 근거다 |
| treat-provider:hyphen:fallback | 사용자측 실패는 다음 공급자로 넘어가지 않는다 — 그 갈림은 응답 의미 축 소유다 | 공급자측 장애와 호출 예외에 한해 다음 공급자로 넘어간다 | 런타임 인덱스의 이 벤더 층이 그 값을 담고, 그 층이 이 정책의 근거다 |
| treat-provider:hyphen:normalization | 매퍼가 모르는 형태를 만나면 변환이 성립하지 않는다 | 없음 — 이 층에 대체 변환 경로가 없다 | 런타임 인덱스의 이 벤더 층이 그 값을 담고, 그 층이 이 정책의 근거다 |
| treat-provider:hyphen:env_gates | 키가 비면 연동 진입이 성립하지 않는다 | 없음 — 키 부재를 메우는 기본값이 이 층에 없다 | 런타임 인덱스의 이 벤더 층이 그 값을 담고, 그 층이 이 정책의 근거다 |
| treat-provider:inhouse:timeout | 만료 자체가 예외 경로다 | 만료 뒤 폴백은 이 층이 정하지 않는다 — 폴백 층이 진다 | 런타임 인덱스의 이 벤더 층이 그 값을 담고, 그 층이 이 정책의 근거다 |
| treat-provider:inhouse:fallback | 사용자측 실패는 다음 공급자로 넘어가지 않는다 — 그 갈림은 응답 의미 축 소유다 | 공급자측 장애와 호출 예외에 한해 다음 공급자로 넘어간다 | 런타임 인덱스의 이 벤더 층이 그 값을 담고, 그 층이 이 정책의 근거다 |
| treat-provider:inhouse:normalization | 없음 | 없음 — 변환 없이 응답 형태를 그대로 쓴다 | 런타임 인덱스의 이 벤더 층이 그 값을 담고, 그 층이 이 정책의 근거다 |
| treat-provider:inhouse:env_gates | 키가 비면 연동 진입이 성립하지 않는다 | 없음 — 키 부재를 메우는 기본값이 이 층에 없다 | 런타임 인덱스의 이 벤더 층이 그 값을 담고, 그 층이 이 정책의 근거다 |
| treat-provider:octover:timeout | 만료 자체가 예외 경로다 | 만료 뒤 폴백은 이 층이 정하지 않는다 — 폴백 층이 진다 | 런타임 인덱스의 이 벤더 층이 그 값을 담고, 그 층이 이 정책의 근거다 |
| treat-provider:octover:fallback | 사용자측 실패는 다음 공급자로 넘어가지 않는다 — 그 갈림은 응답 의미 축 소유다 | 공급자측 장애와 호출 예외에 한해 다음 공급자로 넘어간다 | 런타임 인덱스의 이 벤더 층이 그 값을 담고, 그 층이 이 정책의 근거다 |
| treat-provider:octover:normalization | 매퍼가 모르는 형태를 만나면 변환이 성립하지 않는다 | 없음 — 이 층에 대체 변환 경로가 없다 | 런타임 인덱스의 이 벤더 층이 그 값을 담고, 그 층이 이 정책의 근거다 |
| treat-provider:octover:env_gates | 키가 비면 연동 진입이 성립하지 않는다 | 없음 — 키 부재를 메우는 기본값이 이 층에 없다 | 런타임 인덱스의 이 벤더 층이 그 값을 담고, 그 층이 이 정책의 근거다 |
| treat-provider:__pool__:membership | DB 조회가 비거나 던지면 활성 풀을 얻지 못한다 | 환경값 목록으로 접는다 — 그 기본값은 두 종뿐이라 DB 풀보다 좁다 | 공급자 조회 메서드의 폴백 분기 |
| treat-provider:__pool__:routing | 정렬값이 같으면 순서가 단가로 갈린다 | 없음 — 순서를 정하지 못하는 경로가 없다 | 디스패처의 공급자 맵과 정렬 지점 |
| treat-provider:__car__:scope | 전역 토글이 꺼져 있으면 즉시 범위 밖이다 | **fail-closed** — DB 조회가 던지면 로그를 남기고 범위 밖으로 접는다 | 범위 산출 메서드의 예외 처리 |

## 부록

이 절의 정책은 **현행 발효 여부가 판정되지 않아** 본문에서 격리한다. 다만 이 문서의 미판정은
두 종류이고 그 둘은 서로 다른 것을 말한다.

- `게이트 미상` — 발효 조건이 주입 환경값이거나 게이트가 아예 없다. **닫을 경로가 이 조사 범위
  밖이다.** 환경 변수의 실제 값은 배포 정의와 함께 이 저장소 밖에 있고 이 PRD 는 그것을 열지
  않는다.
- `데이터 의존` — 발효 조건이 관리자 설정 행이다. DB 도 저장소 밖이지만 **닫을 경로가 이름을
  갖고 있다.** `ops-40-db-snapshot` 이 그 스냅샷을 들이면 해당 칸은 닫힌다. 이 문서는 그 도래를
  기다리지 않고 경로를 이름으로만 적는다.

**여기 실린 어떤 정책도 그 규칙이 틀렸다고 말하지 않는다.** 미판정은 부정이 아니다. 규칙 자체는
동결 stg `4d798f55` 의 코드로 확정되며, 판정되지 않은 것은 그 규칙이 지금 어느 공급자에 어떤
순서로 걸려 있는가다.

각 블록은 **그 층이 무엇을 정하고 그것이 발효하려면 무엇이 서야 하는가**를 적는다. 좌표는
프론트매터 `anchors` 와 `## 강제 지점 (개발)` 이 진다.

### treat-provider:codef:timeout

요청 만료 시점을 정하는 층이다. 만료 뒤 호출자가 어느 분기로 가는가는 동결 stg 4d798f55 의 코드로 확정되지만, 그 분기가 발효하려면 이 벤더가 먼저 공급자 풀에 들어야 한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 이 층의 게이트 종류는 `env` 로 재유도됐고 닫을 경로가 이 PRD 범위 밖이다. 만료 값 자체는 이 문서가 옮기지 않는다(30-contracts-limits 소유).

### treat-provider:codef:fallback

이 벤더가 멀티 디스패치 폴백의 후보인가를 정하는 층이다. 후보 목록은 코드가 정하지만 실제 풀은 편성값이 정한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 이 층의 게이트 종류는 `none` 로 재유도됐고 닫을 경로가 이 PRD 범위 밖이다. 게이트 종류가 `none` 인 것은 이 층의 앵커 파일에서 DB 토큰도 env 토큰도 관측되지 않았다는 뜻이지 미명세가 아니다.

### treat-provider:codef:normalization

정규화 매퍼가 없다는 것이 이 층의 내용이다 — 응답을 그대로 응답 DTO 로 옮기거나 자기 형태를 정본으로 쓴다. **관측된 부재다.** 그 형태가 발효하려면 이 벤더가 풀에 들어야 한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 이 층의 게이트 종류는 `env` 로 재유도됐고 닫을 경로가 이 PRD 범위 밖이다.

### treat-provider:codef:env_gates

이 벤더 연동이 서려면 설정 블록의 환경 키가 주입돼야 한다는 것이 이 층의 내용이다. 키 **이름**은 런타임 인덱스가 열거하지만 값은 저장소 밖이고 이 문서도 이름을 나열하지 않는다(11-index-code · 12-index-runtime 소유). 이 층의 게이트 종류는 `env` 로 재유도됐고 닫을 경로가 이 PRD 범위 밖이다.

### treat-provider:coocon:timeout

요청 만료 시점을 정하는 층이다. 만료 뒤 호출자가 어느 분기로 가는가는 동결 stg 4d798f55 의 코드로 확정되지만, 그 분기가 발효하려면 이 벤더가 먼저 공급자 풀에 들어야 한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 이 층의 게이트 종류는 `env` 로 재유도됐고 닫을 경로가 이 PRD 범위 밖이다. 만료 값 자체는 이 문서가 옮기지 않는다(30-contracts-limits 소유).

### treat-provider:coocon:fallback

이 벤더가 멀티 디스패치 폴백의 후보인가를 정하는 층이다. 후보 목록은 코드가 정하지만 실제 풀은 편성값이 정한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 이 층의 게이트 종류는 `none` 로 재유도됐고 닫을 경로가 이 PRD 범위 밖이다. 게이트 종류가 `none` 인 것은 이 층의 앵커 파일에서 DB 토큰도 env 토큰도 관측되지 않았다는 뜻이지 미명세가 아니다.

### treat-provider:coocon:normalization

벤더 응답을 어느 DTO 형태로 접는가를 정하는 층이다. 매퍼 파일과 변환 대상은 코드로 확정되지만 그 변환이 실행되려면 이 벤더가 풀에 들어야 한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 이 층의 게이트 종류는 `none` 로 재유도됐고 닫을 경로가 이 PRD 범위 밖이다. 게이트 종류가 `none` 인 것은 이 층의 앵커 파일에서 DB 토큰도 env 토큰도 관측되지 않았다는 뜻이지 미명세가 아니다.

### treat-provider:coocon:env_gates

이 벤더 연동이 서려면 설정 블록의 환경 키가 주입돼야 한다는 것이 이 층의 내용이다. 키 **이름**은 런타임 인덱스가 열거하지만 값은 저장소 밖이고 이 문서도 이름을 나열하지 않는다(11-index-code · 12-index-runtime 소유). 이 층의 게이트 종류는 `env` 로 재유도됐고 닫을 경로가 이 PRD 범위 밖이다.

### treat-provider:hyphen:timeout

요청 만료 시점을 정하는 층이다. 만료 뒤 호출자가 어느 분기로 가는가는 동결 stg 4d798f55 의 코드로 확정되지만, 그 분기가 발효하려면 이 벤더가 먼저 공급자 풀에 들어야 한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 이 층의 게이트 종류는 `env` 로 재유도됐고 닫을 경로가 이 PRD 범위 밖이다. 만료 값 자체는 이 문서가 옮기지 않는다(30-contracts-limits 소유).

### treat-provider:hyphen:fallback

이 벤더가 멀티 디스패치 폴백의 후보인가를 정하는 층이다. 후보 목록은 코드가 정하지만 실제 풀은 편성값이 정한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 이 층의 게이트 종류는 `none` 로 재유도됐고 닫을 경로가 이 PRD 범위 밖이다. 게이트 종류가 `none` 인 것은 이 층의 앵커 파일에서 DB 토큰도 env 토큰도 관측되지 않았다는 뜻이지 미명세가 아니다.

### treat-provider:hyphen:normalization

벤더 응답을 어느 DTO 형태로 접는가를 정하는 층이다. 매퍼 파일과 변환 대상은 코드로 확정되지만 그 변환이 실행되려면 이 벤더가 풀에 들어야 한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 이 층의 게이트 종류는 `none` 로 재유도됐고 닫을 경로가 이 PRD 범위 밖이다. 게이트 종류가 `none` 인 것은 이 층의 앵커 파일에서 DB 토큰도 env 토큰도 관측되지 않았다는 뜻이지 미명세가 아니다.

### treat-provider:hyphen:env_gates

이 벤더 연동이 서려면 설정 블록의 환경 키가 주입돼야 한다는 것이 이 층의 내용이다. 키 **이름**은 런타임 인덱스가 열거하지만 값은 저장소 밖이고 이 문서도 이름을 나열하지 않는다(11-index-code · 12-index-runtime 소유). 이 층의 게이트 종류는 `env` 로 재유도됐고 닫을 경로가 이 PRD 범위 밖이다.

### treat-provider:inhouse:timeout

요청 만료 시점을 정하는 층이다. 만료 뒤 호출자가 어느 분기로 가는가는 동결 stg 4d798f55 의 코드로 확정되지만, 그 분기가 발효하려면 이 벤더가 먼저 공급자 풀에 들어야 한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 이 층의 게이트 종류는 `env` 로 재유도됐고 닫을 경로가 이 PRD 범위 밖이다. 만료 값 자체는 이 문서가 옮기지 않는다(30-contracts-limits 소유).

### treat-provider:inhouse:fallback

이 벤더가 멀티 디스패치 폴백의 후보인가를 정하는 층이다. 후보 목록은 코드가 정하지만 실제 풀은 편성값이 정한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 이 층의 게이트 종류는 `none` 로 재유도됐고 닫을 경로가 이 PRD 범위 밖이다. 게이트 종류가 `none` 인 것은 이 층의 앵커 파일에서 DB 토큰도 env 토큰도 관측되지 않았다는 뜻이지 미명세가 아니다.

### treat-provider:inhouse:normalization

정규화 매퍼가 없다는 것이 이 층의 내용이다 — 응답을 그대로 응답 DTO 로 옮기거나 자기 형태를 정본으로 쓴다. **관측된 부재다.** 그 형태가 발효하려면 이 벤더가 풀에 들어야 한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 이 층의 게이트 종류는 `env` 로 재유도됐고 닫을 경로가 이 PRD 범위 밖이다.

### treat-provider:inhouse:env_gates

이 벤더 연동이 서려면 설정 블록의 환경 키가 주입돼야 한다는 것이 이 층의 내용이다. 키 **이름**은 런타임 인덱스가 열거하지만 값은 저장소 밖이고 이 문서도 이름을 나열하지 않는다(11-index-code · 12-index-runtime 소유). 이 층의 게이트 종류는 `env` 로 재유도됐고 닫을 경로가 이 PRD 범위 밖이다.

### treat-provider:octover:timeout

요청 만료 시점을 정하는 층이다. 만료 뒤 호출자가 어느 분기로 가는가는 동결 stg 4d798f55 의 코드로 확정되지만, 그 분기가 발효하려면 이 벤더가 먼저 공급자 풀에 들어야 한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 이 층의 게이트 종류는 `env` 로 재유도됐고 닫을 경로가 이 PRD 범위 밖이다. 만료 값 자체는 이 문서가 옮기지 않는다(30-contracts-limits 소유).

### treat-provider:octover:fallback

이 벤더가 멀티 디스패치 폴백의 후보인가를 정하는 층이다. 후보 목록은 코드가 정하지만 실제 풀은 편성값이 정한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 이 층의 게이트 종류는 `none` 로 재유도됐고 닫을 경로가 이 PRD 범위 밖이다. 게이트 종류가 `none` 인 것은 이 층의 앵커 파일에서 DB 토큰도 env 토큰도 관측되지 않았다는 뜻이지 미명세가 아니다.

### treat-provider:octover:normalization

벤더 응답을 어느 DTO 형태로 접는가를 정하는 층이다. 매퍼 파일과 변환 대상은 코드로 확정되지만 그 변환이 실행되려면 이 벤더가 풀에 들어야 한다 — 그 편성은 `TREAT_PROVIDER` 와 `TREAT_POOL` 의 주입값이 정하고 두 값은 저장소 밖에 있다. 이 층의 게이트 종류는 `none` 로 재유도됐고 닫을 경로가 이 PRD 범위 밖이다. 게이트 종류가 `none` 인 것은 이 층의 앵커 파일에서 DB 토큰도 env 토큰도 관측되지 않았다는 뜻이지 미명세가 아니다.

### treat-provider:octover:env_gates

이 벤더 연동이 서려면 설정 블록의 환경 키가 주입돼야 한다는 것이 이 층의 내용이다. 키 **이름**은 런타임 인덱스가 열거하지만 값은 저장소 밖이고 이 문서도 이름을 나열하지 않는다(11-index-code · 12-index-runtime 소유). 이 층의 게이트 종류는 `env` 로 재유도됐고 닫을 경로가 이 PRD 범위 밖이다.

### treat-provider:__pool__:membership

공급자 풀의 정본은 진료공급자 설정 테이블의 활성 행이고 env `TREAT_POOL` 은 그 조회가 비었을 때의 폴백이다. 코드가 정하는 것은 후보 다섯 종이며 실제 풀이 무엇인가는 DB 행이 정한다. 그 행을 이 저장소에서 볼 수 없어 미판정이고, **닫을 경로가 이름을 갖고 있다** — `ops-40-db-snapshot` 이 그 스냅샷을 들이면 이 칸은 닫힌다. 읽는 키는 활성 공급자 행 조회이며 전역 토글은 `tn_treat_setting` 이 진다.

### treat-provider:__pool__:routing

우선순위가 정렬값 오름차순이고 동순위에서 단가가 tiebreaker 라는 규칙 자체는 동결 stg 4d798f55 의 코드로 확정된다. 그러나 그 규칙에 들어가는 정렬값과 단가가 DB 행의 열이라 실제 호출 순서는 이 저장소에서 확정되지 않는다. 닫을 경로는 `ops-40-db-snapshot` 이다.

### treat-provider:__car__:scope

자동차 진료정보 수집 범위는 세 층으로 걸린다 — 전역 토글 `enable_treat_car`(DB `tn_treat_setting`, 미설정 시 env 폴백) · 자체엔진 카나리 `enable_inhouse_car_canary`(같은 테이블) · 공급자 다중 모드 여부. 전역 토글이 꺼져 있으면 즉시 범위 밖이고 **DB 조회가 던져도 범위 밖이다**(fail-closed). 세 값 중 둘이 DB 설정 키라 실제 범위가 이 저장소에서 확정되지 않는다. 닫을 경로는 `ops-40-db-snapshot` 이다.

## 연혁

릴리스 태그가 존재하지 않는다. 릴리스 열은 `—` 로 두고 커밋 SHA 로 추적한다. 행은
`docs/_meta/index/commits.server.jsonl` 이 이 문서의 앵커 경로 접촉으로 기록한 커밋 집합 안에서
**연동 조건이 바뀐 시점**만 골랐다. 만료값을 조정하기만 한 커밋은 값의 변경이고 연동 조건의
변경이 아니므로 제외했으며, 그 판정은 게이트가 하지 못한다 — 게이트는 앵커 경로 접촉과 날짜
정합까지만 본다.

| 릴리스 | 날짜 | SHA | 변경 요약 |
|---|---|---|---|
| — | 2026-06-04 | `21b4a602` | 둘째 공급자가 붙고 공급자 스위치가 생긴다 — 이때부터 *어느 공급자가 부르는가* 가 편성 문제가 된다 |
| — | 2026-06-05 | `af16d981` | 다중 공급자 디스패처 신설 — 폴백 층이 처음 생긴 시점 |
| — | 2026-06-05 | `42fb6e77` | 처리업체 기록과 관리자 단가 설정 — **공급자 편성이 코드에서 DB 로 넘어간 시점** |
| — | 2026-06-05 | `68853192` | 넷째 공급자 추가 — 정규화 매퍼를 갖는 형태가 정착한다 |
| — | 2026-06-12 | `45f2698b` | 자체엔진이 다섯째 공급자로 붙는다 — 매퍼 없이 자기 형태를 그대로 지는 유일한 후보 |
| — | 2026-06-27 | `79523e03` | 자동차 수집 전역 토글이 환경값에서 DB 설정으로 옮겨간다 — **`데이터 의존` 이 생긴 지점** |
| — | 2026-06-30 | `90b878fb` | 라우팅이 정렬 우선순위 기준으로 전환 — 순서의 정본이 DB 열이 된다 |
| — | 2026-07-20 | `8cc3230c` | 자체엔진 카나리가 전역 토글 아래로 들어간다 — 자동차 게이트가 3층이 된 시점 |
| — | 2026-07-20 | `02c4103a` | 카나리 밖에서 fail-closed — **DB 조회 장애를 닫힘으로 접는 방향이 여기서 선다** |
