2026-07-30 아침, 20분 안에 저장소 7개에서 똑같은 한 줄을 입력했다. "검증게이트.txt를 참고해서 로컬 검증과 CI 문서를 바꿔줘." 강의안으로 써 둔 문서 하나가 기준이 됐고, 저장소마다 현실이 달라서 결과는 전부 달랐다. 그 기록을 정리한다.
0. 상황: 정책은 하나, 저장소는 여럿
AI 접두어가 붙은 프로젝트가 여러 개 돌아가고 있다. 그중 AIFid에서 먼저 정리한 검증 정책이 있었다. 강의용으로 검증게이트.txt라는 문서에 적어 둔 것이다. 내용은 이렇다.
- 검증은 로컬에서 끝낸다.
feature → devPR에는 CI를 걸지 않고 코드 리뷰만 한다. - CI는
dev → main배포 PR에서만 돈다. - 습관에 맡기지 않고
.githooks로 강제한다.pre-commit은 스테이징된 PHP를 CS Fixer로 고치고,pre-push는 대상이dev일 때만 전체 검증을 돌린다. main직접 push는 무조건 막는다.feature/*push는 빠른 반복을 위해 검증하지 않는다. 문서만 바뀐 push는 자동으로 건너뛴다. 긴급할 때만SKIP_HOOKS=1을 쓴다.
정책 자체는 이미 정해졌다. 남은 일은 이걸 다른 저장소들의 CLAUDE.md, testing.md, ci.yml, 훅에 옮기는 것이다. 저장소마다 사람이 문서를 열어 고치면 반나절이 걸린다. 그래서 같은 요청을 그대로 던졌다.
1. 요청은 한 줄이다
세션 기록에 남은 첫 입력은 거의 글자 그대로 같다.
@검증게이트.txt문서를 참고해서 로컬 검증과 ci 부분 문서들 변경해줘
입력 시각(KST)은 아래와 같다.
| 시각 | 저장소 |
|---|---|
| 09:12 | AICura |
| 09:14 | AILicet |
| 09:15 | AiCreo |
| 09:16 | AICassa |
| 09:18 | AIPicto |
| 09:18 | AITessera |
| 09:32 | AICopia (끝에 "실제 정책도 반영해줘. ci도 셀프로 돌게 변경해줘"를 붙였다) |
프롬프트에 정책 설명은 한 글자도 없다. 파일 경로 하나와 "문서 바꿔줘"가 전부다. 설명은 기준 문서가 하고, 저장소의 실제 상태를 읽는 건 에이전트의 몫이다. 같은 요청을 반복할 때 이 분업이 핵심이었다.
2. 일곱 곳에서 같은 질문이 돌아왔다
일곱 세션 모두 문서를 쓰기 전에 현재 설정을 읽고 비교했다. 그리고 거의 같은 말로 되물었다.
- AICura: 문서는 CI를
dev→main에서만 돌리라는데 실제ci.yml은dev·main양쪽 push/PR에서 돈다.pre-push훅은 브랜치를 구분하지 않고main차단 로직도 없다. 문서만 고치면 실제 동작과 어긋난다. - AICassa: 실제
ci.yml은feature/**push와devPR에도 CI가 돈다. - AIPicto: 문서에 있는
.githooks/디렉터리가 아예 없다. 문서가 전제한backoffice/·engine/구조도 없는 단일 CI4 앱이다. - AiCreo:
pre-push가 브랜치 구분 없이 항상composer ci를 돌린다. - AITessera:
ci.yml이dev로 가는 push/PR에서도 돈다.
질문의 형태도 같았다. "문서만 현재 실태에 맞게 고칠까, 정책까지 실제 설정에 반영할까."
이 질문이 이번 작업에서 제일 값진 지점이었다. 기준 문서는 AIFid 기준으로 쓴 것이라 다른 저장소에 그대로 붙이면 거짓말이 된다. "CI는 dev→main에서만 돈다"고 적어 놓고 ci.yml은 dev PR에서도 돌고 있는 상태가 되는 것이다. 에이전트가 문서를 쓰기 전에 실제 설정과 대조하지 않았다면 일곱 개의 틀린 문서가 생겼을 것이다.
답은 대부분 "문서와 실제 설정 모두 변경"이었다. AIPicto에서는 "실제 정책까지 변경 (권장하지 않음, 영향 큼)"을 골랐다가 PR이 올라간 뒤 "지금 그대로 둬"라고 멈췄다. 그 저장소는 CI 동작이 바뀌는 영향이 커서 한 템포 쉬어 간 것이다.
3. 같은 정책, 저장소마다 다른 PR 번호
문서와 훅과 ci.yml 트리거를 바꾸는 첫 PR은 모두 빨리 끝났다.
| 저장소 | 첫 PR | 이후 이어진 PR |
|---|---|---|
| AICura | #214 | #215~#218 |
| AILicet | #115 | #116~#120 |
| AICassa | #60 | #61~#64 |
| AIPicto | #143 | #144 (배포 PR) |
| AITessera | #72 | #73 (스모크 테스트 PR) |
| AiCreo | #244 | #245~#248 |
| AICopia | #87 | #88 |
표를 보면 정책 변경 PR은 하나인데, 그 뒤로 PR이 줄줄이 붙어 있다. 정책을 문서에 옮기는 일은 20분이었고, 그 정책을 실제로 돌려 보는 일이 나머지 시간을 먹었다.
4. 문서를 바꿨더니 "CI가 어디서 도는가"가 다음 질문이 됐다
PR이 머지된 직후 여러 저장소에서 거의 같은 질문이 나왔다. "ci 셀프로 도는거 적용됐어?" CI를 dev→main에서만 돌리는 건 정리됐는데, 그 CI를 GitHub 호스팅 러너가 아니라 내 Mac의 self-hosted 러너로 돌린다는 별도 작업이 아직 반영되지 않은 상태였다. AICopia는 처음부터 요청에 이 내용을 붙여서 한 번에 처리했다.
여기서부터는 저장소마다 다른 사고가 났다.
- AILicet: 러너를 설치하라는 안내에서
svc.sh를 찾을 수 없다는 보고가 왔다. 어느 디렉터리에서 실행하는지 안내에 빠져 있었다. "어느 디렉토리에 있는지 안알려줬잖아. 당연히 루트에 있을거 생각하지 않겠어?"라는 지적이 정확했다. 명령만 적고 실행 위치를 안 적으면 안내가 아니다. 이후에도launchctl로드 실패(Input/output error)가 한 번 더 있었다. - AiCreo: 공개 저장소에 self-hosted 러너를 붙이면 외부 PR이 내 Mac에서 코드를 실행할 수 있는 위험이 있다. 그래서 "안전장치 켜고 진행"을 골랐다. 문서 PR의
pre-push도 첫 시도에서composer ci가 걸렸다. 로컬 PHP가 8.2.32인데 의존성이 8.5 이상을 요구했다. 훅은 CI까지 가지 않고 로컬에서 환경 문제를 먼저 잡아낸 셈이다. - AICopia: 러너 등록을 매번 손으로 하기 번거로워서 "셀프호스트 등록하기 쉽게 스크립트로 만들어줘"를 따로 요청했다.
5. 가장 컸던 사고: 배포가 막혔다
AILicet, AICassa, AICura에서 같은 오류가 반복됐다. main에 머지하자 배포 워크플로가 11초 만에 실패했다.
The job was not started because recent account payments have failed
or your spending limit needs to be increased.
ci.yml만 self-hosted로 옮기고 deploy.yml(CD)은 GitHub 호스팅 러너에 그대로 둔 탓이었다. GitHub 결제 한도 문제로 호스팅 러너 배정이 거부되면서 배포 잡이 시작조차 못 했다. 계정 결제는 내가 풀 수 없으니 선택지는 하나였다. CD도 같은 방식으로 self-hosted로 옮기는 것이다. 세 저장소 모두 그렇게 했고, 그 결과가 위 표의 뒤쪽 PR들이다(AILicet #119, AICassa #63, AICura #217).
CI만 옮기면 절반이다. 같은 요청을 여러 저장소에 반복하면 이런 누락도 여러 번 반복된다. 첫 저장소에서 deploy.yml 문제를 잡았다면 나머지는 처음부터 한 번에 처리할 수 있었다. 실제로는 다른 저장소의 세션이 이미 시작돼 있었고, 같은 구멍에 차례로 빠졌다.
6. 정리: 반복 요청을 맡길 때 얻은 것
- 정책은 문서에, 요청은 한 줄에. 프롬프트에 정책을 풀어 쓰지 않고 파일 경로만 줬다. 일곱 세션이 같은 기준을 읽으니 결과물의 뼈대가 맞는다.
- 기준 문서는 출발점이지 정답이 아니다. 문서는 AIFid 기준이었다. 각 저장소의 실제
ci.yml과 훅을 먼저 읽고 차이를 질문으로 돌려준 덕분에, 문서와 현실이 어긋난 채로 머지되는 일을 막았다. - 파괴력이 다른 변경은 저장소마다 따로 확인한다. "문서만"과 "실제 설정까지"는 영향 범위가 다르다. 같은 질문이어도 답은 저장소마다 달랐다.
- 한 저장소에서 얻은 교훈은 즉시 나머지에 전파한다.
deploy.yml도 같이 옮겨야 한다는 사실은 세 번 겪고서야 정리됐다. 병렬로 돌리면 이 전파가 느려진다. 가능하면 한 곳을 끝까지 돌려 본 뒤에 나머지를 시작하는 편이 낫다. - 안내에는 실행 위치를 적는다.
svc.sh를 어디서 실행하는지 한 줄만 적었어도 AILicet에서 두 번의 왕복이 줄었다.
기준 문서를 퍼뜨리는 방식은 한 방향으로 끝나지 않는다. 퍼뜨리다 얻은 교훈(CD도 함께 옮길 것, 실행 위치를 적을 것)은 다시 기준 문서에 돌려놔야 다음 저장소가 같은 구멍에 빠지지 않는다.
댓글 0개