# notes — 00-protocol 마일스톤 5 implement

계획서: `.claude/plans/insuniverse-docs-00-protocol-m5.plan.md`

리뷰 섹션을 계획서 본문이 아니라 여기에 둔다 — 계획서를 편집하면 `mccp-plan-codex` receipt 의
`plan_hash` 가 어긋나 상류 게이트가 stale 로 떨어진다.

## Codex Implementation Review

- 호출: `node C:/Users/madsc/.claude/plugins/cache/mccp/mccp/1.23.0/scripts/lib/codex-invoke.js adversarial-review` (fail-closed Bash wrapper, v0.2.2)
- 라운드 수: 1 (cap 1)
- 합치 결론: R1 `needs-attention` · MEDIUM 1건. **초점으로 넘긴 7개 구현시 결정(헬퍼 배치 · golden emit 위치 · 게이트 순서 의존 · pipefail 전파 · 스테이징 트리 · selftest 재귀 상호작용 · 값 무변경)에는 지적이 0건**이고, 대신 Plan-Codex R1-F1 과 같은 축(`actors` 미검증 승격)이 재차 제기됐다. 구조적 판정은 계획 게이트에서 이미 내려졌으므로 여기서 뒤집지 않는다.

### YAGNI Triage

| Finding | Severity | Verdict | Why |
|---|---|---|---|
| I1 미검증 `actors` 를 정본 config 로 승격 — "M5 를 complete 로 표시하지 말라" | MEDIUM | **DEFER_TO_BACKLOG (중복)** | Plan-Codex R1-F1 과 동일 축. 정본 `docs/01-foundation/01-glossary.md` 가 하류 PRD(`20-foundation-access`) 산출물이라 묶으면 의존이 역전된다. `.claude/plans/codex-findings-backlog.md` 2026-08-07 MEDIUM 행이 이미 같은 내용을 담고 있어 행을 새로 늘리지 않는다 |
| I1 처방 (b) — 값을 **기계 판독 가능한 provisional** 로 표기 | MEDIUM | **REJECT_YAGNI** | schema 가 `actors` 를 *"작성자용 참조 목록"* 으로 규정하고 lint 가 이 키를 읽지 않는다. 오늘 이 키를 프로그램으로 읽는 소비자가 0 이므로 provisional 플래그를 붙여도 그것을 해석할 주체가 없다. 새 키를 넣으면 doc-kit(동결 자산)이 모르는 키가 되어 조용히 무시될 뿐이고, 값에 접미어를 붙이면 계획서가 금지한 "값 변경"이며 문서 본문으로 오염이 번진다 |
| I1 근거 (c) — "게이트와 golden 은 일관성만 증명하지 의미 오류를 못 잡는다" | — | **정정 없이 인정** | 사실이다. 다만 golden 의 `template_config.actors` 행은 *변경* 을 잡는다 — 정본이 생겨 `20-foundation-access` 가 6종을 정정하면 `--check` 가 붉어지고 명시적 `--update` 를 강제한다. 미검증 키에 걸어 둘 수 있는 유일한 기계 장치이며, *정당성* 판정은 정본이 없는 동안 존재하지 않는다 |

- Deferred to backlog: 0 신규 (기존 2026-08-07 MEDIUM 행이 커버)
- Open Questions: `actors` 6종 미검증 — severity MEDIUM (auto-CRITICAL 카탈로그 해당 없음: 보안 경계 · 원자적 상태 · 스키마 파괴 어느 축도 아니다)
- Codex session 참조: threadId `019fda8d-3000-7cf2-a599-f96d72e0ce37`

R2 로 올리지 않는다: escalate 조건 (a)(`ACCEPT_NOW` 이면서 severity CRITICAL/HIGH)가 성립하지 않는다. 유일한 finding 이 MEDIUM 이고 판정은 DEFER/REJECT 다.

### Security Reviewer

> security-reviewer unavailable, skipped (auto-fallback): 이 세션은 Agent/Task tool 호출이 금지돼 있어 `subagent_type: security-reviewer` 를 띄울 수 없다.

수동 대조로 남기는 것(게이트 신규 코드의 셸 주입·경로 축):

- 새 코드가 만드는 셸 확장 지점은 `tc_list`/`tc_scalar` 의 `sed -n "s/^$1: ..."` 하나다. `$1` 은 호출부가 리터럴(`repos` · `statuses` 등)로만 넘기고 config 파일 내용에서 오지 않는다. config 값 자체는 파이프라인의 *데이터*로만 흐르고 `eval`·`bash -c`·비인용 확장에 들어가지 않는다.
- 스테이징은 `$TMP`(`mktemp -d`) 하위에만 쓴다. 대상 경로 3종은 리터럴이며 config 값에서 파생되지 않아 경로 순회 축이 없다.
- `node "$LINTER" ... "$dir/..."` 의 인자는 전부 인용된 리터럴 경로다.

`security_skipped=true` 로 영수증에 기록한다 — 이 상태는 downstream `/mccp:pr` 를 fail-closed 로 막는다. 위 수동 대조는 그 차단을 해제하지 않는다.

### Design Review

> impeccable silent-skip: `impeccable-detect --mode implement` 가 `design_signal=false` (`skill_available=true`, reason `no-signal`). 산출물이 YAML 1 · bash 함수 1 · 텍스트 golden 9행이라 렌더링 표면이 0건이다. critique 루프·명령 라우팅·design-grounding 캡처 전부 미수행.

## santa 라운드 1~4 — m5 (2026-08-10)

수렴하지 않았다. 4라운드 전부 NAUGHTY, 흡수 6건 · 기각 5건. 명목 상한 3을 넘겨 4까지 돈 것은
지적 실질이 아직 0이 아니었기 때문이다(이 저장소는 동시 PASS 가 아니라 실질 곡선으로 종료를
판정한다 — m6 는 12라운드).

| 라운드 | A(Opus) | B(gpt-5.4) | 흡수 | 기각 |
|---|---|---|---|---|
| 1 | PASS 0건 | FAIL 2건 | 2 | 0 |
| 2 | FAIL 1건 | FAIL 2건 | 2 | 1 |
| 3 | FAIL 2건 | FAIL 2건 | 1 | 3 |
| 4 | APPROVE 0건 | FAIL 2건 | 1 | 1 |

### S1 — 흡수 6건이 전부 한 축이었다: `template-config` 파서가 두 벌인데 문법이 다르다

`verify.sh` 의 `tc_list`/`tc_scalar` 와 doc-kit `lint-docs.mjs` 의 `parseFlatYaml` 이 **같은
파일을 읽는 독립 구현 둘**이다. 이 저장소가 여러 곳에 *"파서를 두 벌 두면 그 둘이 갈라진다"* 고
적어 뒀는데, m5 는 그 상황을 만들어 놓고 갈라짐을 검사하지 않았다.

| 라운드 | 갈라진 자리 | 방향 |
|---|---|---|
| 1 | 중복 키 | verify 병합 · lint last-wins, 둘 다 무경고 |
| 1 | 블록형 리스트 | schema 유효 · verify 0건, 진단이 config 를 지목 |
| 2 | `]#c` (공백 없는 주석) | verify 읽음 · lint throw |
| 2 | `'…'` · 따옴표 안 `#` | verify `'` 같은 쓰레기 값이 통과 |
| 3 | 리스트 원소 `"…"` | lint 는 원소마다 unquote · verify 는 안 함 |
| 4 | 콜론 뒤 공백 2칸 / 0칸 | 양방향 발산 |

**매 라운드 한 건씩 나왔다.** 개별 결함이 아니라 접근의 문제다 — 문법 하위집합을 열거해 막는
방식은 열거가 끝났음을 증명할 수 없다.

### S2 — 채택한 원칙: 넓히지 말고 좁힌다

라운드 1 은 lint 쪽으로 **넓혔고**(`]` 뒤 주석 허용) 그 확장이 라운드 2 에서 양방향으로 깨졌다.
이후로는 방향을 뒤집었다 — 게이트가 읽을 수 있는 좁은 형태만 받고 나머지는 **정확한 진단으로
거부**한다. 셸로 lint 의 따옴표·대괄호 상태 기계를 세 번째로 구현하지 않는다는 판단이며,
manifest 가 `menu_codes` DB 축을 `complete: false` + `db.gap` 으로 닫은 것과 같은 처리다.

현재 받는 형태: 콜론 뒤 공백 1개 이상 · 값에 `#`·`'` 없음 · 리스트 원소에 `"` 없음 ·
scalar 의 `"` 는 값 전체를 감싸는 짝일 때만 · 흐름형 한 줄. 현 config 9개 키가 전부 이 안에 있다.

### S3 — 구조적으로 닫으려면 lint 가 파싱 결과를 내줘야 한다

열거를 끝낼 수 있는 유일한 길은 게이트가 **자기 추출값을 lint 의 추출값과 직접 대조**하는 것이다.
그런데 `lint-docs.mjs` 에는 config 덤프 모드가 없고 `parseFlatYaml` 은 내부 함수이며, doc-kit 은
**동결 자산이자 이 PRD 소유 경로 밖**이라 이 마일스톤이 손댈 수 없다. 그래서 열거식 좁히기가
현재 가용한 유일한 수단이다. doc-kit 에 `--print-config` 류가 생기면 이 축 전체가 한 번에 닫힌다.

### 기각 5건

- **A: "`pipefail` 을 제거하면 판정이 뒤집힌다"** (R3) — 가정법. 29행에 있고 그 의존성은
  `verify.sh` 주석이 이미 명시했다. A 자신도 같은 라운드 criterion 6 에서 존재를 확인했다.
- **A: "`run_template_config_gate` 가 `tc_guard` 를 안 불러 순서 의존이 취약하다"** (R3) —
  `$TMP` 는 호출마다 `mktemp -d` 이고 `EXIT` 에 `rm -rf` 가 걸린다. `[ -f "$TMP/repos.raw" ]` 가
  참이면 이 프로세스에서 `gen_report` 가 돌았다는 뜻이고, 거기서 9개 키가 전부 `tc_guard` 를 탄다.
  A 가 근거로 든 *"file could be stale"* 이 성립하지 않는다.
- **B: "`evidence_grades` ↔ `05-final-spec` §2 교차 대조가 없다"** (R3) — §2 표의 등급 열은
  `S`·`A`·`B`·`C`·`D`·`X` 뿐이고 `S-test` 같은 슬러그가 없다. 기계 대조를 하려면 정본에 없는
  매핑을 새로 만들어야 한다. m5 계획 게이트가 같은 근거로 판정해 백로그에 LOW 로 있다.
- **B: "`run_template_config_gate` 가 예시 fixture 만 검사한다"** (R2) — 실 `docs/` 문서는
  `run_lint_gate` 가 본다(0건이면 통과가 아니라 실패). 지금 0건이라 `--bootstrap` 으로 면제
  중인 것이고 그것은 m3 의 마일스톤 스코프 예외다.
- **B: "`repos` 순서 불변식이 강제되지 않는다"** (R4) — config 주석은 소속(membership)을
  규정하지 순서를 규정하지 않는다. `statuses` 만 순서를 갖고 게이트가 그것만 정렬하지 않는다.

### S4 — Reviewer A 는 5라운드 중 실결함 1건이다

m6 3라운드 + m5 4라운드 = 7라운드에서 A 의 단독 실발견은 m5 R2 의 `]#c` 1건뿐이다. m5 R4 에서는
방법론에 *"whitespace variants"* 를 테스트했다고 적고 APPROVE 를 냈는데, B 가 같은 라운드에
공백 축 발산을 실측으로 제시했다. **A 를 단독으로 쓰면 게이트가 없는 것과 같다**는 관찰이
두 마일스톤에 걸쳐 재현됐다.

라운드 4 에서 A 에게 *"PASS 는 실행한 probe 를 대야만 인정된다"* 를 명시했는데도 결과가 같았다.
프롬프트 강화로 닫히는 문제가 아닐 수 있다 — 다음 마일스톤에서는 A 를 다른 계열 모델로 바꾸는
것을 검토한다.

### 종료 판정 — 미수렴 상태로 종료 (2026-08-10, 사용자 판단)

라운드 4 도 실결함 1건을 냈으므로 **수렴이 아니다.** 그럼에도 종료한 근거는 라운드를 더 도는
기대값이 낮다는 것이다 — 흡수 6건이 전부 한 축(S1)이고, 그 축을 끝내는 유일한 길은 S3 의
구조적 해결인데 이 마일스톤이 손댈 수 없는 자산에 있다. 라운드 5 는 열거를 한 겹 더 하는 것이며
그 열거가 언제 끝나는지는 여전히 말할 수 없다.

**수용한 상태.** 게이트가 받는 형태는 — 콜론 뒤 공백 1개 이상 · 값에 주석기호와 작은따옴표 없음 ·
리스트 원소에 큰따옴표 없음 · scalar 의 큰따옴표는 값 전체를 감싸는 짝일 때만 · 흐름형 한 줄.
현 config 9개 키가 전부 이 안에 있고, 벗어나면 정확한 진단으로 거부한다.

**잔여 위험의 방향은 fail-closed 다.** 남은 것은 "lint 는 받는데 게이트가 거부하는 형태"이며,
그 반대 — 게이트는 받는데 lint 와 값이 다른 형태 — 는 라운드 1~4 가 닫았다. 거부는 시끄럽고
진단이 이유를 지목하므로, 조용히 틀린 값이 golden 에 굳는 경로가 아니다.

**구조적 해결은 백로그로.** `.claude/plans/codex-findings-backlog.md` 2026-08-10 HIGH —
doc-kit `lint-docs.mjs` 에 config 파싱 결과 출력 모드를 열어 `verify.sh` 가 자기 추출값을
lint 의 추출값과 직접 대조하게 한다. 그것이 열리면 여기 쌓은 열거식 검사 5종을 대조 1건으로
대체할 수 있다. `doc-template-kit` PRD 소관이다.

### 미해결

- receipt 2종은 `head_sha: c4243d8` 로 stale 이고 `codex_verdict=divergent` 그대로다.
  **갱신하지 않았다** — santa 가 수렴이 아니라 판단으로 끝났으므로 receipt 에 ACCEPT 를 찍으면
  기록이 사실과 어긋난다. stale 은 정직한 상태이며, 갱신은 위 구조적 해결 이후에 한다.
- 그 결과 `/mccp:pr` 은 계속 막혀 있다. `security_skipped=true` 도 별도로 남아 있다.
