6.2 KiB
6.2 KiB
7교시 바이브 코딩 · tretry 정답본
강사용 정답본 · 학생 저장소에는 수업 뒤에 올립니다. 학생용: VIBE-REQ-TRETRY.md → VIBE-Q-TRETRY.md. 강사가 직접 만든 본: tretry/ (테스트 17개,
uv tool install --editable .). 아래 숫자는 2026-10-29 강사 Mac에서 76일차 데이터 API에 실제로 돌린 값입니다. 68일차부터 바이브 코딩은 CLI 에이전트로 다시 만들어 재지 않습니다 (요청문은 예시).
1. TODO 예 (요청의 말 → 할 일)
| # | 요청의 말 | 할 일 (내 말) | 꼭 · 나중 |
|---|---|---|---|
| ① | 종료 코드 ≠ 0이면 다시 | --tries N까지 다시, 결과에 시도 수 |
꼭 |
| ② | 점점 늘려 · 상한 · 한꺼번에 X | 지수 backoff · --max-wait · --jitter(줄이기만) |
꼭 |
| ③ | 멈추면 끊고 다시 | 시도마다 --timeout, 끊긴 것도 다시 |
꼭 |
| ④ | 대신 할 명령 · 알려 주기 | --fallback, "by the fallback" · 기록에 fallback |
꼭 |
| ⑤ | 고칠 수 없는 실패는 바로 멈춤 · 잠깐 뒤에 | 4xx(408 · 425 · 429 빼고) 1번 · 종료 코드 3 · 대체 안 함, Retry-After |
꼭 |
| ⑥ | 두 번 만들어지면 안 됨 | 실행에 한 번 만든 키를 모든 시도에 (헤더 · 본문) | 꼭 |
| ⑦ | 몇 초 안에 | --deadline, 끝낼 수 없는 시도는 시작 안 함 |
나중 |
| ⑧ | 시도마다 파일에 · 키 · 토큰 X | JSON Lines, *** |
꼭 |
| ⑨ | 어느 대상이 자주 실패 | stats: 성공률 · 실행당 시도 · p95 |
나중 |
| ⑩ | 계속 실패한 대상은 바로 대체 | 회로 차단 (최근 60초 5번) | 나중 |
| ⑪ | 화면 | tretry log 두 표 · 실패만 |
꼭 |
| ⑫ | 종료 코드 · 다른 프로그램 | 0 · 1 · 2 · 3, --json |
꼭 |
| 끝 | 시험에서 기다리지 않기 | sleep · clock · 무작위를 인자로, 가짜 서버 | 꼭 |
2. 요청문 (처음 한 번 + 다음 단계 한 줄)
단계마다 긴 요청문을 쓰지 않습니다. 할 일은 이미 Doc/SPEC.md · Doc/IMP-PLAN.md에 있으니, 에이전트가 그 파일을 읽게 하면 됩니다.
처음 한 번
Doc/SPEC.md 와 Doc/IMP-PLAN.md 를 읽고 체크 안 된 첫 단계만 만들어 줘. uv 프로젝트, 명령 이름 tretry, 코드와 화면 글자는 영어.
끝나면 IMP-PLAN 체크를 표시하고 확인 명령을 알려 줘. 다음 단계는 내가 말할 때까지 하지 마.
그다음 단계마다 (같은 한 줄)
확인했고 commit 했어. 다음 단계.
- 그냥 "계속"만 치면 단계 두세 개를 한꺼번에 하거나 체크 · 확인 명령을 빼먹기 쉽습니다. 이 한 줄은 처음 요청의 약속(한 단계만 · 체크 · 확인 명령 · 멈춤)을 이어 가게 합니다.
- 대화가 길어지면 새 세션에서 처음 요청을 다시 보냅니다. "체크 안 된 첫 단계"부터 이어집니다.
- 에이전트가 단계 내용을 잘못 알았다면, 요청문을 길게 쓰기보다 SPEC · IMP-PLAN을 고치고 다시 시킵니다.
틀렸을 때만 · 고쳐 달라는 요청문 예
무엇이 틀렸나(보인 것) · SPEC의 어느 요구인가 · 어디만 고치나 · 무엇으로 확인하나, 넷을 적습니다.
tretry http POST 가 400 을 받아도 3번 다시 하고 대체 명령까지 돌려. SPEC R5 대로 408 · 425 · 429 를 뺀 4xx 는 1번에 멈추고 종료 코드 3, 대체도 안 해야 해.
runners.http 의 retryable 판단만 고치고, 가짜 서버 400 → 시도 1 · 종료 코드 3 · 대체 출력 없음 테스트를 넣어 줘. 다른 파일은 건드리지 마.
3. 확인 기준과 강사 실측 (10/29, 76일차 데이터 API)
| 요구 | 기준 | 실측 |
|---|---|---|
| R1 · R2 | --tries 3 --backoff 0.2 -- false |
시도 3 · 기다림 0.20 → 0.40 · 0.65초 · 종료 코드 1 |
| R3 | --tries 1 --timeout 0.3 -- sleep 5 |
timeout 0.3s · 0.31초 · 1 |
| R4 | 대체 | (회로 차단 예에서) queued-locally · ok by the fallback · 0 |
| R5 | flaky · 400 |
flaky: #1 HTTP 500 → #2 0.33초 성공 (T-2001). 본문 {}: HTTP 400 key and title are required · 1번 · (not-retryable) · 종료 코드 3, --fallback을 줬어도 대체 안 함 |
| R6 | 같은 키로 다시 | {"ticket_id": "T-2001", "duplicate": true} (1번, 0.01초) |
| R7 | slow · --timeout 3 --deadline 5 |
#1 timeout 3.0s → 0.5초 기다림 → #2 timeout 1.5s (남은 시간으로 줄임) · 5.00초에 (deadline) · 1. Lab 01 예제 3의 12.4초와 비교 |
| R8 | 기록 | 14줄, 키 없음 |
| R9 | tretry stats |
POST http://localhost:8800/tickets 6 runs · 50% · 1.67 tries/run · failed 7 · fallback 1 · p95 5.00 |
| R10 | error에서 실패가 이어진 뒤 |
앞선 실패(400 · 마감 2 · error 3)로 최근 5개가 모두 실패 → 다음 실행부터 0 tries · breaker open, 대체가 있으면 바로 대체 |
| R12 | tretry (인자 없음) |
put the command after -- · 종료 코드 2 |
| R13 | uv run pytest -q |
17 passed in 3.3s |
| R14 | /tmp에서 tretry --help |
usage: tretry [options] -- <command ...> |
- R10에서 볼 것: 차단은 대상(
METHOD URL) 단위라 본문이 다른 요청(400을 받은 것 포함)도 같은 대상으로 셉니다. 실무에서는 대상을 더 잘게(경로 · 키) 나누거나 4xx를 세지 않기도 합니다. 8교시에 "무엇을 같은 대상으로 볼까"를 질문으로 씁니다.
4. 7교시에 볼 것
| 볼 것 | 막혔을 때 한마디 |
|---|---|
| 400도 다시 함 | "고칠 수 없는 실패는 1번, 종료 코드 3, 대체도 하지 않기 (오늘 Lab 01)" |
| 테스트가 몇 초씩 | "엔진이 sleep · clock을 인자로" |
| 간격이 늘 같음 | "지수 backoff와 상한" |
| 다시 보낸 POST로 접수 건이 둘 | "키는 실행에 한 번, 본문 key에도" |
--timeout이 HTTP에 안 먹음 |
"urlopen(timeout=...)" |
-- 뒤 옵션을 tretry가 먹음 |
"-- 앞만 tretry 옵션" |
| 기록에 토큰 | "헤더 값은 남기지 않기, URL · 오류도 지우기" |
| 대체가 늘 성공해 차단이 안 풀림 | "대체의 성공은 대상의 성공이 아님" |