DHH는 날짜를 짚었고 저는 AI에 손코딩을 넘긴 날을 모릅니다

이미지
DHH가 올해 Rails World에서 한 발표를 요약한 영상을 몇 편 봤습니다. 원본 발표를 처음부터 끝까지 본 건 아니고, 한국어로 정리해 준 유튜브 영상 네 편을 이어서 봤습니다. 발표를 남이 정리해 준 걸로 보고 대충 알았다고 넘어가는 것도, 생각해 보면 요즘 제가 코드를 대하는 방식이랑 비슷합니다. 원본을 다 읽지 않고 정리된 결과를 보고, 이상한 데가 있으면 그때 찾아봅니다. 내용이 많았는데 제일 오래 남은 건 날짜 하나였습니다. 2025년 11월 24일. 영상에 따르면 DHH는 이날을 "우리 시대의 코닥 브라우니"라고 불렀다고 합니다. Claude Opus 4.5가 나온 날입니다. 1900년에 1달러짜리 카메라가 나오면서 초상화를 그리던 화가들이 일감을 잃고 방향을 틀었던 것처럼, 그날부터 프로그래머의 일이 바뀌었다는 얘기였습니다. 그리고 기술은 비탈길처럼 매끄럽게 오르는 게 아니라 한참 평평하다가 어느 날 한 칸 뛰는 계단처럼 온다고 했습니다. 영상을 보면서 저도 모르게 제 날짜를 찾고 있었습니다. 저는 언제였지. 생각이 안 났습니다. 마지막으로 직접 친 코드 어림잡을 수 있는 건 있습니다. 2025년 9월쯤부터는 제가 코드를 직접 쓴 기억이 없습니다. DHH가 짚은 날보다 두 달쯤 앞입니다. 이걸 날짜라고 하기는 좀 어렵습니다. 9월 몇 일에 무슨 일이 있어서 그날부터 안 쓴 게 아니라, 거꾸로 짚어 올라가다 보니 그쯤부터는 기억이 비어 있다는 정도입니다. 어느 날 키보드에서 손을 뗀 게 아니라 손으로 친 마지막 줄이 언제였는지 생각해 보니 안 떠오르는 겁니다. 두 달 앞이라고 해서 제가 남들보다 빨랐다는 뜻도 아닙니다. 그때 무슨 모델을 쓰고 있었는지도 정확히 기억이 안 납니다. DHH는 특정 모델이 나온 날을 짚었는데 저는 어떤 모델 때문에 넘어왔는지를 말할 수가 없습니다. 모델이 바뀐 날은 발표가 있으니 찾아보면 나오겠지만, 제가 바뀐 날은 아무 데도 적혀 있지 않습니다. 커밋 기록을 뒤져 보면 뭔가 나올...

Claude Code 훅 12개를 4개월 돌린 결과 발화 0회 - 안 걸리는 훅의 공통점

밝은 사무실 복도에 설치된 출입 게이트 여러 대가 모두 열린 채로 서 있고 아무도 지나가지 않는 장면

사이드로 하는 모바일 게임 프로젝트가 하나 있습니다. 회사에서 AI로 설계를 밀어붙이다 두 달 만에 방법론을 접고 나서 시작한 건데(그 얘기는 지난 글에 썼습니다), 여기서는 조건을 하나 바꿔보고 싶었습니다. 설계를 건너뛰지는 않되 그 설계를 제 손으로 쓰지는 않는 것. 분석부터 테스트까지 전부 AI한테 넘기고 저는 검토만 하는 식으로 해보기로 했습니다.

219 커밋이 쌓였습니다. 설계 문서가 21개, 테스트 파일이 102개, 유니티 클라이언트 쪽에만 git이 추적하는 파일이 1,113개입니다. 게임은 돕니다. 5대5 전투가 돌아가고 가챠가 뽑히고 던전이 열리고 영웅 12종에 포트레이트까지 붙었습니다. 그동안 제가 직접 친 코드는 거의 없습니다.

그래서 잘 되고 있는 줄 알았는데, 이 글을 쓰려고 오랜만에 검토 쪽 장치들을 열어봤더니 열두 개 중에 이 레포를 보고 있는 게 하나도 없었습니다.

단계는 그대로 있었습니다

AI한테 말만 하면 알아서 다 만들어준다는 말을 요즘 자주 듣습니다. 반쯤은 맞는 말인데, 그게 자주 이제 분석이나 설계 같은 건 안 해도 된다는 말로 바뀌어서 돌아다니는 것 같습니다. 제 레포를 보면 그렇지는 않았습니다.

컴퓨터가 입력, 처리, 출력으로 도는 건 어떤 기계를 쓰든 안 바뀝니다. 진공관이든 GPU든 그 셋은 그대로입니다. 기계의 성질이 아니라 계산이라는 일 자체의 성질이라서요. 분석, 설계, 구현, 테스트도 비슷한 층에 있다고 봅니다. 뭘 만들지 모르는 상태에서 돌아가는 물건까지 가려면 그 넷을 어떤 식으로든 거쳐야 합니다. 거치는 게 사람 손이냐 모델이냐는 한 층 아래 얘기입니다.

게임 프로젝트 디렉터리를 그냥 ls 해보면 이렇게 나옵니다.

client/     design/     docs/     production/     server/     shared/     tests/     tools/

design/ 안에 gdd, balance, registry가 있고, docs/ 안에 architecture, engine-reference, handoff가 있습니다. production/ 안에는 epics, sprints, qa, sprint-status.yaml이 있습니다. 이름만 게임 업계 말로 바뀌었을 뿐, 분석이고 설계고 구현이고 테스트입니다.

design/gdd/ 밑에는 문서가 21개 있습니다. arena, battle-engine, economy, gacha, hero-system, tutorial 같은 식으로 시스템 하나에 문서 하나입니다. 이 문서들에는 규격이 있습니다. 문서마다 Overview, Player Fantasy, Detailed, Formulas, Edge Cases, Dependencies, Tuning Knobs, Acceptance Criteria 여덟 개 섹션을 갖춰야 합니다. 수식이 몇 번 수식이고, 어떤 예외 상황이 있고, 어떤 값이 밸런싱 손잡이인지가 다 적혀 있습니다.

분석도 형태가 남아 있습니다. production/ 밑에 epics, sprints, qa가 있고, sprint-status.yaml과 stage.txt가 지금 어느 단계인지를 들고 있습니다. 뭘 만들지 쪼개고 순서를 정하고 어디까지 왔는지 적어두는 일인데 이것도 없앤 적이 없습니다. 오히려 이게 없으면 AI가 세션마다 처음부터 다시 판단해서 지난주에 정한 걸 다시 바꿔버립니다. 몇 번 겪고 나서 상태 파일이 늘었습니다.

테스트도 그렇습니다. client/Assets/Tests/EditMode/ 밑에 Unit, Integration, Performance가 나뉘어 있고 파일이 102개입니다. arena_battle_determinism_test.cs, try_spend_budget_test.cs, tutorial_gate_suppression_test.cs 같은 것들입니다. 전투 결정론 검증, 재화 소비 예산 검증, 튜토리얼 게이트 억제 검증. 소프트웨어공학 교과서에 나오는 테스트 분류 그대로입니다.

없어진 단계는 없었습니다. 없어진 건 그 단계를 손으로 거치던 사람입니다. 저 21개 문서도 102개 테스트도 AI가 썼습니다. 그런데 문서가 필요하다는 사실은 하나도 안 바뀌었고 오히려 늘었습니다. 손으로 짜던 시절에는 GDD를 21개까지 안 썼습니다. 머릿속에 있으면 됐으니까요.

AI한테 맡기면서 문서가 늘어난 건 AI가 제 머릿속을 못 읽어서입니다. 예전엔 암묵적으로 들고 있던 걸 전부 파일로 꺼내놔야 세션이 바뀌어도 같은 판단이 나옵니다. 말만 하면 된다는 건 말을 안 해도 된다는 뜻이 아니라, 말을 문서로 적어두면 그다음부터 실행이 자동이라는 뜻에 가까운 것 같습니다.

제 역할

그래서 219 커밋 동안 제가 실제로 한 일은 읽고 판단하고 승인하는 거였습니다.

경제 설계가 올라오면 재화 흐름이 닫혀 있는지를 봅니다. 전투 엔진 설계가 올라오면 결정론이 어디서 무너지는지를 봅니다. 커밋이 올라오면 diff를 훑고 통과시킵니다. 손은 놀고 있는데 판단은 계속 해야 합니다. 하는 일이 직접 만드는 쪽에서 관리하는 쪽으로 넘어간 겁니다.

이 판단이 형식적인 게 아니라는 것도 몇 번 느꼈습니다. 문서에 적힌 대로 짰는데 문서 쪽이 틀려서 계획서대로 나갔으면 버그가 그대로 배포됐을 뻔한 적이 있습니다. 설계가 맞는지는 설계를 읽어야 알고, 읽는 건 아직 사람 몫입니다. 개발자가 코더에서 리뷰어로, 실행자에서 관리자로 바뀐다는 말은 제 경우엔 실제로 그렇게 됐습니다.

그런데 관리도 노동이고, 꽤 지겨운 노동입니다. AI는 하루에 커밋을 여덟 개씩 만드는데 저는 그걸 다 읽어야 합니다. 설계 문서 여덟 개 섹션이 다 채워졌는지를 매번 눈으로 봐야 하고, 자산 파일 이름 규칙이 지켜졌는지, JSON 문법이 맞는지, 하드코딩된 밸런스 숫자가 코드에 들어가지 않았는지를 봐야 합니다.

몇 주 하다 보면 이것도 자동화하면 되잖아, 하는 생각이 자연스럽게 듭니다. 그래서 훅을 깔았습니다.

걸어놓고 안심했습니다

.claude/hooks/ 밑에 검사 스크립트가 열 개 넘게 쌓였습니다.

제일 큰 건 validate-commit.sh입니다. 커밋 직전에 스테이징된 파일을 훑어서 설계 문서 섹션 누락, JSON 문법 오류, 게임플레이 코드의 하드코딩 숫자, 담당자 없는 TODO를 잡습니다. validate-assets.sh는 자산 파일 이름 규칙과 JSON 유효성을 봅니다. validate-push.sh는 보호 브랜치 푸시를 막습니다. detect-gaps.sh는 세션을 시작할 때 코드는 많은데 설계 문서가 부족한 상태를 잡습니다. 나머지는 세션 로깅과 알림이고, 그 위에 에이전트와 스킬이 잔뜩 얹혀 있습니다.

목록만 보면 꽤 그럴듯합니다. 저는 이걸 만들어놓고 안심했습니다. 제가 매번 안 봐도 기계가 대신 본다고 생각했으니까요.

열어보니

validate-commit.sh부터 열었습니다. 이 훅에는 검사가 넷 있는데 각각 이런 경로를 봅니다.

DESIGN_FILES=$(echo "$STAGED" | grep -E '^design/gdd/')
DATA_FILES=$(echo "$STAGED"  | grep -E '^assets/data/.*\.json$')
CODE_FILES=$(echo "$STAGED"  | grep -E '^src/gameplay/')
SRC_FILES=$(echo "$STAGED"   | grep -E '^src/')

이 레포에는 assets/도 src/도 없습니다. 유니티 프로젝트라 소스는 client/Assets/Scripts/MasterHeroes/ 밑에 있고 데이터도 client/Assets/ 밑에 있습니다. 혹시 몰라 전체 히스토리를 뒤져봤습니다.

$ git log --all --name-only --pretty=format: | grep -E '^(assets|src)/' | sort -u | wc -l
0

219 커밋 동안 그 경로에 파일이 커밋된 적이 한 번도 없었습니다. 네 검사 중 셋은 걸릴 기회 자체가 없었던 겁니다. 더 고약한 건, 이 훅에서 커밋을 실제로 막을 수 있는 분기가 assets/data/의 JSON 문법 검사 하나뿐인데(exit 2로 진짜 막습니다) 하필 그게 없는 경로를 보고 있었다는 겁니다. 막을 힘이 있는 코드가 한 번도 실행된 적이 없었습니다.

validate-assets.sh는 좀 더 미묘하게 빗나갔습니다.

if ! echo "$FILE_PATH" | grep -qE '(^|/)assets/'; then
    exit 0
fi

소문자 assets/입니다. 유니티는 자산 폴더 이름이 대문자 Assets입니다. grep에 -i가 없으니 client/Assets/Data/foo.json은 이 조건에 안 걸립니다. git이 추적하는 파일이 그 밑에 1,113개 있는데 자산 검증 훅은 그중 하나도 본 적이 없습니다. 대문자 A 하나 때문에요.

detect-gaps.sh는 판정 조건이 두 줄입니다.

if [ "$SRC_FILES" -gt 50 ] && [ "$DESIGN_FILES" -lt 5 ]; then
  echo "⚠️  GAP: Substantial codebase ... but sparse design docs"

SRC_FILES는 find src로 셉니다. src가 없으니 늘 0이고, 0은 50보다 크지 않으니 이 경고는 뜰 수가 없습니다. 세션을 시작할 때마다 이 스크립트가 돌면서 "=== Checking for Documentation Gaps ===" 를 찍고 아무것도 못 찾고 끝납니다. 저는 그 출력을 볼 때마다 문제가 없다는 뜻으로 읽었습니다.

validate-push.sh는 아예 대놓고 꺼져 있었습니다.

if [ -n "$MATCHED_BRANCH" ]; then
    echo "Push to protected branch '$MATCHED_BRANCH' detected." >&2
    echo "Reminder: Ensure build passes, unit tests pass, and no S1/S2 bugs exist." >&2
    # Allow the push but warn -- uncomment below to block instead:
    # echo "BLOCKED: Run tests before pushing to $CURRENT_BRANCH" >&2
    # exit 2
fi

막는 두 줄이 주석 처리돼 있고, 남은 건 빌드 통과했는지, 테스트 돌렸는지, S1/S2 버그 없는지 확인하라는 안내문입니다. 사람한테 확인하라고 말하는 문장이 사람 대신 확인해주는 장치를 대신하고 있었습니다. 저 주석을 쓴 건 이 훅을 만든 AI이고, 그걸 읽고 통과시킨 건 저입니다.

살아 있는 검사가 하나 있긴 했습니다. design/gdd/ 섹션 검사는 경로가 맞으니까 실제로 돕니다. 그게 뭘 잡았는지 궁금해서 설계 문서마다 필수 섹션이 다 있는지 직접 대조해봤습니다. 핵심 문서 넷에서 필수 섹션이 비어 있었고, 그중 하나는 여덟 개가 통째로 없었습니다. 그런데 전부 그대로 커밋돼 있었습니다. 이 검사는 경고만 하고 exit 0으로 끝나기 때문입니다.

막을 수 있는 검사는 한 번도 실행된 적이 없고, 실행되는 검사는 막지 않습니다. 이게 같은 원인에서 나온 것 같습니다. 막히면 아프니까 아픈 검사는 안전한 경로에 놓였고, 안 아픈 검사만 실제 경로에 남았습니다. 제가 일부러 그렇게 둔 건 아닌데, 아무도 안 아픈 쪽으로 흘러가면 결과는 똑같았습니다.

남의 지도

왜 경로가 안 맞나 싶어서 들어온 날짜를 찍어봤습니다.

$ git log --diff-filter=A --format='%ad %h %s' --date=short -- .claude/hooks/
2026-04-16 2ce2eaf chore: CCGS 기반 게임 개발팀 구성

$ git log --diff-filter=A --format='%ad %h' --date=short -- client/ | tail -1
2026-03-29 71154e9

client/ 스캐폴드가 3월 29일에 들어왔고 훅들은 4월 16일에 들어왔습니다. 감시 장치가 감시 대상보다 늦게 설치된 겁니다. 처음부터 안 맞았습니다. 훅을 짤 때 레포 안에는 이미 client/Assets/가 있었는데 훅은 src/와 assets/를 봤습니다.

이유는 커밋 메시지에 있었습니다. "CCGS 기반 게임 개발팀 구성". 외부 템플릿을 통째로 옮겨 온 커밋입니다. 그 템플릿은 src/와 assets/를 쓰는 레이아웃을 전제로 만들어졌고, 저는 그걸 그대로 가져와서 유니티 레포에 얹었습니다. 그 뒤로 4개월 동안 이 세 파일은 한 줄도 안 고쳐졌습니다.

이게 제일 아팠습니다. 저는 훅을 도입했다고 생각했는데 실제로 한 건 파일 복사였습니다. 도입이라면 대상에 맞춰 겨누는 일까지 들어가야 하는데 그걸 건너뛰었고, 건너뛴 걸 4개월 동안 몰랐습니다. 몰랐던 이유는 단순합니다. 훅이 조용히 통과시킬 때와 검사할 게 없어서 통과시킬 때 출력이 똑같습니다. 둘 다 아무 말도 안 합니다.

사람이 직접 하던 시절과는 여기가 다릅니다. 제가 손으로 코드 리뷰를 하다 말면 리뷰가 안 된 게 티가 납니다. 코멘트가 안 달려 있으니까요. 자동 검사는 안 하고 있어도 하고 있을 때와 겉모습이 같습니다. 침묵이 두 가지를 뜻하는데 로그에는 한 가지로만 남습니다.

블로그 레포에서도 같은 걸 겪었습니다. 커밋 훅이 정작 커밋되는 파일을 안 보고 있었던 적이 있고, 시크릿 스캔을 걸어뒀는데 AWS 키가 그냥 통과한 적도 있고, 벤치마크 게이트가 두 달 반 죽어 있던 적도 있습니다. 그때마다 그 레포의 실수라고 생각했는데, 다른 레포에서 같은 모양이 또 나오니까 이제는 실수라기보다 이렇게 일하는 방식이 기본으로 갖고 있는 실패처럼 보입니다.

CI는 더 조용하게 낡았습니다

훅 위에 CI가 있습니다. 여기도 열어봤습니다.

.github/workflows/tests.yml이 있고 EditMode 테스트를 유니티 러너로 돌리게 돼 있습니다. 그런데 트리거가 한 줄뿐입니다.

on:
  workflow_dispatch:

푸시에도 PR에도 안 돌고 손으로 눌러야만 돕니다. 언제 이렇게 바꿨나 찾아봤더니 5월 4일이었고 커밋 메시지에 이유가 적혀 있었습니다.

회사 PC GitHub repo 에 UNITY_LICENSE/EMAIL/PASSWORD secrets 미설정 + prototype 단계 (Step 9 진행 중) 라 push 시 자동 발화는 무의미한 fail. 보존은 하되 자동 트리거만 제거 — Sprint 2 + secrets 설정 후 push trigger 복구.

판단 자체는 합리적이었습니다. 라이선스 시크릿이 없으면 푸시할 때마다 빨간 X만 쌓이고, 그게 쌓이면 빨간 X를 무시하는 습관이 생깁니다. 끄는 게 맞았고 복구 조건까지 적어놨으니 나쁘지 않은 처리였습니다.

문제는 그 뒤였습니다. 5월 4일 이후로 커밋이 42개 쌓였는데 그중 8월 초 커밋 하나가 눈에 걸렸습니다.

8642d53 chore(engine): Unity 6.3 → 6.5 (6000.5.4f1) 이주 + 컴파일 블로커 수정

엔진을 올렸습니다. 그리고 tests.yml은 지금도 그대로입니다.

env:
  UNITY_VERSION: 6000.3.0f1   # Unity 6.3 LTS — update on /setup-engine upgrade

프로젝트의 ProjectVersion.txt는 6000.5.4f1인데 CI에 적힌 값은 6000.3.0f1입니다. 주석에는 엔진 업그레이드할 때 갱신하라고 친절하게 적혀 있는데 갱신이 안 됐습니다. 아무도 못 알아챈 건 그 워크플로가 안 돌기 때문입니다.

그러니 이 게이트는 두 겹으로 죽어 있었습니다. 자동으로 안 돌고, 손으로 눌러도 설치되지 않을 에디터 버전을 요구합니다. 나중에 시크릿을 채우고 트리거를 되살리는 날 저는 켜자마자 실패하는 파이프라인을 만날 겁니다. 원인은 테스트가 아니라 석 달 묵은 버전 문자열이고요.

꺼둔 게이트는 꺼진 채로 그대로 있지 않고 낡아갑니다. 모델 버전이 오르면 하네스의 일부가 무효화된다는 얘기를 인프라 쪽에서 다시 본 것 같았습니다. 대상이 바뀌면 그 대상을 보던 장치는 같이 안 바뀌고, 그 어긋남은 장치가 돌 때만 드러납니다.

테스트 실행 기록도 봤습니다. test-results/ 안 로그 중 제일 최근 게 editmode-batt-2026-05-03.xml입니다. 그 뒤 42 커밋 동안 실행한 흔적이 하나도 없습니다. 테스트 파일은 102개 그대로 있고요. 쓰여는 있는데 안 돌아갑니다.

곁다리로 하나 더 나왔습니다. .claude/settings.json 허용 목록에 Step 49 commit hash 3351fa1 기록 처럼 특정 커밋 해시가 들어간 일회용 규칙이 둘 남아 있었습니다. 그 커밋을 만드는 순간 쓸모가 없어진 항목입니다. 같은 파일에 /Users/kakaoent/... 로 시작하는 경로도 두 줄 있는데, 이 레포의 실제 경로는 /Users/jaewon.lee/...입니다. 다른 머신에서 굳은 문자열이 그대로 따라와서 아무 데도 안 걸리는 허용 규칙으로 남은 겁니다. 하나하나는 사소한데 사소한 게 안 지워지고 쌓이는 게 이 레포에서 계속 보이는 모양입니다. 설정 파일은 누가 들여다보지 않으면 줄어들지 않습니다.

순서가 거꾸로였습니다

여기까지 뒤지고 나니 뭘 잘못했는지 보였습니다. 검사기를 먼저 깔고 규칙은 나중에 정하려고 했던 겁니다.

원래는 반대일 것 같습니다. 개발을 네 단계로 끊는 건 단계마다 정해야 할 게 다르기 때문이고, 그 정하는 일이 먼저 있어야 자동 검사가 거기서 나옵니다. 분석 단계에서는 뭘 만들고 뭘 안 만드는지, 언제 끝났다고 볼지를 사람이 정해야 스코프를 벗어났다는 경고나 요구사항과 커밋을 잇는 검사가 나옵니다. 설계에서는 문서 규격과 불변식, 되돌릴 수 없는 결정의 목록이 있어야 섹션 누락 검사나 문서와 코드가 어긋났는지 보는 검사가 나옵니다. 구현에서는 코딩 규칙과 파일 이름 규칙, 데이터와 코드의 경계를 정해야 린트나 하드코딩 값 검사, 이름 규칙 검사가 의미가 있습니다. 테스트에서는 뭘 어디까지 보장하고 언제 돌릴지를 정해야 CI 트리거나 결정론 검증, 커버리지 하한을 걸 수 있습니다.

제 레포는 검사기 쪽은 꽉 차 있고 정하는 쪽은 비어 있었습니다. 자산 파일 이름 규칙을 정한 적이 없는데 이름 규칙 검사기는 있었습니다. 검사기가 틀렸다기보다, 참고할 규칙이 이 레포에 없으니 남의 규칙을 대신 들고 온 겁니다.

딱 하나만 예외였습니다. GDD 여덟 개 섹션은 제가 실제로 정한 규격이고, 그래서 그 검사만 이 레포를 보고 있었습니다. 정한 게 있는 유일한 단계와 살아 있는 유일한 검사가 정확히 겹쳤습니다. 우연은 아닐 것 같습니다.

요즘 AI한테 일을 시키는 걸 보면 이 정하는 부분이 통째로 빠져 있는 경우가 많은 것 같습니다. 빠졌다기보다 그것까지 넘긴 거죠. 규칙도 알아서 잡아달라고 하면 AI는 진짜로 잡아줍니다. 훅 727줄이 반나절 만에 나온 것도 그래서입니다. 그런데 그렇게 나온 규칙은 이 프로젝트를 위해 새로 만든 게 아니라 학습된 일반 규칙, 그러니까 남의 프로젝트 규칙입니다. 소문자와 밑줄로 파일 이름을 짓는 건 일반적으로는 맞는 규칙이고 유니티 레포에서만 틀립니다. AI는 일반을 줬고 저는 특수를 안 줬습니다.

이 부분은 넘길 수가 없는 것 같습니다. 이 프로젝트가 뭘 보장해야 하고 어디까지는 안 해도 되는지는 학습 데이터에 없습니다. AI가 더 똑똑해진다고 채워질 빈칸은 아니라고 봅니다.

관리자가 세야 하는 것

관리 쪽으로 역할이 넘어갔다는 말은 맞는데, 관리자의 일이 감시 장치를 만드는 건 아닌 것 같습니다. 만드는 건 AI가 더 빨리 합니다. 727줄짜리 훅 세트를 저는 반나절도 안 걸려 갖췄습니다.

그보다는 단계마다 기준을 정해두고, 그 기준에서 나온 장치가 최근에 뭔가를 실제로 막았는지를 세는 쪽이 관리자 일에 가까워 보입니다. 이번에 뒤지면서 떠오른 것들이 몇 가지 있었습니다.

게이트가 걸렸든 안 걸렸든 기록을 남겼으면 좋았겠다는 생각이 제일 먼저 들었습니다. 훅이 아무 말 없이 통과시킬 때와 볼 게 없어서 통과시킬 때를 구분할 수 있어야 합니다. 몇 건을 봤고 몇 건이 걸렸는지 한 줄씩 쌓아두기만 해도, 그 파일이 안 자란다는 것 자체가 신호가 됩니다.

걸린 횟수가 오래 0이면 통과가 아니라 고장으로 읽는 게 맞을 것 같습니다. 깨끗해서 안 걸리는 경우도 있겠지만, 219 커밋 동안 0이면 깨끗한 게 아닙니다. 한 달 넘게 아무것도 안 잡은 검사를 뽑아보는 데서 점검을 시작했으면 훨씬 일찍 알았을 겁니다.

감시하는 경로가 실제로 있는지도 먼저 봤어야 했습니다. grep -E '^src/' 앞에 [ -d src ] || echo "WARN: src/ 없음" 한 줄만 있었으면 4개월이 아니라 첫날 걸렸을 겁니다. 경로가 없을 때 조용히 exit 0 하면 검사를 안 한 것과 통과시킨 것이 같은 출력으로 나옵니다. 없으면 시끄럽게 실패하는 쪽이 낫습니다.

템플릿에서 가져온 하네스는 가져온 날 다시 겨눠야 했습니다. 복사는 도입이 아니었습니다. 남의 레이아웃을 전제로 만든 스크립트는 제 레포에서 문법적으로는 잘 돌면서 아무것도 안 합니다. 에러가 안 나니까 잘 도는 게 제일 위험했습니다.

다섯 번째 단계

처음에는 분석, 설계, 구현, 테스트 네 단계 위에 관리라는 다섯 번째 단계가 생겼다고 쓰려고 했습니다. AI가 아래 넷을 하고 사람이 위에서 본다고요.

레포를 뒤지고 나서는 그 그림이 좀 틀렸다고 생각합니다. 다섯 번째 단계가 생긴 게 아니라 네 단계 전부가 사람 없이도 끝까지 돌 수 있게 된 겁니다. 관리는 위에 새로 얹힌 층이 아니라 네 단계 안에 원래 있었는데, 사람이 손으로 짜는 동안에는 저절로 따라오던 일이었습니다. 코드를 직접 치면 그 코드를 읽게 됩니다. 안 치면 안 읽습니다.

그래서 AI가 다 해주니 사람은 관리만 하면 된다는 말이 좀 위험하게 들립니다. 관리는 남은 일이면서 제일 먼저 자동화하고 싶어지는 일이기도 합니다. 지겹고, 반복적이고, 눈에 성과가 안 남으니까요. 넘기기 딱 좋은 조건을 다 갖췄습니다.

제 프로젝트는 그 자동화까지 마쳤습니다. 훅 12개, 727줄, 에이전트 21종, 스킬 75개. 그중 감시를 맡은 넷이 4개월 동안 한 번도 안 걸렸습니다. 게임은 그동안 잘 돌아갔습니다. 저는 그게 제일 무섭습니다. 감시가 없어도 티가 안 났다는 얘기니까요.

고치기 전에

훅은 아직 안 고쳤습니다. 고치기 전에 궁금한 게 있어서, 죽어 있던 검사 셋의 정규식만 떼어다가 실제 경로에 손으로 돌려봤습니다. 4개월치가 한꺼번에 쏟아질 줄 알았습니다.

하드코딩된 밸런스 숫자 검사부터 했습니다. 훅에 있는 정규식 그대로 client/Assets/Scripts/ 전체에 걸었더니 1건 나왔습니다. 219 커밋에 1건입니다. 담당자 태그 없는 TODO 검사는 7건이었습니다. 솔직히 좀 김이 샜습니다. 켜뒀어도 제 판단이 달라졌을 것 같지는 않았습니다.

나머지 하나에서 걸렸습니다. 자산 파일 이름 규칙 검사는 소문자와 밑줄만 허용합니다. 이걸 client/Assets/ 에 걸었더니 이렇게 나왔습니다.

전체 추적 파일: 1113
이름 규칙 위반: 746

67%입니다. 유니티 쪽 관행은 PascalCase인데 이 규칙은 그걸 모르는 템플릿에서 왔기 때문입니다. 경로만 남의 것이었던 게 아니라 규칙도 남의 것이었습니다.

그러니 대문자 A 하나 고치고 훅을 켜면 파일 하나 저장할 때마다 경고가 쏟아질 겁니다. 경고가 쏟아지면 저는 그걸 끕니다. 확실하게 끕니다. CI에서 이미 한 번 그랬으니까요. 빨간 X가 계속 뜨니까 트리거를 수동으로 돌려놨고, 그게 석 달 뒤에 버전 문자열까지 같이 썩게 만들었습니다.

게이트가 죽는 방식이 두 가지라는 걸 여기서 봤습니다. 하나는 조용해서 죽습니다. 아무것도 안 잡는데 아무 말도 안 하니까 살아 있는 줄 압니다. 다른 하나는 시끄러워서 죽습니다. 맞는 말을 746번 하면 사람은 그걸 끕니다. 경로만 맞게 고치는 건 조용한 죽음을 시끄러운 죽음으로 바꾸는 일이라, 그것만으로는 아무것도 안 끝납니다.

그래서 순서를 바꿨습니다. 훅을 고치기 전에 이 레포의 자산 이름 규칙이 뭔지부터 정하려고 합니다. 그게 정해져야 검사가 뭘 잡을지 정해지고, 그래야 켤 수 있습니다. 남의 하네스를 가져다 쓸 때 진짜로 옮겨 와야 했던 건 스크립트가 아니라 그 스크립트가 깔고 있던 규칙이었습니다.

727줄을 만든 날의 저는 관리를 시작한 게 아니라 관리를 그만둔 것 같습니다. 그날 실제로 한 일은 파일 열두 개를 복사한 거였고, 그걸 관리 체계라고 부르는 순간 그 위를 다시 볼 이유가 없어졌습니다. AI가 네 단계를 다 밟아주는 판에서 사람 몫으로 남는 게 그 다시 보는 일 하나인 것 같은데, 저는 그것까지 넘길 수 있게 만들어놓고 넘긴 줄도 몰랐습니다.

1건과 7건은 별거 아니었는데 746건은 좀 오래 들여다보게 됩니다.

댓글

이 블로그의 인기 게시물

봉제인형 사진 한 장, ChatGPT와 Gemini의 다른 대답

구글은 서울에서 모델이 아니라 에이전트를 판다

AI 부업으로 3개월에 2달러 벌고 50달러를 썼다는 증언을 봤습니다. 그 위에 광고가 네 겹입니다