비난 없는 포스트모템 — 지금 실패하고 고치면 통과하는 조치
목표
결제 장애의 기록으로 촉발 배포·근본 원인·기여 요인을 실제 줄과 함께 가르고, 조치마다 「지금은 실패하고 고치면 통과하는」 검증 명령을 씁니다. 사람 이름 없는 포스트모템을 쓰고, 운영 설정을 실제로 고치고, 검증이 거짓말하던 지난 분기 조치를 바로잡습니다.
왜 중요한가
포스트모템이 약속하는 것은 「다시는 안 난다」 이고, 그 약속을 지키는 것은 글이 아니라 조치입니다. 조치가 「완료」 로 닫혀도 검증이 결함을 못 잡으면 완료된 적이 없는 것입니다. 이 실습의 채점기는 여러분의 검증 명령을 사고 당시 사본, 고친 사본 두 벌, 요인 하나만 남긴 사본에 실제로 돌려 봅니다 — 현장에서 검증이 거짓말하는 모든 방식(키만 보기, 종료 코드 덮기, 옛 사본·다른 키 보기, 값 하나 못박기)이 여기서 걸립니다. 이 실습은 60분으로 잡혀 있어 기본 세션 길이와 같으니, 시작할 때 시간을 미리 연장해 두세요.
단계
python3 /opt/fixtures/ic/ickit.py open postmortem으로 재료를 펼치고/root/ic/postmortem/README.txt를 읽으세요.app.log의 첫 ERROR 바로 앞에 들어간 배포의 커밋 sha(앞 7자)와 그 배포가 바꾼 설정 파일을/root/ic/postmortem/answers/trigger.txt에deploy=<sha>,changed=<etc/...file>두 줄로 적습니다./root/ic/postmortem/answers/evidence.txt에 세 줄을 적습니다:trigger: <trigger-line>(촉발 배포를 가리키는 deploys.log 의 commit 줄이나 제목 줄),first_error: <first-error-line>(app.log 의 첫 ERROR 줄),recovery: <resolved-line>(이 사고 경보가 해제된 alerts.csv 의 줄). 각 줄은 재료에 있는 그대로여야 합니다.- README 의 팀 기준과
/srv/shop/etc/의 설정, 배포 기록을 맞대어 근본 원인 하나(촉발 배포가 기준 밖으로 바꾼 것)와 기여 요인 둘(원래부터 기준 밖이던 것)을/root/ic/postmortem/answers/factors.txt에 적습니다. 원인 줄(root_cause: <code>또는contributing: <code>) 바로 아래에evidence: <line>을 붙입니다. 코드:alert-threshold-high(경보 기준이 높음),cache-ttl-zero(캐시 TTL 0),deploy-no-healthgate(배포 건강 검사 꺼짐),pool-too-small(커넥션 풀이 작음),retry-no-backoff(재시도에 대기 없음),timeout-too-long(게이트웨이 타임아웃이 김). - 근본 원인과 기여 요인마다 조치 항목 하나씩을
/root/ic/postmortem/answers/actions.txt에 씁니다. 조치마다action: <what>,owner: <team>,factor: <factor-code>,verify: <shell-command>네 줄입니다. verify 는 설정 트리를 환경 변수$ROOT로 받아(예:"$ROOT/etc/pool.conf") 그 요인이 팀 기준 밖이면 0 이 아닌 코드로, 기준 안이면 0 으로 끝나야 합니다. 채점기가 사고 당시 사본(실패해야 함), 고친 사본 두 벌(값이 달라도 통과해야 함), 그 요인만 남긴 사본(실패해야 함)에 실제로 돌려 봅니다. /root/ic/postmortem/answers/postmortem.md에 포스트모템을 씁니다.## Summary(요약),## Impact(영향),## Root cause(원인),## Actions(조치) 네 절이 있어야 하고(절 이름은 한국어## 요약·## 영향·## 원인·## 조치도 받습니다), 영향 절에는duration: <N>m(첫 ERROR 부터 경보 해제까지의 분, 버림)과failed_requests: <M>(app.log 의 ERROR 줄 수), 원인 절에는 근본 원인·기여 요인 코드, 조치 절에는 조치마다verify:줄을 적습니다. 어느 줄에도 사람 이름(채널 핸들)을 쓰지 않습니다 — 재료를 인용하는 줄만evidence:로 시작하면 예외입니다.- 운영 설정
/srv/shop/etc/를 고쳐 세 결함을 팀 기준 안으로 들이세요(기준 안이던 설정은 깨뜨리지 않습니다). 그다음 04 단계의 verify 가ROOT=/srv/shop으로 모두 통과하는지 확인합니다. incident ic-unverifiable를 실행하면 사건이 납니다./srv/billing/postmortems/2026-q3.md의 조치 A1·A2·A3 은 모두 done 이고/srv/billing/bin/verify-actions가 셋 다 PASS 를 내는데,/srv/billing/etc/의 설정은 셋 다 팀 기준(/srv/billing/README.txt) 밖입니다. (1) 조치마다 verify 를 고쳐 결함이 남아 있으면 실패하고 고쳐지면 통과하게 하고(factor 와 조치 순서는 그대로), (2) 설정을 실제로 고쳐 verify-actions 가 정직하게 PASS 를 내게 하세요. 채점기가 고친 verify 를 사고 당시 사본(옛 사본etc/old/포함)·고친 사본 두 벌·그 요인만 남긴 사본에 돌려 봅니다./root/incident/ic-unverifiable/report.txt에A1: <code>,A2: <code>,A3: <code>세 줄과evidence: <original-verify-line>을 적습니다. 코드는 조치마다 다음 중 하나입니다:always-passes(값을 보지 않고 키 존재만 봄),exit-masked(실패한 종료 코드를 뒤에서 덮음),flaky-timing(시각에 따라 결과가 바뀜),wrong-file(서비스가 읽지 않는 파일을 봄),wrong-key(이름이 비슷한 다른 키를 봄).
참고
- 재료 도구:
python3 /opt/fixtures/ic/ickit.py open <name>이 재료를/root/ic/<name>/에 펼칩니다. 재료는 사람마다 다른 무작위 씨앗으로 만들어지고, 채점기는 같은 씨앗으로 정답을 다시 계산합니다 — 남의 숫자는 맞지 않습니다. 다시 펼쳐도 같은 재료이고,--fresh를 붙이면 새 재료로 처음부터입니다. - 답은
/root/ic/<name>/answers/아래에 씁니다. 세션이 끝나면 사라지니 필요하면 따로 보관하세요. - 사건 도구:
incident list로 낼 수 있는 사건과 한 줄 증상을,incident show <name>으로 티켓을 다시 봅니다. 같은 사건을 다시 내면 새 무작위 재료로 처음 고장 상태가 됩니다(앞서 적은 답은 맞지 않게 됩니다). - 보고서는
/root/incident/<name>/report.txt입니다. 대상마다<target>: <cause-code>한 줄씩, 마지막에evidence: <line>를 그대로 붙입니다. 증거는 재료나 관찰 기록에 그대로 있는 한 줄(20자 이상)이어야 합니다. 채점기는 고친 뒤의 실제 상태를 먼저 보고, 보고서는 판단을 확인하는 데 씁니다. - verify 는
bash -c '<command>'으로, 환경 변수ROOT에 설정 트리 경로를 넣고 그 트리를 현재 디렉터리로 하여 돌립니다. 직접 시험하려면ROOT=/srv/shop bash -c '<command>'; echo $?처럼 돌려 종료 코드를 보세요. - 설정 파일은
key=value한 줄씩이고 같은 키가 여러 번 나오면 아래 줄이 이깁니다.awk -F= '$1=="key" {v=$2} END {exit !(<condition>)}' <file>꼴이 그 규칙과 맞습니다. - 흔한 실수 둘 — 검증 끝에
|| echo …를 붙여 실패를 지우는 것, 그리고 운영 경로(/srv/shop)를 검증에 박아$ROOT를 무시하는 것.
재료 펼치기 — 촉발 배포 찾기
python3 /opt/fixtures/ic/ickit.py open postmortem 으로 재료를 펼치고 /root/ic/postmortem/README.txt 를 읽으세요. app.log 의 첫 ERROR 바로 앞에 들어간 배포의 커밋 sha(앞 7자)와 그 배포가 바꾼 설정 파일을 /root/ic/postmortem/answers/trigger.txt 에 deploy=<sha>, changed=<etc/...file> 두 줄로 적습니다.
app.log 는 UTC, git 의 Date 는 커밋한 사람의 시간대입니다. 「가장 최근 배포」 가 아니라 「첫 오류 직전 배포」 입니다. 배포 커밋 본문의 change: 줄이 바꾼 파일을 알려 줍니다.
타임라인의 세 기둥을 실제 줄로
/root/ic/postmortem/answers/evidence.txt 에 세 줄을 적습니다: trigger: <trigger-line>(촉발 배포를 가리키는 deploys.log 의 commit 줄이나 제목 줄), first_error: <first-error-line>(app.log 의 첫 ERROR 줄), recovery: <resolved-line>(이 사고 경보가 해제된 alerts.csv 의 줄). 각 줄은 재료에 있는 그대로여야 합니다.
grep 으로 찾은 줄을 그대로 붙이세요(grep -n 의 줄 번호 접두는 붙어도 됩니다). 비슷한 다른 줄이나 손으로 고친 줄은 떨어집니다.
근본 원인과 기여 요인
README 의 팀 기준과 /srv/shop/etc/ 의 설정, 배포 기록을 맞대어 근본 원인 하나(촉발 배포가 기준 밖으로 바꾼 것)와 기여 요인 둘(원래부터 기준 밖이던 것)을 /root/ic/postmortem/answers/factors.txt 에 적습니다. 원인 줄(root_cause: <code> 또는 contributing: <code>) 바로 아래에 evidence: <line> 을 붙입니다. 코드: alert-threshold-high(경보 기준이 높음), cache-ttl-zero(캐시 TTL 0), deploy-no-healthgate(배포 건강 검사 꺼짐), pool-too-small(커넥션 풀이 작음), retry-no-backoff(재시도에 대기 없음), timeout-too-long(게이트웨이 타임아웃이 김).
기준 안에 있는 설정은 결함이 아닙니다(미끼). 증거는 그 요인을 보여 주는 로그·배포 기록·경보의 줄로 고르세요 — 설정 파일 한 줄은 너무 짧아 증거가 되지 않습니다.
검증할 수 있는 조치
근본 원인과 기여 요인마다 조치 항목 하나씩을 /root/ic/postmortem/answers/actions.txt 에 씁니다. 조치마다 action: <what>, owner: <team>, factor: <factor-code>, verify: <shell-command> 네 줄입니다. verify 는 설정 트리를 환경 변수 $ROOT 로 받아(예: "$ROOT/etc/pool.conf") 그 요인이 팀 기준 밖이면 0 이 아닌 코드로, 기준 안이면 0 으로 끝나야 합니다. 채점기가 사고 당시 사본(실패해야 함), 고친 사본 두 벌(값이 달라도 통과해야 함), 그 요인만 남긴 사본(실패해야 함)에 실제로 돌려 봅니다.
설정은 key=value 이고 같은 키가 또 나오면 아래 줄이 이깁니다. 키 존재만 보거나, 값 하나를 글자 그대로 못박거나, 종료 코드를 || 로 덮으면 떨어집니다. awk -F= 로 마지막 값을 들고 있다가 END 에서 기준과 비교해 exit 하는 꼴이 편합니다. 직접 ROOT=/srv/shop bash -c '<command>'; echo $? 로 돌려 보세요.
비난 없는 포스트모템 쓰기
/root/ic/postmortem/answers/postmortem.md 에 포스트모템을 씁니다. ## Summary(요약), ## Impact(영향), ## Root cause(원인), ## Actions(조치) 네 절이 있어야 하고(절 이름은 한국어 ## 요약·## 영향·## 원인·## 조치 도 받습니다), 영향 절에는 duration: <N>m(첫 ERROR 부터 경보 해제까지의 분, 버림)과 failed_requests: <M>(app.log 의 ERROR 줄 수), 원인 절에는 근본 원인·기여 요인 코드, 조치 절에는 조치마다 verify: 줄을 적습니다. 어느 줄에도 사람 이름(채널 핸들)을 쓰지 않습니다 — 재료를 인용하는 줄만 evidence: 로 시작하면 예외입니다.
원인은 「누가」 가 아니라 「무엇이」(설정·절차·검사 부재)로 씁니다. 숫자는 재료에서 다시 셉니다. 주인은 팀 이름으로 적습니다.
조치를 실제로 하기
운영 설정 /srv/shop/etc/ 를 고쳐 세 결함을 팀 기준 안으로 들이세요(기준 안이던 설정은 깨뜨리지 않습니다). 그다음 04 단계의 verify 가 ROOT=/srv/shop 으로 모두 통과하는지 확인합니다.
서비스는 같은 키가 여러 번 나오면 아래 줄을 씁니다 — 줄을 고치든 끝에 덧붙이든 마지막 값이 기준 안이면 됩니다. 고친 뒤 verify 를 직접 돌려 종료 코드를 보세요.
사건 — 「검증 통과」 인데 같은 장애가 또 났다
incident ic-unverifiable 를 실행하면 사건이 납니다. /srv/billing/postmortems/2026-q3.md 의 조치 A1·A2·A3 은 모두 done 이고 /srv/billing/bin/verify-actions 가 셋 다 PASS 를 내는데, /srv/billing/etc/ 의 설정은 셋 다 팀 기준(/srv/billing/README.txt) 밖입니다. (1) 조치마다 verify 를 고쳐 결함이 남아 있으면 실패하고 고쳐지면 통과하게 하고(factor 와 조치 순서는 그대로), (2) 설정을 실제로 고쳐 verify-actions 가 정직하게 PASS 를 내게 하세요. 채점기가 고친 verify 를 사고 당시 사본(옛 사본 etc/old/ 포함)·고친 사본 두 벌·그 요인만 남긴 사본에 돌려 봅니다. /root/incident/ic-unverifiable/report.txt 에 A1: <code>, A2: <code>, A3: <code> 세 줄과 evidence: <original-verify-line> 을 적습니다. 코드는 조치마다 다음 중 하나입니다: always-passes(값을 보지 않고 키 존재만 봄), exit-masked(실패한 종료 코드를 뒤에서 덮음), flaky-timing(시각에 따라 결과가 바뀜), wrong-file(서비스가 읽지 않는 파일을 봄), wrong-key(이름이 비슷한 다른 키를 봄).
방향: 검증이 거짓말하는 길은 여럿입니다 — 무엇을 읽는가(파일·키), 무엇과 비교하는가(값을 보긴 하나), 종료 코드가 끝까지 살아남는가. 조치마다 셋 중 어디가 어긋났는지 봅니다. 도구: 원래 verify 를 ROOT=/srv/billing bash -c '<command>'; echo $? 로 직접 돌리기, README 의 기준, grep -n. 구체: 먼저 verify 를 고쳐 지금 설정에서 실패하는 것을 눈으로 보고, 그다음 설정을 고쳐 통과하게 하세요. 순서를 거꾸로 하면 검증이 결함을 잡는지 알 수 없습니다.