늘모자란, 개발 :: 기능 커밋은 CSS를 건드리지 않았는데 화면이 되돌아갔다

늘모자란, 개발

AI 기능을 바꾸는 배포였다. 수정한 소스는 세 파일뿐이었다. 설정 하나, AI 호출 서비스 하나, 검토 결과를 읽는 서비스 하나. 새 컨테이너는 정상 기동했고 작업 프로세스도 멀쩡했다. 실제 AI 호출까지 성공했다. 여기까지만 보면 배포는 끝난 셈이다.

그런데 화면에서 밝은 테마가 사라졌다.

처음에는 새 기능이 CSS를 건드렸는지 의심했다. 소스 차이는 그렇지 않았다. 줄바꿈 형식을 맞추고 실행 중인 컨테이너와 운영 체크아웃의 애플리케이션 파일을 비교하자, 의도한 AI 변경 세 파일 외에 화면 파일 일곱 개가 달랐다. 테마 스크립트 하나는 아예 없었고, 스타일시트와 HTML 템플릿, 다국어 스크립트는 이전 내용으로 돌아가 있었다.

원인은 기능 커밋이 아니라 빌드 기준점이었다. 이미지는 현재 운영 소스가 아니라 테마 변경이 아직 들어오지 않은 다른 저장소의 트리에서 만들어졌다. 그 위에 AI 변경은 정확히 얹혔다. 그래서 기능은 새것이었고 화면은 과거였다. 커밋 diff만 보면 깨끗했지만, 컨테이너 전체를 교체하는 순간 diff 밖의 오래된 파일까지 함께 배포됐다.

이 유형의 회귀는 일반적인 기능 테스트로 잘 잡히지 않는다. 프로세스 health는 실행 여부를 보여 주고, API smoke는 새 기능이 작동하는지 확인한다. 둘 다 이전 화면 자산이 보존됐는지는 답하지 않는다. 새 기능이 성공했다는 사실과 기존 상태가 유지됐다는 사실은 별도의 검증 대상이다.

배포 검증에는 세 기준점이 필요하다. 현재 운영 중인 정확한 소스, 검토한 변경분, 실제로 실행할 최종 산출물이다. 최종 산출물은 단순히 새 커밋과 일치해서는 부족하다. 운영 기준점에 검토된 변경만 더해졌는지 파일 수준에서 비교해야 한다. 정적 자산처럼 빌드 과정에서 조용히 사라질 수 있는 항목은 존재 여부와 참조까지 따로 확인해야 한다.

수정은 현재 운영 커밋 위에 AI 변경 세 파일만 다시 얹어 이미지를 만들고, 격리 환경에서 기능과 테마를 함께 확인한 뒤 교체하는 방식으로 끝났다. 새 컨테이너의 health, 재시작 횟수, 테마 자산과 참조, 실제 AI 호출을 다시 검사했다.

불변 이미지는 배포를 재현 가능하게 만든다. 다만 기준점이 틀리면 잘못된 과거도 아주 성실하게 재현한다. 그래서 배포 단위는 커밋 하나가 아니다. 이전 런타임에서 새 산출물로 넘어가며 달라지는 모든 파일이 배포 단위다.

2026/08/13 15:49 2026/08/13 15:49