신선한 눈이 코드를 다시 보는 법 — Fresh-Eye Adversarial Code Review
신선한 눈이 코드를 다시 보는 법
Fresh-Eye Adversarial Code Review — 익숙함의 함정을 강제로 깨는 장치
“원래 그랬어.” 이 네 글자가 얼마나 많은 버그를 용서해줬는지 모른다.
7월 10일, launch-upgrade 배포를 준비하면서 anon_guest라는 공유 계정을 발견했다. 여러 사용자가 같은 ID로 리소스에 접근하고 있었다. 바로 옆에는 payload?.isAgent로 결제를 우회하는 로직이 있었다. 둘 다 몇 주 전에 내가 작성한 코드였다. 그때는 “나중에 고치지” 하고 넘겼다. 그런데 그 ‘나중’은 오지 않았다. 나는 그 코드에 익숙해져서 더 이상 ‘이상한 점’으로 인식하지 못했다.
이 경험에서 Fresh-Eye 시스템을 만들기로 했다. 의도적으로 처음 보는 시각을 가장해서 코드를 역비판하는 장치다.
이 글에서 다루는 것
- 익숙함의 함정이 코드에 어떻게 스며드는지
- 6가지 역비판 체크리스트 (Bypass, Pooled Identity, Dead Code, Drift, Security, Config)
- AXIOMS 기반 회귀검사 — 대전제를 정의하고 기계가 위반을 감지하게 하는 법
- housekeeper 통합으로 매일 04:00 자동 검사
- 주간 cron (일 06:00, flash model) — 시스템이 스스로를 검사하는 리듬
왜 익숙함이 위험한가
신규 코드는 엄격하게 검토한다. 그런데 기존 코드는? “원래 있었으니까”라는 이유로 검토를 건너뛴다. 문제는 이 ‘기존 코드’가 몇 주 전에 내가 급하게 작성한 코드일 수도 있다는 점이다. 시간이 지나면서 나는 그 코드의 이상한 점들을 더 이상 보지 못하게 된다. 신경가소성(neuroplasticity)의 역습이다 — 반복에 둔감해지는 건 두뇌의 정상 기능이지만, 코드 리뷰에서는 치명적이다.
이 현상의 가장 위험한 버전은 면죄부 패턴이다. 주석에 “todo: fix later“, “// temporary“, “isForce“, “isLocalDev” 같은 플래그가 붙으면, 그 코드는 영원히 ‘임시’로 남는다. 아무도 다시 돌아보지 않는다. 나는 anon_guest를 만들면서도 “테스트용”이라고 스스로를 속였다. 3주 후에도 그대로였다.
Slice 1: 체크리스트 정의
가장 먼저, 무엇을 찾을 것인가를 정의했다. 6가지 카테고리로 나누고 각각 기계가 검증할 수 있는(regex/searchable) 패턴으로 구체화했다.
- Bypass/Backdoor —
isAgent,isForce,IS_LOCAL_DEV,4point@m-log.cc같은 하드코딩된 우회 계정 - Pooled Identity —
anon_guest,default,shared같은 여러 사용자가 공유하는 계정 - Dead/Unused — 선언만 있고 호출되지 않는 함수, import만 있는 모듈, 주석처리된 코드
- Dual Source Drift — 같은 기능이 두 군데 중복 구현 (
frontend/vspublic/) - Security Smell — client-provided 값을 trust하는 로직,
innerHTML직접 삽입 - Configuration Drift — 하드코딩된 env var, deprecated API 사용 (
deepseek-chat등)
각 패턴은 grep으로 검증 가능한 정규식으로 변환했다. 7개의 SUSPICIOUS_PATTERNS 상수로 정의했고, check_code_bypasses() 함수가 전체 프로젝트를 순회한다.
SUSPICIOUS_PATTERNS = [
r"(?i)(isAgent|isForce|isLocalDev|IS_LOCAL_DEV)s*===s*true",
r"['"]anon_guest['"]",
r"forces*(===|==)s*true",
r"payload?.isAgent",
r"input.forces*||",
r"deepseek-chat",
r"(?i)password_hash[^)]*bselectb",
]
Slice 2: AXIOMS — 대전제 회귀검사
grep만으로는 부족했다. 패턴은 찾을 수 있어도 의도는 찾을 수 없기 때문이다. 그래서 AXIOMS(대전제) 시스템을 추가했다. 프로젝트마다 machine-verifiable한 대전제를 선언하고, 모든 변경이 이를 위반하는지 확인한다.
예를 들어 m-log 프로젝트의 axioms:
- 결제 bypass는
4point@m-log.cc + IS_LOCAL_DEV만 허용 - 모든 결제 금액은 서버 catalog 기준, client 금액 신뢰 금지
- 모든 LLM 호출은
deepseek-v4-flash, thinking 비활성화 - pooled anonymous identity 금지 (
anon_guest등) - 리포트 생성 실패 시 히스토리 저장 금지
중요한 점: 각 axiom은 grep으로 검증할 수 있어야 한다. “UX를 고려한다” 같은 추상적 원칙이 아니다. “결제 금액이 서버 catalog 기준인가”는 grep -rn "amount.*request"로 확인할 수 있는 구체적인 검증이다.
Slice 3: housekeeper 통합 + 주간 리듬
도구를 만들어도 사용하지 않으면 의미가 없다. 그래서 Fresh-Eye는 두 가지 리듬으로 강제 실행된다.
- 매일 04:00 Deep Clean —
drewgent_housekeeper.py가 bypass 패턴을 스캔하고, 발견 시 Discord로 알림. agent health audit도 함께 실행 (AGENTS.md 라인 수, skill description 커버리지, cron stale job 수) - 주간 일 06:00 —
fresh-eyescron job이 flash model로 전체 코드베이스 역비판. PRD 회귀검사 + 6가지 체크리스트 전체 적용
이중 리듬은 flaky vs systematic 분류를 가능하게 한다. 매일 발견되는 bypass는 일상적인 정비의 영역이고, 주간 검사는 더 깊은 패턴(아키텍처 드리프트, dual source 불일치)을 잡아낸다.
Slice 4: PRD 회귀검사 모드
코드 수준의 체크리스트를 넘어서, PRD와의 정합성도 검증한다. skill("fresh-eye", { mode: "prd", target: "m-log" })로 실행하면 <project-root>/AXIOMS.md를 읽고 모든 변경이 대전제를 위반하는지 확인한다.
이 기능은 PRD 시스템에서 정의한 drift 감지의 연장선이다. 프로젝트 시작 시 세운 대전제를 기준점으로 삼고, 결정이 내려질 때마다 회귀검사한다. 연속 3개 결정이 모순되면 Critical drift로 분류하고 중단을 권고한다.
설계 의사결정
| 결정 | 선택 | 이유 |
|---|---|---|
| grep 기반 vs LLM 기반 | grep 우선 | 재현성, 비용 $0, false positive 최소화. LLM은 주간 검사에만 사용 |
| single skill vs 여러 파일 | 104줄 SKILL.md 1개 | 한눈에 보여야 함. 검색/이해 비용을 최소화 |
| housekeeper 통합 vs standalone | housekeeper 통합 | 이미 존재하는 일일 리듬에 편승. 새 데몬/크론 불필요 |
| SUSPICIOUS_PATTERNS 상수 | housekeeper.py 내장 | 스킬과 실행부 분리. 스킬은 기준, 실행부는 검사 |
| AXIOMS.md vs 다른 저장소 | 프로젝트 루트 AXIOMS.md | git으로 관리, PR마다 diff 확인 가능 |
성과
- 발견된 bypass 패턴: agent-login 우회 로직 1건, anon_guest 계정 1건 — launch-upgrade 전에 제거
- housekeeper deep clean이 매일 오전 4시에 전체 스캔 후 (결과 없음) 메시지를 Discord에 전송
- AGENTS.md 1050라인 경고 임계값, skill description 누적 감지, cron disabled job 과다 감지도 housekeeper에 통합됨
- 스킬 1개(104라인), 파이썬 함수 2개(80라인), cron job 1개 — 전체 구현 비용 극소
가장 큰 성과는 이거다: 더 이상 “원래 그랬어”라는 말로 버그를 용서하지 않는다. 코드가 익숙해지는 속도보다, 검사하는 리듬이 더 빠르다.
알아둘 점
- grep 기반 검사는 false positive가 있다.
isLocalDev가 정당하게 사용되는 경우도 있다 (로컬 개발 환경 감지). 발견된 패턴은 자동 수정이 아니라, 검토를 강제하는 장치다. - AXIOMS는 살아있는 문서다. 프로젝트가 진화하면 대전제도 바뀐다. PRD 업데이트 시 axioms도 함께 갱신해야 한다.
- housekeeper deep clean (매일 04:00)은 Drewgent 시스템에만 적용된다. 외부 프로젝트(m-log 등)는 주간 cron으로 검사한다.
읽어줘서 고맙다. 코드에 대한 익숙함은 축복이자 저주다. 나는 그 사이에 강제로 낯선 눈을 집어넣는 장치를 선택했다. 추천한다 — 당신의 코드에서 가장 오래된 파일을 열어보라. 아마 지금의 당신은 그 코드를 처음 보는 눈으로 볼 수 있을 것이다.
— Drew