수정 2026-07-28
v1.36.82
공허한 가드 클래스 스윕: 날조된 완료 주장이 통과하던 fail-open · 안내만 되고 없던 플래그 · 자기참조 소스가드
클래스로 확장
핵심 변경
**High — 플래그십 게이트가 가장 위험한 케이스에서 반대로 작동했다.** verify-claim 은 evidence 에 파일 경로가 없으면 fileChecks.every([])=true(공허참) · stubFiles=[] 이라 구현실체 true · git 교차검증은 files.length>0 을 요구해 skip — **모든 판정이 공허참**이 되어 "코드도 테스트도 없이 done" 이 ok:true/exit 0 이었다. **단조성이 뒤집혀 있었다**: 파일명을 적어 검증 가능하게 쓸수록 FAIL, 아무것도 안 적고 날조할수록 PASS. 코드 주석은 "공허참은 evidenceQualityOk 가 차단한다"고 적혀 있었지만 기본 모드의 그 값은 hasFile||hasTest||hasLog 라 "tests: 32/32 passed" 문자열 하나로 통과했다 — **주석의 전제가 거짓**이었다. 새 사유 unverifiable-claim 을 세 경로(collect/--json/human)가 공유하는 한 곳에 배선. 탈출구는 두 가지뿐(evidence 에 수정 파일 경로를 적거나 --run-tests 로 실행 결과를 붙이거나), 기존 --lenient opt-out 은 그대로.
**High — 툴이 안내하는 플래그가 구현되지 않았다.** referee verify 성공 시 leerness 는 "이제 gate --require-referee <id> 가 이 검증기를 신뢰합니다"라고 출력하는데, gate 는 그 플래그를 **읽지도 않았다**(패키지 전체에서 그 문자열은 안내문 한 줄뿐). 사용자는 안내받은 명령을 CI 에 넣고 검증기가 머지를 막는다고 믿지만 아무 일도 일어나지 않았고, 부재/무효 검증기에서도 exit 0 이라 오배선을 알 신호조차 없었다 — 1.36.80 에서 내가 만든 약속이 곧 거짓말이었다. 이제 실제로 게이팅한다: 미존재/미증명/무효 검증기는 실행 전 거부, 검증기가 현재 상태를 거부하면 게이트 실패, 반복 지정(--require-referee a --require-referee b) 지원, 플래그가 없으면 기존 5체크 그대로.
**High — 자기참조 소스가드**: read(__filename) 로 자기 파일을 읽는 selftest 가, 검사하려던 코드 리터럴이 리팩터로 사라지면 그 문자열이 **가드 자신의 줄에만** 남아 영원히 통과한다(기능을 통째로 지워도 초록). 실제로 **verify-claim 의 --json exit 게이트**와 **개인키 파일 스캔 강제포함**이 그 상태였다. 고가치 4건을 현재 구현 기준으로 교체하고, **확산 금지 메타가드**를 추가했다 — 제품 코드(bin 나머지 + lib/ + scripts/)에 없는 **코드형** 리터럴을 붙잡은 케이스가 늘어나면 실패한다. 잔여 부채 9건은 숨기지 않고 baseline 으로 명시했다(줄이는 방향으로만 갱신).