# Notes: insuniverse-docs-40-runtime-vendor-legal-m4

Plan: `.claude/plans/insuniverse-docs-40-runtime-vendor-legal-m4.plan.md`

이 파일은 `/mccp:prp-implement` 구현 창의 리뷰 기록이다. **계획서 본문에 쓰지 않는다** —
`mccp-plan-codex` receipt 가 `plan_hash` 로 계획서를 결박하고 있어 본문 편집은 그 receipt 를
stale 로 떨어뜨린다. 계획서 §NOT Building 도 착수 후 본문 편집을 명시적으로 금지한다.

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

이 창은 **승인된 계획이 아니라 반려가 봉인된 계획** 위에서 돈다. 그 사실을 먼저 적는다.

`.claude/receipts/mccp-plan-codex/insuniverse-docs-40-runtime-vendor-legal-m4.json` 실측:

```
resolution.review_verdict           divergent
resolution.review_proof.layers      l1 converged · l2 divergent · l3 null
resolution.review_proof.quorum      passed=false · required 3 of 4 · responded 4
perspectives                        architect fail · security pass · test pass · invariant pass
meta.review_single_pass_reason      deadline_pressure
meta.review_single_pass_bypassed_verdict  true
```

`MCCP_REVIEW_SINGLE_PASS=deadline_pressure` 가 라운드 캡을 1로 고정했고, 그래서 architect 의
반려가 **흡수 라운드 없이 그대로 봉인**됐다. `.claude/state/fix-task.md` 가 그 상태를 이어받아
`/mccp:santa-loop` 을 요구하고 있다.

**이 창은 santa-loop 을 돌지 않고 진입했다.** 근거는 셋이다.

1. mccp receipt 게이트가 이 진입을 **ALLOW** 했다 — `mccp ALLOW path: mccp:prp-implement`.
   `mccp_receipt_gate` 컨텍스트 블록이 주입되지 않았으므로 Phase 0.0 복구 경로도 성립하지 않는다.
2. receipt 는 아직 **미추적**(`git status` 가 `??`)이라 tracked-receipt 교착이 아니다.
   `escalate_pending` 은 자기 해제가 불가능한 상태 표기이고, 실제 하류 게이트는
   `resolution.codex_verdict` 다 — 이 창의 implement receipt 는 그것을 `skipped` 로 적으므로
   cross-gate dedupe 가 PR-Codex 를 건너뛰지 않는다(fail-closed 유지).
3. **architect 반려 4건 중 어느 것도 구현을 막는 형태가 아니다.** 아래 §반려 흡수가 건별로
   무엇을 흡수했고 무엇이 계획서 봉인 때문에 흡수 불가인지 적는다.

봉인된 `divergent` 는 이 창이 지우지 않는다. Phase 5 리포트와 PR 본문이 그 상태를 그대로 싣는다.

### 반려 흡수 — architect 4건 · invariant 3건

층위는 `CLAUDE.md` §2 체크리스트 번호.

| # | 지적 | 층위 | 판정 | 처리 |
|---|---|---|---|---|
| A1 | `#2d` 가 축 2 의 30%(3/10)만 덮는다. 나머지 7건은 `configuration.ts` 앵커가 없어 그 검사로 검증 불가인데 계획서는 이를 *사소한 사각* 으로 적었다 | 8 | **흡수(하네스)** | 계획서 본문은 못 고친다. 대신 `#2d` 출력이 **사각의 크기를 매 실행 자백**하게 만든다 — 축 2 10건 중 `configuration.ts` 앵커 보유 건수와 미보유 건수를 유도해 찍고, 미보유 건은 이 검사가 못 보는 집합임을 이름으로 열거한다. 사각을 문장이 아니라 계수로 낸다 |
| A2 | Task 1 산문은 *"정책 id 를 손으로 만들지 않는다"* 인데 축 2 10건은 손으로 골라 표에 박혔다 | 2 | **흡수(부분)** | 산문 모순은 계획서 안이라 못 고친다. 구현은 축 2 를 *유도* 로 취급하지 않고 **선언**으로 취급한다 — 하네스는 축 2 를 `DECLARED_AXIS2` 상수로 두고 `#2b` 가 계획서 표와 집합 대조하며, 세 번째 출처(동결 트리)가 `#5`·`#8` 로 각 행을 친다. 유도 주장은 축 1 에만 붙인다 |
| A3 | 축 2 가 틀리면 구조적으로 막힌다 — 계획서 본문은 못 고치고 하네스만 고치면 `#2b` 가 깨진다 | 1 | **동의 · 설계대로** | 이것은 결함이 아니라 계획서 §201 이 **의도한 실패 경로**다. 축 2 오류 시 대응은 편집이 아니라 중단 후 `/mccp:plan` 재진입이다. 이 창은 그 규약을 지킨다 — 축 2 행이 검사에 걸리면 하네스 상수를 문서에 맞추지 않는다 |
| A4 | Acceptance 의 `#2d` 검증 가능 주장과 축 2 완전성 `(미검증)` 이 모순이다 | 7 | **흡수(하네스)** | A1 과 같은 자리. `#2d` 는 *설정 블록 키가 전건 귀속된다* 만 판정하고 *축 2 가 완전하다* 는 판정하지 않는다. 그 구별을 출력 문면에 못박는다 — `#2d ok` 줄 뒤에 `#2d 사각:` 줄을 따로 낸다 |
| I1 | `preflight` 가 일회용이라 Task 1 이후 검사가 문서 부재에 눌러앉는 회귀를 아무도 못 잡는다 | 8 | **흡수(하네스)** | `preflight` 를 일회용으로 두되 **문서를 임시로 가린 상태에서 재실행 가능**하게 만든다. `all` 에는 넣지 않는다(계획서 요구). 대신 `preflight` 가 문서 존재 여부를 스스로 관측해 출력에 찍으므로, Task 8 이후 다시 돌리면 *문서가 있는데 왜 이걸 도느냐* 를 스스로 보고한다 |
| I2 | 축 2 완전성이 Summary 주장과 Acceptance `(미검증)` 사이에 벌어져 있다 | 2 | **흡수(부분)** | A1·A4 의 계수 자백이 이 간극의 크기를 매 실행 출력에 낸다. 간극 자체는 열린 집합이라 안 닫힌다 |
| I3 | 동결 트리 포인터가 계획 저작 시점에 고정돼 있고 그 유효성을 검사하는 게이트가 없다 | 8 | **흡수(하네스)** | `#0` 에 팔을 하나 더한다 — 동결 3트리 SHA 를 `extraction-manifest.yaml` `repos[].head` 에서 재유도해 하네스 상수와 대조한다. 어긋나면 exit 1. INV2 의 직접 항체이고, 계획서 §Files to Change 밖 파일을 **읽기만** 한다 |

## Codex Implementation Review

- 호출: `node C:/Users/madsc/.claude/plugins/cache/mccp/mccp/1.32.1/scripts/lib/codex-invoke.js adversarial-review` (fail-closed Bash wrapper, v0.2.2)
- 라운드 수: 0
- **Codex skipped per `MCCP_CODEX_DISABLED=1`** — env-level 정책이며 도구 실패가 아니다.
  `/usr/bin/env` 실측에서 `MCCP_CODEX_DISABLED=1` 을 확인했다(설정 출처는
  `C:/Users/madsc/.claude/settings.json` 의 `env` 블록). 셸 프로브로는 안 보이는 축이라
  환경 열거로 확인한다.
- 게이트 기록값: `codex_verdict = skipped` · `meta.codex_disabled = true`.
  **`converged` 가 아니다** — cross-gate dedupe(`dedupe.js#evaluateForDedupe`)는 `converged`
  이외의 값에 fail-closed 이므로 이 receipt 는 하류 PR-Codex 를 건너뛰게 만들지 않는다.
- 합치 결론: 없음 — 리뷰가 돌지 않았으므로 합치도 없다. 아래 §2.5.2 목록이 **리뷰를 받지 못한
  결정 집합**이고 그것이 이 절이 남기는 유일한 실질이다.
- YAGNI Triage: 해당 없음 — findings 0건.
- Deferred to backlog: 0 (리뷰 산출 없음). 계획서 plan-codex 라운드가 남긴 **반려 7건**은
  위 §반려 흡수가 건별로 처리했고, 이월 대상은 Task 8 이 `codex-findings-backlog.md` 로 보낸다.
- Open Questions: 없음.
- Codex session 참조: 없음 (미호출).

### 이 창에서 새로 생기는 implement-time 결정 (2.5.2 — 리뷰를 못 받은 목록)

계획서가 pre-commit 하지 않은 것만 적는다. Codex 가 꺼져 있어 **아래 9건은 리뷰를 받지 못했다.**

1. `vendor-behaviors.yaml` 제한 리더의 수용 형태 — 계획서 Task 0 은 *"필요한 사실만 읽는 제한
   리더를 두고 모르는 형태는 관용하지 않고 죽는다"* 까지만 정했다. M3 하네스의 `vendorIndex()`
   가 같은 파일을 이미 읽지만 `outcomes` 축만 본다. 층 키(`timeout`·`fallback`·`normalization`·
   `exception`·`env_gates`)를 어느 중첩 깊이까지 받을지는 이 창의 결정이다.
2. 축 4 결합 규칙의 **스캔 단위 파일 해석** — 계획서는 *"정책 `anchors[]` 가 가리키는 파일들의
   합집합"* 까지만 정했다. 앵커 문자열(`treat-provider.service.ts 52행`)에서 동결 트리의 실 경로와
   저장소(server/site)를 어떻게 유도할지는 미정이다. 파일명만으로 트리를 훑을지, 확장자·이름
   패턴으로 저장소를 먼저 가를지가 `#5`·`#8` 의 사각 크기를 좌우한다.
3. `preflight` 의 문서 의존 검사 13종 열거 방식 — 하드코드 목록인지 검사 메타데이터에서 유도하는지.
   하드코드면 검사를 추가할 때 조용히 빠질 수 있고, 유도면 유도 규칙 자체가 검사 대상이 된다.
4. `#2d` 의 *"벤더성 설정 블록 키"* 판별 규칙 — `configuration.ts` 의 어느 최상위 키를 벤더성으로
   볼 것인가. 이 판별이 넓으면 오탐, 좁으면 A1 사각이 커진다. **A1 흡수가 이 결정에 직접 걸린다.**
5. `#15` PRD diff hunk 파서 형태 — `git diff HEAD -- <PRD>` 의 `@@` 헤더에서 신 파일 행 범위를
   읽어 절 범위와 교차시키는 방식. 절 범위는 `## Delivery Milestones` 헤더부터 다음 `## ` 까지다.
6. `#2b` 의 계획서 축 2 표 재파싱기 — 마크다운 표를 node 로 읽되 어느 앵커로 표를 특정할지.
   계획서에 5열 표가 여럿이라 헤더 문자열 일치가 필요하다(셸 파서는 금지 축, §NOT Building).
7. 연혁 행 선정 — 계획서 Task 7 이 *"연동 조건이 바뀐 시점만 싣는다"* 로 판정을 저자에게 남겼고
   게이트 `#9` 는 앵커 경로 접촉까지만 본다. Acceptance 가 이미 `(미검증)` 으로 자백한 축이다.
8. `#13` 코드값 패턴 집합의 구성 — 계획서가 *"패턴은 표본이고 범위가 아니다"* 로 사각을 자백했으나
   표본의 구성(대문자 상수형 정규식의 형태)은 미정이다.
9. 동결 트리 독출 캐시의 형태 — Risks 표가 *"검사별로 캐시"* 를 요구했으나 캐시 키(트리 SHA +
   경로)와 무효화 시점은 미정이다. M3 하네스가 2분을 넘긴 것이 이 결정의 배경이다.

### Security Reviewer

해당 없음 — 이 창의 산출물은 `docs/**` 마크다운 3건과 `.claude/plans/**` 게이트 하네스 1건,
그리고 PRD·backlog 각 1행이다. 인증·암호·비밀값·입력 검증·주입·SSRF·경로 순회·권한 상승 어느
표면도 **구현하지 않는다**. 문서가 벤더 자격증명·서명 축을 *기술* 하지만 계획서가 값·키 이름·
알고리즘 파라미터의 전사를 금지하고 검사 `#6`·`#13` 이 그 0건을 문다 — 기술은 표면이 아니다.
Phase 2.5.5 의 트리거 조건(*"security-sensitive areas"*)이 성립하지 않으므로 `security_skipped`
플래그를 세우지 않는다. 이것은 폴백 은폐가 아니라 **트리거 미성립**이다(M2·M3 receipt 도 같다).

### Design Review

`impeccable-detect.js detect --mode implement --json` 실측:

```json
{"skill_available":true,"cli_available":true,"design_signal":false,"signal_files":[],
 "mode":"implement","reason":"no-signal","silent_skip":true,"silent_skip_reason":"no-signal",
 "impeccable_invocation":"impeccable","impeccable_version":"4.0.4"}
```

SKILL_AVAIL=1 · SIGNAL=0 · DESIGN_INTENT_ACTIVE=0 이므로 2.5.5b 결정표의 silent-skip 행이다 —
receipt 에 `--impeccable-silent-skip --impeccable-silent-skip-reason "no-signal"` 을 넘긴다.

**계획서 §Design Critique 의 plan 단계 탐지(`design_signal: true`)와 결과가 다르다.** plan 단계는
동결 site 트리의 인용 앵커 3파일(`PushEventConsentPopup.tsx` · `PushSettingsPage.tsx` ·
`PushConsentModal.tsx`)을 신호로 잡았고, implement 단계는 **git diff 를 본다** — 이 창의 diff 는
`.md` 와 `.mjs` 뿐이라 신호가 0이다. 계획서가 그 오탐을 예고했고 implement 탐지가 그것을 확인했다.

렌더 표면이 없으므로 라우팅(2.5.5b) · 크리티크 루프 · 방향 캡처(2.5.5c) 는 돌지 않고,
그 결과 Phase 3.6 · 3.7 은 아티팩트 부재로 no-op 이다.

## 음성 케이스 관찰 (Task 0 · 계획서 §Validation 이 이 절로 보낸 기록)

계획서 §Validation 이 *"나머지는 하네스가 서는 Task 0 에서 한 번씩 실행하며 그 관찰은 계획서가
아니라 `.claude/notes/` 에 기록한다"* 로 이 절을 예약했다. 아래는 **실행해서 본 출력**이지
예상이 아니다. 매 케이스는 변이 → 검사 → 복원이고, 복원은 `finally` 가 아니라 **등록부 +
process exit 훅**으로 걸었다(`die()` 류가 `finally` 를 건너뛰는 실패 모드를 프로브 자신도 갖는다).
마지막에 sha256 대조로 복원을 확인했다 — `restore: ok (digest 전건 일치)`.

### (가) 하네스가 선 시점 — 문서 부재로 13검사가 떨어지고 2검사는 통과한다

계획서 Task 0 이 그 주장을 산문이 아니라 `preflight` 서브커맨드로 만들라고 요구했다. 문서 3종이
없는 상태에서 돌린 실측:

```
preflight — 문서 존재: 0건 / 3
preflight ok 문서 의존 검사 13종 중 통과 0건 — 전건 non-zero
preflight ok #2b 통과 — 계획서 축 2 표 10행 == 하네스 상수 10행
preflight ok #15 통과
```

**하네스가 문서에 맞춰 휘지 않았다는 관찰이 이것이다** — 하네스는 문서보다 먼저 섰고 그 시점에
문서를 보는 검사 전건이 떨어졌으며, 문서 없이도 성립해야 하는 둘은 통과했다.

`preflight` 는 일회용이지만 **재실행 가능하다**(plan-codex invariant/MEDIUM 흡수 I1). 문서가 있는
상태에서 돌리면 스스로 그 사실을 관측해 `문서 존재: …` 와 경고 한 줄을 찍고 **판정하지 않는다** —
문서가 있는데 통과하는 것은 정상이기 때문이다. `all` 에는 넣지 않았다(계획서 요구).

### (나) 검사별 음성 케이스 — 변이 → rc=1 → 복원

| 검사 | 변이 | rc | 관찰된 실패 |
|---|---|---|---|
| `#1` | 정책 하나를 부록에서 본문으로 올린다 | 1 | `#1 FAIL: lint 가 exit 1` (규칙 `placement` 위반) |
| `#2` | 프론트매터에서 선언 id 하나를 뺀다 | 1 | `#2 FAIL: 04-messaging 에 유도 id messaging:aligo:local-mock 부재` |
| `#2b` | 하네스 축 2 상수의 게이트 종류를 바꾼다 | 1 | `#2b FAIL: 축 2 5행 '게이트 종류' 불일치 — 계획서 'env' / 하네스 'db'` |
| `#3` | 데이터 의존 정책의 status 를 게이트 미상으로 바꾼다 | 1 | `#3 FAIL: treat-provider:__car__:scope 유도 data-dependent-unknown 문서 conditional-unknown` |
| `#4` | 03 에 다른 축 벤더 층을 하나 넣는다 | 1 | `#4 FAIL: 문서 03 벤더 집합 잉여 aligo` |
| `#5` | 대조표에서 자동차 범위 행의 게이트 종류를 env 로 고친다 | 1 | `#5 FAIL: treat-provider:__car__:scope 재유도 both 문서 env` |
| `#6` | 봉쇄 목록의 만료 값 하나를 산문에 적는다 | 1 | `#6 FAIL: docs/06-vendors/03-payments.md:151 봉쇄 값 30000` |
| `#7` | 벤더별 진입 형태 표에서 한 행을 지운다 | 1 | `#7a FAIL: 진입 형태 표 누락 [hyphen] 잉여 []` |
| `#8` | 앵커 행 번호를 파일 행수보다 크게 적는다 | 1 | `#8 FAIL: 행 초과 — …/push.scheduler.ts:99999 (파일 29행)` |
| `#9` | 연혁 SHA 한 글자를 바꾼다 | 1 | `#9 FAIL: 04-messaging 연혁 SHA 2ec78695 를 commits.server.jsonl 에서 못 찾는다` |
| `#9` | 이 문서의 앵커를 안 건드린 커밋을 연혁에 넣는다 | 1 | `#9 FAIL: 03-payments 21b4a602 날짜 불일치 — 인덱스 2026-06-04 문서 2026-01-29` |
| `#10` | 적용 범위 표에서 한 행을 지운다 | 1 | `#10 FAIL: 03-payments 적용 범위 부족 payment:toss:exception` |
| `#12` | 배치표를 안 고치고 다른 스케줄러 정책을 넣는다 | 1 | `#12 FAIL: 문서 누락 push.scheduler` |
| `#13` | 문서에 벤더 코드값 하나를 적는다 | 1 | `#13 FAIL: 목록 밖 코드값 2건 — 03-payments.md:165 코드값 CF-12103` (두 패턴이 같은 히트를 잡는다) |
| `#14` | 사각 절에서 차집합 키 하나를 지운다 | 1 | `#14 FAIL: 차집합 mailer 미기술` |
| `#14b` | 플랫폼 차이 표의 계수를 하나 고친다 | 1 | `#14b FAIL: BRIDGE_NAME 소비 횟수 문서 31 재계수 32` |
| `#15` | PRD 의 절 범위 밖 한 줄을 고친다 | 1 | `#15a FAIL: 절 범위 밖 변경 194 (절 196~210)` |

**`#9` 의 두 팔이 다른 사유로 떨어진다.** SHA 를 한 글자 바꾸면 *인덱스 부재* 로, 이 문서와 무관한
커밋을 넣으면 *날짜 불일치* 로 먼저 걸린다. 계획서가 예상한 *앵커 경로 미접촉* 분기는 날짜까지
맞춘 무관 커밋에서만 도달한다 — 세 팔 모두 rc=1 이며 겨냥한 층위는 같다.

**`#13` 은 한 히트를 두 패턴이 잡는다.** `CF-12103` 이 `codes/vendor.yaml pattern` 과 `CF-nnnnn`
양쪽에 걸려 2건으로 세어진다. 계수는 위반 **건수**가 아니라 (히트 × 패턴) 이며, 그 사실이 출력에
패턴 이름과 함께 나오므로 오독되지 않는다.

### (다) `#0` 세 팔 — 회귀 · 워킹트리 불변 · 동결 포인터

| 변이 | rc | 관찰 |
|---|---|---|
| 선행 M1 문서에서 정책 블록 1건 삭제 | 1 | `#0a FAIL: M1 rc=1 (검사 check1 check6 에서)` — 어느 하네스의 어느 검사가 떨어졌는지 이름으로 찍는다 |
| 선행 문서에 개행 1개만 추가하고 고치지 않음 | 1 | `#0a FAIL: M2 rc=1 (검사 check0 … check12 에서)` |
| manifest head 를 실재하지 않는 SHA 로 바꾼다 | 1 | `#0c FAIL: manifest head 00000000 를 insuniverse-server 에서 열 수 없다 — 동결 포인터가 실재하지 않는다` |

**둘째 팔의 관찰이 계획서 예상과 다르다.** 계획서는 워킹트리 오염이 `#0b` 에서 별도 사유로
떨어질 것으로 적었는데, 실제로는 **M2 하네스 자신이 같은 불변식을 갖고 있어 `#0a` 에서 먼저**
죽는다. `#0b` 는 그 뒤에 오므로 도달하지 못했다. 두 경로 모두 rc=1 이고 겨냥한 층위는 같다 —
다만 *이 하네스의 `#0b` 가 그 케이스에서 실행된다* 는 주장은 성립하지 않으며, `#0b` 가 단독으로
잡는 것은 **선행 하네스가 보지 않는 문서(예: `02-failure-semantics.md` 밖 형제 파일)의 오염**뿐이다.
그 축소된 사정거리를 여기 적는다.

셋째 팔은 계획서에 없던 검사다 — plan-codex invariant/LOW 반려(I3, 동결 포인터 유효성 게이트
부재)의 흡수로 신설했고, `extraction-manifest.yaml` `repos[].head` 를 상위 체크아웃에서 실제
객체로 열어 commit 인지 확인한다(INV2 의 직접 항체).

### (라) `#11` 양성 프로브의 필요성

| 프로브 | rc | 관찰 |
|---|---|---|
| 실 하네스 `--help` | 0 | 서브커맨드 목록 출력 |
| 없는 경로로 `--help` | 1 | `Cannot find module …\nosuch-gates.mjs` |
| 실 하네스에 알 수 없는 서브커맨드 | 1 | `알 수 없는 서브커맨드: nosuchcheck — 지원: …` |

**뒤 두 rc 가 같다.** 그래서 `#11` 은 음성 rc 만 보지 않고 `--help` 성공(rc=0 + 목록 출력)을 먼저
확인한다. 그 양성 프로브가 없으면 *하네스 부재* 와 *하네스가 unknown 을 올바로 거부* 가 구별되지
않는다.

## 구현 로그

### 계획서와 실측이 갈린 자리 — 다섯

전건 이월 원장(`.claude/plans/codex-findings-backlog.md`)에 id 와 함께 올렸다. 계획서 본문은
`plan_hash` 앵커라 고치지 않는다.

1. **env 토큰이 제네릭 호출을 놓친다** (`id=40m4-env-token-generic-widened`). 계획서 §축 4 의
   리터럴 `configService.get(` 는 `configService.get<string>(` 에 걸리지 않는다. 실측에서
   `libs/aligo/src/aligo.service.ts` 의 env 접근 8건이 전부 제네릭 형태라 리터럴이면 E=0 →
   **거짓 `none`** 이 나온다. `none` 을 *"두 토큰이 다 없었다는 관측"* 으로 정의한 §축 4 를 그
   거짓이 직접 깨므로 관용했다.
2. **인덱스 층 35칸 중 8칸에 앵커가 없다** (`id=40m4-layer-anchor-inheritance-rules`). 승계 규칙
   3단을 뒀고 어느 규칙이 쓰였는지 `derive`·`#5a` 가 층마다 낸다.
3. **`#2d` 의 귀속 경로가 셋에서 넷으로** (`id=40m4-2d-fourth-discharge-path`). 벤더성 키 12종 중
   `mailer`·`s3`·`user` 가 계획서의 세 경로 어디에도 없고 `## NOT Building` 은 봉인이라 못 고친다.
   넷째 경로는 계획서 `#14` 가 이미 요구하는 *04-messaging 사각 절 기술* 이다.
4. **`#14b` 신설** (`id=40m4-14b-added-recount`). 계획서 Task 5 가 요구한 재계수에 대응 검사가
   없었다. 부분 문자열 매칭이어야 한다 — 단어 경계로는 `REACT_APP_BRIDGE_NAME` 이 0건이다.
5. **`#2c` 문면의 '4문서' 가 실측 5문서** (`id=40m4-2c-prior-doc-count`).

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

`#5c` 가 매 실행 낸다. `db → both` 3건(`__pool__:membership` · `__pool__:routing` · `__car__:scope`)과
`none → env` 1건(`messaging:fcm:token-lifecycle`)이다. **네 건 모두 미판정 종류를 바꾸지 않는다** —
`db` 와 `both` 는 함께 `데이터 의존` 으로, `none` 과 `env` 는 함께 `게이트 미상` 으로 접히기
때문이다. `#5c` 는 편차가 status 를 바꾸면 그 자리에서 죽는다(관측이 아니라 판정이 되는 경계).

계획서 §축 4 가 *"로케이터 표를 믿지 않고"* · *"산문 규칙은 이 재유도의 기대값이고 판정 근거가
아니다"* 로 이 편차를 미리 허용했으므로 중단 사유가 아니다.

### 게이트 최종

```
$ node .claude/plans/insuniverse-docs-40-runtime-vendor-legal-m4.gates.mjs all
all ok 16/16 통과
```

## 코드리뷰 흡수 — `/mccp:code-review` 로컬 4건 전건

Task 8 이후 미커밋 12파일에 대한 로컬 리뷰. 지적 4건은 전부 하네스에 있었고 문서·계획서는
대상이 아니었다. 네 건 다 흡수했고 **매 건 반사실 검증**했다 — 수정 전 통과하던 프로브가
수정 후 뒤집히는지 실행해 확인한다.

| # | 층위 | 지적 | 판정 | 반사실 |
|---|---|---|---|---|
| H1 | 2 | `#5` 가 대조표 7열 중 `정책 id`·`게이트 종류` 둘만 물었다. 나머지 5열 무검사 + 루프가 유도 쪽만 돌아 표의 **잉여 행**을 못 봤다 | **흡수(하네스)** | 3열 위조 → 수정 전 `all 16/16`, 수정 후 `#5 FAIL: … '인덱스 값' 재유도 'vendor_side_key: 없음 · dynamic_anchors 無' 문서 '완전히 거짓인 값 999'` · 날조 행 → 수정 후 `#5 FAIL: … 유도 밖 행 treat-provider:FABRICATED:layer` |
| H2 | 5 | `#15` 가 워킹트리 diff 부재에 무조건 죽는다 — **M4 를 커밋하는 순간** `all` 이 영구 15/16 이 되고 M5 의 `#0a` 가 M4 에서 죽는다 | **흡수(하네스)** | 커밋 직후 `all` 재실행 (아래 §커밋 후 검증) |
| M1 | 8 | 제한 리더의 *"주사 층위에서 모르는 형태를 만나면 행 번호와 함께 죽는다"* 가 자기가 주사하는 층위에서 거짓 | **흡수(하네스)** | `    - stray` + `      orphan_key: 1` 주입 → 수정 전 `#2a ok … 35칸 · 건너뛴 34개`(무반응), 수정 후 `FAIL: …vendor-behaviors.yaml:49 — 'vendors:' 아래 주사 층위에서 모르는 형태` |
| L1 | 7 | `#11c` 의 의존 열거가 동적 import 호출을 못 봐 INV1 주장에 구멍 | **흡수(하네스)** | 열거 추가 직후 주석의 예시 리터럴이 스스로 잡혀 `#11c FAIL: 허용 밖 지정자 x` — 검사가 실제로 그 형태에 닿는다는 양성 증거 |

### H1 — 전사 3열 중 하나만 게이트가 있었다

하네스 머리 주석은 *"Task 2 의 저자가 대조표 **뒤 세 열**을 이 출력에서 전사한다 — 저자가
판정하지 않는다는 계약의 반대편이다"* 로 적었는데, 그 셋(`게이트 종류`·`미판정 종류`·`닫을
경로`) 중 게이트가 붙은 것은 첫째뿐이었다. `layerForm()` 결과는 `derive` 출력에만 쓰이고 어느
검사도 참조하지 않았다. 저자가 판정하지 않는다는 계약이 5열에서 성립하지 않았다는 뜻이다.

**현 문서에는 값 오류가 없었다** — 45행 × 6열을 `derive` 와 대조해 불일치 0을 먼저 확인했다.
검사 부재이지 데이터 결함이 아니다. 그래서 흡수는 값 정정이 아니라 게이트 신설이다.

### H2 — `preflight` 에서 한 번 잡은 결함이 `#15` 에 남아 있었다

plan-codex invariant 반려 I1 이 `preflight` 의 일회용성을 지적했고 그것은 흡수해 `all` 밖으로
뺐다. `#15` 는 성질이 같은데 `all` 안에 있었다. 같은 축을 두 번째로 놓친 자리다.

해소는 `all` 에서 빼는 쪽이 아니라 **모드를 가르는** 쪽으로 했다 — diff 가 있으면 갱신 자체를
물고(미커밋), 없으면 그 주장만 포기하고 절 안 4행의 내용은 계속 문다(커밋 후). 커밋 뒤에도
`Plan 셀 == 이 계획서 경로` · `Status == in-progress` · `complete 아님` 이 살아 있다.
어느 모드인지는 `#15a`·`#15b`·`#15` 출력이 매 실행 찍는다.

### 범위 밖으로 분리한 것

리뷰가 별도로 확인했으나 지적이 아닌 것: plan-codex 가 `divergent` 로 봉인된 사실(이미 §진입
상태 · backlog `40m4-plan-sealed-divergent`), `#5c` 편차 4건 · `#2c` 4문서↔5문서 · `#2d` 넷째
귀속 경로 · `#14b` 신설(전부 backlog 에 자백 완료), 신규 3문서 시크릿 스캔 0건.
