-
동료가 PR에 "이거 그냥 부탁이잖아요" 한 줄을 달았어요AI Agent 2026. 6. 25. 09:00728x90반응형

대문자로 박아 넣고 나니까 마음이 좀 놓였어요.
에이전트한테 일을 맡기기 직전이었거든요.
프롬프트 맨 위 첫 줄에, 제가 끌어낼 수 있는 가장 단호한 표현을 다 모아서 한 줄을 적었어요.
"이 검사가 빨강이면 절대 커밋하지 마.
먼저 고쳐." 대문자에, 느낌표에, 번호까지 붙여서 999번 규칙이라고 못을 박았어요.
999면 제일 위라는 뜻이었어요.
무슨 일이 있어도 이건 어기면 안 된다는, 제 딴엔 최후의 줄이었던 거죠.
그렇게 적어두고 나니까 이제 됐다 싶었어요.
그날 밤은 별 걱정 없이 노트북을 덮었어요.그 안심은 다음 날 PR에서 깨졌어요
그게 무너진 건 다음 날 PR이었어요.
같은 변경을 동료가 슥 훑다가, 그 999 줄 옆에 코멘트를 하나 달았어요.
길지도 않았어요.
"이거 그냥 부탁이잖아요.
모델이 무시하고 커밋해도 막는 게 없는데요." 거창한 리뷰도, 따지는 말투도 아니었어요.
지나가다 본 거 한 줄 적은 정도였어요.
그런데 그 한 줄을 읽고 나서 한참을 못 넘겼어요.
맞는 말이었거든요.
프롬프트는 손목까지 붙잡아주진 않더라고요.
모델이 "네, 안 어기겠습니다" 대답하고 바로 그다음 줄에서 어겨도, 셸은 아무 일 없었다는 듯 커밋을 통과시키니까요.
저는 그냥 적어두기만 한 거였어요.
막히는 건 따로 만들어야 했고요.변명을 좀 해보고 싶긴 했어요.
"프롬프트 우선순위를 더 올리면 되죠" 같은 게 머릿속에 떠올랐거든요.
근데 그 반박을 끝까지 따라가 보니까, 전부 "모델이 잘 따라줄 거다" 위에 서 있더라고요.
대부분 따라준다는 게 위안이 안 됐어요.
한 번이라도 안 따른 그 한 번에, 빨강인 채로 커밋된 상태가 들어와 쌓이는 거니까요.
그래서 변명을 접었어요.막는 손을, 모델이 못 닿는 자리로 옮겼어요
규칙이 진짜이려면, 막는 손이 모델이 못 닿는 자리에 있어야 했어요.
그래서 그날 그 한 줄을 프롬프트에서 떼어다가, 커밋 직전에 돌아가는 작은 게이트 스크립트 안에 옮겨 적었어요.
거기서 계약서에 적힌 검사 명령들을 전부 실행하고, 하나라도 빨강이면 스크립트가exit 1로 죽게요.
0이 아닌 코드로 죽으면 pre-commit 훅이 커밋을 그냥 거부해요.
이제 모델이 "고쳤습니다" 하고 말로 우겨도 셸은 종료 코드만 봐요.다 붙이고 나서, 진짜 막히는지 일부러 시험해봤어요.
가짜 토큰 하나를 일부러 staged 해놓고 커밋 게이트를 돌렸거든요.
시크릿 스캐너가 그걸 잡고 게이트가exit 1로 죽으면서, 커밋이 거부됐어요.
같은 리허설에서 스캐너를 detect 모드로 한 번 더 돌렸더니, 한 작업 레포에서 159건, 다른 레포에서 2건이 빨강으로 주르륵 떴어요.
진짜 시크릿들이었어요.
막힌다를 말로 믿는 거랑, 빨강 159라는 숫자가 화면에 차오르는 걸 보는 건 손맛이 달랐어요.함정 하나는 처음엔 못 봤어요.
검사할 게 0개일 때요.
테스트가 한 건도 수집 안 되면 종료 코드가 5로 떨어지는데, 5는 "실패 0건"이라 무심코 통과로 셀 뻔했어요.
근데 0개면 안 돌린 거지 통과한 게 아니잖아요.
게다가 CI처럼 비대화형 환경에선 확인용 env가 없으면 위험 작업이exit 5로 abort하게 묶어뒀는데, 그것도 5라 헷갈렸어요.
그날 게이트에 if 한 줄을 더 넣어서, 그 5들을 다 빨강에 묶었어요.그런데 기계 판정만으론 부족했어요
기계가 판정하는 것만으론 부족하다는 건 며칠 전에 한 번 데여서 알았어요.
그날도 테스트는 다 초록이었거든요.
근데 습관처럼 빌드를 직접 띄워봤는데, 화면 한쪽 글자가 통째로 안 보이는 거예요.
테스트는 그 요소가 화면에 붙어 있는지까진 봐요.
근데 진짜로 눈에 그려지는지는, 거기까진 안 보더라고요.
그래서 게이트에 하나를 더 묶었어요.
모델이 만지는 코드 바깥, 호스트 쪽에서 화면을 캡처해 기준 이미지랑 픽셀 단위로 비교하는 검사요.
폰트랑 뷰포트, device pixel ratio를 전부 고정해놓고 돌렸어요.
안 고정하면 코드를 한 줄도 안 바꿔도 같은 화면이 4.49%씩 흔들리거든요.
골든이 저 혼자 떨면, 진짜 회귀가 그 노이즈에 묻혀버려요.그 픽셀 디프가 제일 무덤덤하게 일을 했어요.
per-channel로 12 미만 델타는 안티앨리어싱이라 일부러 흡수하고, 변경된 픽셀이 1%를 넘으면 HOLD를 내면서exit 2로 멈춰요.
0이면 PASS, 2면 HOLD, 크기가 안 맞으면 3으로 죽었어요.
처음엔 이 숫자들이 자꾸 헷갈렸고요.디프에 뜬 X자 무늬의 정체
한 화면 군을 레퍼런스 이미지에 픽셀 단위로 맞춰가는 수렴 루프를 돌리던 날이었어요.
디프 마스크에 X자 무늬가 떴어요.
사람 눈엔 그냥 가장자리가 흐릿한 노이즈처럼 보였어요.
안티앨리어싱이라고 넘어갈 뻔했는데, 스크립트는 그 영역을 changed로 세서 HOLD를 냈더라고요.
파보니까 노이즈가 아니었어요.
두 캡처의 대각선 그라데이션 방향이 서로 반대였어요.
그 각도를 손으로 좌표에 옮기는 과정에서 기울기 부호가 뒤집힌 거예요.
마스크의 X자는 "두 그림의 선 방향이 다르다"는 신호였어요.
고치고 나니 그 상태의 diff_ratio가 0.073788에서 0.068916으로 떨어졌고, 옆 상태도 0.036444에서 0.035898로 같이 내려갔어요.다른 사이클에선 9~11px짜리 깨끗한 가로 띠가 떴어요.
색 문제인 줄 알고 한참 색만 봤어요.
결국 자식 노드 목록을 쭉 훑고 나서야, 레퍼런스엔 있는 간격이랑 라벨 분기가 구현에선 통째로 빠진 걸 봤어요.
색이 아니라, 거기 있어야 할 구조가 없던 거죠.
마스크 무늬마다 원인이 다르다는 걸 그때서야 좀 알아챘어요.
X자는 방향이 뒤집힌 거였고, 흐릿한 건 그냥 안티앨리어싱이었고.
깔끔한 가로 띠는, 솔직히 그날은 뭔지 몰랐다가 한참 뒤에야 빠진 자식 노드인 걸 알았어요.그 수렴 루프는 한 번에 안 끝났어요.
처음엔 13개 상태 중 3개만 PASS, 10개가 HOLD였어요.
HOLD 범위가 0.027104에서 0.086223까지 벌어져 있었고요.
한 바퀴 돌고 나서 6 PASS / 7 HOLD가 됐고, 범위가 0.073788까지 좁혀졌어요.
또 한 바퀴 돌았는데 PASS 개수는 그대로 6/7인데 범위만 0.068916으로 더 좁아졌어요.
화면 크기 매칭은 내내 13개 다 PASS였고요.
숫자가 한 자리씩 내려가는 걸 보는 게 그날 일의 거의 전부였어요.
0.07이 0.06으로 떨어질 때마다 어깨가 조금씩 풀렸는데, 정작 화면은 제 눈엔 똑같아 보여서 내가 대체 뭘 고치고 있는 건지 몇 번을 의심했어요.하나를 고치면 멀쩡하던 게 깨졌어요
근데 그 수렴 루프에 생각 못 한 병목이 있었어요.
이미 PASS인 상태가 회귀 감시견이더라고요.
한 상태를 더 좋게 만들려고 공통 셸을 건드리면, 멀쩡하던 다른 PASS 상태가 깨졌어요.
전역으로 보정을 하나 만들었다가 — 라이브 스트립 오프셋 하나, 카드 하단 패딩 1px 같은 실험이었어요 — 그게 다른 PASS 행을 깨자, 같은 사이클 안에서 바로 되돌렸어요.
결국 보정을 그 상태 하나에만 국소적으로 가둬야만 앞으로 갈 수 있었어요.그 의도라는 게 또 병목이었어요.
어느 무관한 상위 변경이 화면 상단의 작은 어포던스 하나를 제목 옆 인라인으로 옮긴 적이 있어요.
본문 텍스트는 한 글자도 안 바뀌었어요.
그런데도 그 화면의 골든 테스트가 빨강이 됐고, 통과시키려면 기준 PNG를 다시 찍어야 했어요.
그것도 한 장이 아니었어요.
CI랑 macOS 두 렌더 환경에, 한국어/영어 케이스까지 곱해서 6장을 한꺼번에 재생성했어요.
갱신하고 다시 비-갱신 모드로 6개를 돌려서 전부 통과하는 걸 확인하는 게 그 슬라이스의 전부였는데, 노트엔 "이 슬라이스는 동작 커버리지를 늘리지 않는다"고 그대로 적혀 있더라고요.
행동은 1%도 안 늘렸는데 PNG 6장을 다시 찍은 거예요.종료 코드를 너무 믿었다가 데인 적도 있어요.
풀 테스트 출력을| tail로 파이프해서 끝부분만 봤거든요.
근데 화면엔 통과처럼 떴어요.
tail이 자기 일을 끝내고exit 0을 냈으니까요.
실제로는 그 안에 209개가 실패해 있었어요.
tail의 0을 테스트의 0으로 착각한 거예요.
그래서 머신 판독용 JSON으로 실패한 이름 집합을 통째로 뽑아서, 베이스라인이랑 diff를 떴어요.
회귀가 0이라는 걸 숫자로 봐야 그제야 믿겼어요.결국 둘 다 커밋 앞에서 만나요
그러고 보니 커밋이라는 한 지점에, 기계 판정이랑 화면 검증이 같이 셸의 종료 코드로 합류하게 돼 있었어요.
둘 중 하나라도 빨강이면 커밋은 못 들어가요.
모델한테 부탁하는 999 줄은 그대로 둬도 돼요.
읽고 따라주면 그건 그거대로 좋으니까요.
막는 손만 그 줄 밖으로 옮긴 거예요.아직 못 정한 건, 막은 걸 푸는 손이에요
근데 다 풀린 건 아니에요.
픽셀 디프가 자기 혼자선 "내가 일부러 화면을 바꾼 경우"랑 "실수로 망가뜨린 경우"를 구분을 못 해요.
그래서 의도한 변경도 일단 빨강으로 막히고, 누군가 기준 이미지를 손으로 갱신해줘야 다시 초록이 돼요.
그 갱신 권한을 모델한테 주면 강제가 또 헐거워지고, 사람만 쥐고 있으면 그 6장 다시 찍는 자리가 병목이 되고요.
막는 건 바깥으로 옮겼는데, 그 막은 걸 푸는 손을 어디에 둘지는 아직 못 정했어요.
다음엔 이것도 종료 코드로 정리해보려는데, 될지는 아직 모르겠어요.728x90반응형'AI Agent' 카테고리의 다른 글
15점 만점 보고서를 닫으려다, 그냥 화면을 켜봤어요 (0) 2026.06.26 줄 번호 대보라니까, 스무 개 중에 한 개도 못 대더라고요 (0) 2026.06.25 테스트 44개가 다 초록인데, 가렸어야 할 게 새고 있었어요 (0) 2026.06.24 4.3만 건을 기억하는데, 언제 무슨 일이 있었는지는 몰랐어요 (0) 2026.06.24 한 달 전에 만든 기록 폴더를 열었더니, 안에 .gitkeep 하나뿐이었어요 (0) 2026.06.23