# Implementation Report: 스케줄 · 벤더 · 법적 정책 문서 M4 — 벤더 연동 정책과 미판정의 두 종류

**Plan**: `.claude/plans/insuniverse-docs-40-runtime-vendor-legal-m4.plan.md`
**Notes (리뷰 기록 · 음성 관찰 · 구현 로그)**: `.claude/notes/insuniverse-docs-40-runtime-vendor-legal-m4.md`
**Branch**: `40-runtime-vendor-legal`

## Summary

`docs/06-vendors/` 에 문서 세 건을 신설하고 정책 45건을 세웠다. M3 가 벤더의 **응답 의미**를
닫았다면 이 창은 그 앞 단계 — **연동 자체가 무엇에 걸려 있는가** — 를 연다. 인덱스에서 유도한
연동 층 35칸(treat 5벤더 × 4 · non-treat 3벤더 × 5)에 계획서가 선언한 코드 전용 정책 10건을
더했다.

**이 창이 더한 판정은 미판정이 한 종류가 아니라는 것이다.** M1~M3 는 미판정 전건을
`conditional-unknown` 하나로 닫았다. M4 는 그것을 둘로 가른다 — 발효 조건이 주입 환경값이라
**닫을 경로가 범위 밖**인 `conditional-unknown` 42건과, 발효 조건이 관리자 설정 행이라 **닫을
경로가 `ops-40-db-snapshot` 이라는 이름을 갖는** `data-dependent-unknown` 3건. 어휘 신설은 없다
(UI12 — `data-dependent-unknown` 은 `template-config.yaml` 8종에 이미 있었다).

그 갈림을 저자가 고르지 않는다. 게이트 `#5` 가 동결 트리에서 DB/env 토큰을 재스캔해 게이트 종류
4어휘를 만들고 `#3` 이 거기서 status 를 유도하며, `#3a` 가 **두 종류가 각각 1건 이상 나오는지**를
함께 문다 — 한쪽이 0이면 통과가 아니라 실패이고 그때 반증되는 것은 문서가 아니라 계획서 §Summary 다.

## 진입 상태 — plan-codex 가 `divergent` 로 봉인돼 있었다

**이 창은 승인된 계획이 아니라 반려가 봉인된 계획 위에서 돌았다.** 숨기지 않고 적는다.

| 항목 | 값 |
|---|---|
| `resolution.review_verdict` | `divergent` |
| L2 quorum | passed=false · required 3 of 4 · responded 4 |
| perspectives | architect **fail** · security pass · test pass · invariant pass |
| 원인 | `MCCP_REVIEW_SINGLE_PASS=deadline_pressure` 가 라운드 캡을 1로 고정 → 흡수 라운드 없이 봉인 |

진입 근거는 셋이다 — (1) mccp receipt 게이트가 `ALLOW` 했고 `mccp_receipt_gate` 블록도 주입되지
않았다 (2) receipt 가 미추적이라 tracked-receipt 교착이 아니며 실제 하류 게이트인
`codex_verdict` 를 이 창의 implement receipt 가 `skipped` 로 적어 cross-gate dedupe 가
fail-closed 를 유지한다 (3) 반려 7건 중 구현을 막는 형태가 없다.

**반려 7건은 건별로 처리했다** (전문은 notes §반려 흡수).

| # | 지적 | 처리 |
|---|---|---|
| A1 | `#2d` 가 축 2 의 30%만 덮는다 | 흡수 — `#2d` 가 **사각의 크기를 매 실행 계수로 자백**한다 (보유 3 / 미보유 7 + 이름 열거) |
| A2 | "손으로 만들지 않는다" 산문과 축 2 손저작이 모순 | 부분 흡수 — 구현은 축 2 를 *선언* 으로 취급하고 유도 주장은 축 1 에만 붙인다 |
| A3 | 축 2 오류 시 구조적 교착 | 동의 · 설계대로 — 계획서가 의도한 실패 경로이고 이 창은 그 규약을 지켰다 |
| A4 | Acceptance 의 `#2d` 검증가능 주장과 완전성 `(미검증)` 모순 | 흡수 — `#2d ok` 뒤에 `#2d 사각:` 줄을 따로 낸다 |
| I1 | `preflight` 일회용이라 회귀를 못 잡는다 | 흡수 — `preflight` 가 문서 존재를 스스로 관측하고 그 상태에서는 판정하지 않는다 |
| I2 | 축 2 완전성 간극 | 부분 흡수 — 간극의 **크기**를 매 실행 출력에 낸다. 열린 집합이라 닫히지 않는다 |
| I3 | 동결 포인터 유효성 게이트 부재 | 흡수 — `#0c` 신설. manifest `repos[].head` 를 상위 체크아웃에서 실제 commit 으로 연다 |

봉인된 `divergent` 는 지우지 않았다. 이월 원장 `id=40m4-plan-sealed-divergent` 에 그 상태와
재봉인 경로를 적었다.

## Assessment vs Reality

| Metric | Predicted (Plan) | Actual |
|---|---|---|
| Complexity | Large | Large — 문서 3건(1,394행) + 하네스 1건(약 1,500행) |
| 정책 수 | 축 1 35 + 축 2 10 = 45 | **45** (01=23 · 03=11 · 04=11) |
| Files Changed | CREATE 4 · UPDATE 2 | CREATE 4 · UPDATE 2 (+ notes 1 · 이 리포트 1) |
| 미판정 분포 | 두 종류가 각각 1건 이상 | `data-dependent-unknown` **3** · `conditional-unknown` **42** |
| 본문 정책 | 0건 (네 번째 반복) | **0건** — 게이트 `#3c` 가 본문 자격 0 == 본문 정책 0 을 문다 |

## Tasks Completed

| # | Task | Status | Notes |
|---|---|---|---|
| 0 | 게이트 하네스를 문서보다 먼저 세운다 | 완료 | `preflight` 로 *문서 부재 시 13검사 전건 non-zero · `#2b`·`#15` 통과* 를 실행 확인 |
| 1 | 문서 3종 골격 + 정책 45건 프론트매터 | 완료 | id·status·앵커 전건 유도. 저자는 산문만 저작 |
| 2 | 연동 층 대조표 3건 · 두 미판정 갈림 | 완료 | 뒤 세 열은 `derive` 출력에서 왔고 `#5`·`#3` 이 같은 유도기로 대조 |
| 3 | 01 풀 축 산문 + 벤더별 진입 형태 | 완료 | 극성 갈림은 판정하지 않고 두 앵커 병기 |
| 4 | 03 환경별 모드 + 재현 불가 | 완료 | 동결 site `.env` 0건을 그대로 적고 구값을 옮기지 않았다 |
| 5 | 04 FCM 사각 · push.scheduler 수용 · 플랫폼 차이 | 완료 | 차집합이 `{fcm, mailer, s3, user}` 4건으로 나와 전건 기술 |
| 6 | 부록 격리 + 미판정 사유 두 어휘 | 완료 | `limitations` 2건(FCM 부재 3층 · 자동차 극성 갈림) |
| 7 | 연혁 3건 + 나머지 세 절 + lint | 완료 | 연혁 01=9 · 03=2 · 04=5 행. `--strict-refs` 8파일 위반 0 |
| 8 | 전 게이트 재실행 · PRD · 이월 | 완료 | 이월 12행을 **게이트 앞에** 적었다 |

## Validation Results

| Level | Status | Notes |
|---|---|---|
| 정적 검사 (doc-kit lint) | 통과 | `OK — 8개 파일, 위반 0 (--strict-refs)` — 신설 3 + 선행 5 |
| 게이트 하네스 | 통과 | `all ok 16/16 통과` (`#0`~`#15`) |
| 선행 회귀 | 통과 | M1 15/15 · M2 13/13 · M3 14/14, 분자==분모 · 분모 ≥ `--help` 선언 |
| 음성 케이스 | 통과 | 17 + 6 케이스 전건 rc=1, 복원 digest 일치 |
| 빌드 · 단위 테스트 | N/A | 산출물이 Markdown 3 + 게이트 스크립트 1. 이 저장소에 빌드·테스트 표면이 없다 |

### Design Grounding (v1.18.22)

**Design Grounding: N/A (no design trigger).** `impeccable-detect.js --mode implement` 가
`design_signal: false` · `silent_skip: true` (`reason: no-signal`) 를 냈다 — 이 창의 diff 는
`.md` 와 `.mjs` 뿐이다. 2.5.5c 캡처가 돌지 않았으므로 Phase 3.6 · 3.7 은 아티팩트 부재로 no-op.
receipt 에 `--impeccable-silent-skip --impeccable-silent-skip-reason "no-signal"` 을 넘겼다.

계획서 §Design Critique 의 plan 단계 탐지는 `design_signal: true` 였고 그 신호원은 §GROUND 관측 8
이 **인용한** 동결 site 트리의 기존 파일 3종이었다. 계획서가 그것을 오탐으로 예고했고 implement
단계 탐지(git diff 기반)가 확인했다.

## Files Changed

| File | Action | Lines |
|---|---|---|
| `docs/06-vendors/01-treat-providers.md` | CREATED | +625 |
| `docs/06-vendors/03-payments.md` | CREATED | +366 |
| `docs/06-vendors/04-messaging.md` | CREATED | +403 |
| `.claude/plans/insuniverse-docs-40-runtime-vendor-legal-m4.gates.mjs` | CREATED | 하네스 `#0`~`#15` + `derive` + `preflight` |
| `.claude/prds/insuniverse-docs-40-runtime-vendor-legal.prd.md` | UPDATED | +1 / -1 (Delivery Milestones 4행) |
| `.claude/plans/codex-findings-backlog.md` | UPDATED | +12행 (이월) |
| `.claude/notes/insuniverse-docs-40-runtime-vendor-legal-m4.md` | CREATED | 리뷰 기록 · 반려 흡수 · 음성 관찰 · 구현 로그 |

## Deviations from Plan

계획서 본문은 `plan_hash` 앵커라 **하나도 고치지 않았다.** 편차는 전건 이월 원장에 id 와 함께 올렸다.

| # | 편차 | 왜 | 이월 id |
|---|---|---|---|
| 1 | env 토큰 정규식이 제네릭 호출(`get<T>(`)을 관용한다 | 계획서 리터럴로는 aligo 의 env 접근 8건이 전부 미탐 → **거짓 `none`**. `none` 을 "두 토큰이 다 없었다는 관측" 으로 정의한 §축 4 를 그 거짓이 직접 깬다 | `40m4-env-token-generic-widened` |
| 2 | 층 앵커 승계 규칙 3단 신설 | 인덱스 층 35칸 중 8칸에 `anchors[]` 가 없다. 규칙대로 두면 §축 4 의 *0파일 → exit 1* 에 정상 층이 걸린다 | `40m4-layer-anchor-inheritance-rules` |
| 3 | `#2d` 귀속 경로를 셋 → 넷으로 | 벤더성 키 12종 중 `mailer`·`s3`·`user` 가 계획서 세 경로 밖이고 `## NOT Building` 은 봉인. 넷째 경로는 `#14` 가 **이미 요구하는** 04 사각 절 기술이다 | `40m4-2d-fourth-discharge-path` |
| 4 | `#14b` 신설 (플랫폼 계수 재유도) | Task 5 가 요구한 재계수에 대응 게이트가 없었다 — 주장 ≠ 검사 | `40m4-14b-added-recount` |
| 5 | `#0c` 신설 (동결 포인터 대조) | plan-codex invariant/LOW(I3) 흡수 | notes §반려 흡수 I3 |
| 6 | `#2c` 가 '선행 5문서' 를 쓴다 | 계획서 `#2c` 문면은 '4문서', 같은 계획서 `#0b` 는 '5문서'. 실측은 5 | `40m4-2c-prior-doc-count` |

### 계획서 축 2 기대값 대비 재유도 편차 — 4건, 전건 status 보존

`#5c` 가 매 실행 이름으로 낸다: `__pool__:membership`·`__pool__:routing`·`__car__:scope` 가
`db → both`, `messaging:fcm:token-lifecycle` 이 `none → env`. **네 건 모두 미판정 종류를 바꾸지
않는다** (`db`·`both` → 데이터 의존 / `none`·`env` → 게이트 미상). `#5c` 는 편차가 status 를
바꾸면 그 자리에서 죽는다 — 관측과 판정의 경계를 코드가 진다. 계획서 §축 4 가
*"로케이터 표를 믿지 않고"* 로 이 편차를 미리 허용했다.

## Issues Encountered

| 문제 | 해소 |
|---|---|
| receipt-write 가 `other-live-holder` 로 8분간 차단 | `/clear` 직전 세션이 같은 work unit 을 claim 중이었다. TTL 15분을 기다렸고 guard 는 끄지 않았다 |
| `parseDoc` 가 계획서·PRD 에서 0절을 낸다 | 프론트매터가 없으면 조용히 조기 반환한다. 최소 인덱서 `parsePlain` 을 두고 펜스 인지까지 복제했다 |
| `statusPlacementMap` 이 원문 문자열에 `null` 을 낸다 | 파싱된 배열을 받는 함수였다. `parseFlatYaml` 선행 + `null` 이면 사유와 함께 죽는 래퍼로 감쌌다 |
| `tableRowsInRange` 가 첫 표에서 멈춘다 | `extraTableLine` 을 따라 되풀이하는 `tablesIn` 을 뒀다 |
| `-w` 단어 경계로는 `REACT_APP_BRIDGE_NAME` 이 0건 | `#14b` 는 부분 문자열 매칭이며 그 사실을 출력에 적는다 |

## Tests Written

전용 테스트 파일은 없다. 이 저장소의 검증 표면은 게이트 하네스이며 `#11` 이 하네스 자신을
프로브한다(`--help` 양성 · 알 수 없는 서브커맨드 exit 1 · 의존 지정자 4건 전건 허용 목록 안).
음성 케이스 23건은 `.claude/notes/…-m4.md` §음성 케이스 관찰에 출력과 함께 기록했다.

## 남은 것 — `(미검증)`

- **축 2 완전성**: 코드 전용 정책을 하나도 빠뜨리지 않았는가는 열린 집합이라 게이트로 닫히지
  않는다. `#2d` 가 사각의 **크기**를 매 실행 계수로 낸다 — 축 2 10건 중 `configuration.ts` 앵커
  보유 3건, 미보유 7건은 이름으로 열거된다. 판별 자체의 사각(블록 키와 유닛 디렉터리 **이름이
  어긋나는** 연동 — 본인확인·챗봇 웹훅·동영상 API·CDN)도 같은 줄에 적힌다.
- **`[구-SHA]` 3행 재측정 결과 3갈래**: 이월 표에 행으로 남았다(사람 확인).
- **온보딩 질문 커버리지**: 유지보수자 판정.

## Next Steps

- [ ] `/mccp:code-review` 로 커밋 전 검토
- [ ] `/mccp:prp-commit` 후 `/mccp:pr`
- [ ] `MCCP_REVIEW_SINGLE_PASS` 를 풀고 `/mccp:plan` 재실행 → plan-codex 를 실제 verdict 로 재봉인
      (`id=40m4-plan-sealed-divergent`)
