어떤 에이전트가 리포지토리를 수정하기 전에, 실패하는 명령어를 저장하세요. 첫 번째 PR은 채팅 추측이 아닌 번들(bundle)에서 시작해야 합니다. 이 번들에는 스크립트, 두 개의 로그 파일, 그리고 기본 SHA가 포함되어 있습니다.
실패 지점부터 시작하기
당신은 리포지토리에 합류했고 티켓 내용만 들어도 급박한 분위기입니다. 누군가 점심 식사 전에 에이전트가 버그를 패치할 수 있다고 제안합니다. 당신은 이슈 텍스트를 붙여넣고 첫 번째 diff(차이점)를 승인합니다.
리뷰어는 자신의 기계에서 그 채팅 내용을 재현할 수 없습니다. 나중에 main 브랜치가 망가지더라도, 당신 역시 롤백을 방어하기 어렵습니다. 첫 시간은 해결책을 발명하는 것이 아니라 실패 자체를 증명하는 데 사용되어야 합니다.
남겨야 할 것들
당신은 작은 repro(재현) 디렉터리를 가지고 한 시간을 마무리하게 될 것입니다. 여기에는 스크립트, 두 개의 로그 파일, SHA, 그리고 메모가 들어 있습니다. 이 스크립트는 깨끗한 환경에서 두 번 실행했을 때 동일하게 실패해야 합니다.
이 시간 동안 풀 리퀘스트(pull request)를 열지 마세요. 에이전트가 그 실행 전에 파일을 작성하도록 허용하지 마세요.
리뷰어가 빠르게 찾을 수 있도록 파일 이름은 안정적으로 유지하세요. 로그 파일을 프롬프트에 붙여넣었다고 해서 이름을 바꾸지 마세요.
repro/
START_SHA
NOTE
...
1. 시작 SHA 고정하기 (Freeze the starting SHA)
리포지토리를 깨끗한 호스트의 새 디렉터리에 클론(clone)하세요. 오래된 빌드로 가득 찬 노트북 체크아웃을 재사용하지 마세요. 팀이 이미 문서화한 기본 브랜치를 체크아웃하세요.
추가 도구를 설치하기 전에 커밋 SHA를 기록하세요. 이 파일은 패치에 롤백(revert)이 필요할 때 당신의 기준점(anchor)이 됩니다. 두 번의 실행을 시작한 후에는 절대 SHA를 업데이트하지 마세요.
mkdir -p repro
git rev-parse HEAD | tee repro/START_SHA
printf '%s\n'
파일을 실제 명령이 도착할 때까지는 템플릿으로 취급하세요. 로그에 설정 단계가 언급되면, 그 단계를 먼저 배치하세요. 비밀 정보는 스크립트와 메모장에서 제외하세요.
## 3. 깨끗한 호스트에서 스크립트를 두 번 실행하기
노트북 캐시는 추적하는 버그를 숨길 수 있습니다. 대신 폐기할(throwaway) 호스트에서 두 시도를 모두 실행하세요. 이 좁은 검사에는 깨끗한 호스트만으로 충분합니다.
공개: 본 문서는 MonkeyCode의 제품 아웃리치(product outreach)의 일환으로 준비되었습니다. MonkeyCode는 무료 모델 접근과 무료 서버 옵션을 제공합니다. 해당 서버는 이 두 번의 실행을 위한 깨끗한 호스트로만 사용하세요.
로그가 일치한 후에만 무료 모델 접근을 사용하세요. 모델 이름, 할당량(quota), 또는 장치 크기를 가정하지 마세요. 이러한 세부 정보는 변경될 수 있기 때문에 여기에 명시되지 않았습니다.
접근에 의존하기 전에 최신 제품 문서를 읽으세요. 거기에 어떤 것을 저장하기 전에 실시간 제한 사항을 확인하세요. 현재의 접근은 지속적인 약속이 아니라 선택 사항으로 취급하세요.
스크립트를 한 번 실행하고 모든 출력 줄을 보관하세요. 진정한 폴백(fallback)은 테스트 실패 후 셸을 살아있게 유지합니다. 명령이 0이 아닌 값으로 종료되어도 로그는 필요합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
./repro/run.sh > repro/run-1.log 2>&1 || true
잠시 기다린 다음, 같은 스크립트를 다시 실행하세요. 두 번째 로그를 첫 번째 로그 옆에 저장하세요. 실패가 실제인지 결정하기 전에 로그들을 비교(Diff)하세요.
./repro/run.sh > repro/run-2.log 2>&1 || true
diff -u repro/run-1.log repro/run-2.log > repro/log.diff || true
로그가 의미 있는 방식으로 불일치할 때 중단하세요. 불안정한(flaky) 실패는 첫 번째 PR의 좋지 않은 대상입니다.
불일치를 티켓에 작성하고 사람에게 문의하세요. 모델에게 재시도(retries)로 플래크를 숨기라고 요청하지 마세요.
## 4. 프롬프트를 하기 전에 로그 읽기
로그는 위에서가 아니라 아래부터 읽으세요. 파일과 줄을 명시하는 첫 번째 오류를 찾으세요. 녹색 메인 빌드에서도 나타나는 경고는 무시하세요.
오류를 파일에 연결할 수 없다면, 여기서 멈추세요. 모호한 실패는 생성된 패치(patch)가 아니라 사람의 도움이 필요합니다.
tail -n 40 repro/run-2.log > repro/PROMPT_LOG
## 5. 로그가 일치할 때만 패치를 요청하기
두 로그가 일치할 때만 채팅을 여세요. 스크립트, SHA, 그리고 두 번째 로그를 첨부하세요. 이 스크립트를 통과하게 만드는 패치를 요청하세요.
코드에 대한 요청은 파일 목록을 먼저 하세요. 저장한 스크립트를 무시하는 답변은 거절하세요. 프롬프트를 짧게 유지하여 무료 모델도 답변할 수 있게 하세요.
채팅창에 붙여넣기 전에 저장된 로그를 잘라내세요. 40줄은 시작 상한선일 뿐, 측정 기준이 아닙니다. 토큰, 고객 행(customer rows), 또는 개인 URL을 절대 붙여넣지 마세요.
Base SHA: <paste repro/START_SHA>
Command: ./repro/run.sh
Failure log: <paste repro/PROMPT_LOG>
...
티켓에 그것들이 필요하다면, 비공개 러너(private runner)를 사용하세요. 답변을 결과가 아닌 실행되지 않은 제안으로 취급하세요. 여전히 적용하고 스크립트를 다시 실행해야 합니다.
## 6. 브랜치에서 적용하고 재실행하기
이미 기록한 SHA에서 브랜치를 만드세요. 각 hunk를 볼 수 있도록 짧은 패치를 수동으로 적용하세요. 새로운 종속성(dependencies)을 추가하는 패치는 적용하지 마세요.
같은 스크립트를 실행하고 세 번째 로그를 저장하세요. 두 번째 로그와 세 번째 로그를 직접 비교하세요. 이전 오류 텍스트는 세 번째 로그에서 사라져야 합니다.
git checkout -b junior/repro-fix "$(cat repro/START_SHA)"
검토된 패치를 수동으로 적용한 다음:
./repro/run.sh > repro/run-3.log 2>&1 || true
이 명령어의 다른 테스트들이 실패해서는 안 됩니다. 만약 실패한다면, 브랜치를 되돌리고 번들(bundle)을 유지하세요. 모든 hunk를 실패 로그의 한 줄에 매핑하세요.
git diff --stat "$(cat repro/START_SHA)"
만약 hunk에 이야기가 없다면, 패치가 너무 넓다는 뜻입니다. 추가 파일을 잘라내고 더 작은 패치를 요청하세요.
## 7. 생소한 사람도 재현할 수 있도록 PR 작성하기
PR은 diff를 설명할 수 있을 때만 여세요. 본문에 스크립트 경로와 기본 SHA를 넣으세요.
실행한 명령어와 비교한 로그 이름을 명시하세요. 에이전트에 대한 칭찬이 아니라 번들 검토(review)를 요청하세요.
Repro
- Base SHA: <paste>
- Script: repro/run.sh
...
## 8. 이야기가 깨지면 같은 날 롤백하기
검토 과정에서 문제가 발견되면 같은 날 롤백하세요. 영리하지만 설명할 수 없는 패치보다 깔끔한 되돌림(revert)이 더 좋습니다. 병합된 내용(merge)을 squashed했다면 팀의 롤백 규칙을 따르세요.
병합 후에는 팀에서 문서화한 롤백 경로를 사용하세요.
git revert --no-edit <병합 커밋>
되돌림(revert) 후에도 번들(bundle)은 티켓에 남겨두세요. 다음 사람이 당신의 노트북 없이도 다시 실행할 수 있도록 말입니다. PR이 닫혔다고 해서 로그를 삭제하지 마세요.
## 의사결정표 (Decision table)
푸시하기 전에 이 표를 사용하세요. 이것은 속도를 위한 점수판이 아니라 체크리스트입니다.
| 신호(Signal) | 조치(Action) |
| :--- | :--- |
| 로그 2개가 일치하고 오류가 하나 발견됨 | 작은 패치를 요청하세요 |
| ... |
표를 인쇄하여 티켓 옆에 두고 보세요. 한 줄이 중단하라고 한다면, 다시 질문하기 전에 멈추세요.
## 소리 내어 말할 때의 제한 사항 (Limits to say out loud)
이 방법은 안정적인 로그와 함께 실패하는 명령어 하나를 다룰 수 있습니다. 레이스 조건(races), 부하 테스트(load tests), 또는 하드웨어 버그는 다루지 못합니다. 일치하는 실행 2개가 희귀한 충돌(rare crash)이 사라졌음을 증명하지는 못합니다.
무료 서버는 나중에 잠들거나, 속도를 제한하거나, 사라질 수 있습니다. 그 호스트를 팀의 지속적 통합(continuous integration)이라고 부르지 마세요. 여기에 자격 증명이나 프로덕션 덤프를 저장하지 마세요.
무료 모델 접근은 매우 긴 로그를 거부할 수 있습니다. 실패한 섹션으로 잘라내어 그 조각만 보내세요. 이 글에 있는 명령어들은 실행되지 않은 예시입니다.
이것은 측정된 기준점(benchmark)이 아니라 적응하기 위한 워크플로우입니다. 타이밍, 통과율, 또는 하드웨어 주장은 여기에 속하지 않습니다.
## 누가 이것을 건너뛰어야 하는가 (Who should skip this)
팀에서 외부 코드 호스팅을 금지한다면 이 과정을 건너뛰세요. 버그를 위해 비공개 데이터셋이 필요하다면 건너뛰세요. 라이브 인시던트(live incident)로 온콜(on call) 상태라면 건너뛰세요.
다중 서비스 장애(multi-service outage)를 쫓는 시니어 엔지니어들은 다른 계획이 필요합니다. 문서화된 단위 테스트 실패가 있는 신입 사원들이 적합합니다. 멘토가 이미 패치를 가지고 있다면, 그와 페어 프로그래밍을 하세요.
## 시간을 마무리하기 (Close the hour)
첫 시간은 영웅적인 패치(hero patch)가 아니라 번들로 끝내야 합니다. SHA, 스크립트, 그리고 일치하는 로그 2개를 저장하세요.
그 증거가 존재한 후에만 패치를 요청하세요. 만약 차이점(diff)이 설명보다 앞선다면, 오늘 되돌리세요.
이미 무료 서버가 있다면, 그곳에서 두 가지 검사를 실행하세요. 프롬프트는 저장된 로그에만 연결되도록 유지하세요. 사용 가능성에 의존하기 전에 팀이 신뢰하는 문서를 확인하세요.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38