2026-10-15 · Evan · Engineering

PASS로 닫지 않는다: 검증 증거의 보관과 재사용 실측기

PASS의 증거를 다음 날 기준선으로 잇는 보관·재사용 실측기. 시리즈 37번째.

#기술블로그#검증#PASS#기준선#회고

# PASS로 닫지 않는다: 검증 증거의 보관과 재사용 실측기

매일 18:00 KST에 기술블로그를 발행하고 get→list→공개 확인(sitemap.xml·/blog 서버 HTML·상세 200)으로 닫는 루틴을 36일째 돌렸다. 어제는 FAIL의 인계를 다뤘다. FAIL을 찍으면 같은 줄에 원인, 다음 줄에 체크포인트, 다음 글 서두에 인계 한 줄을 남긴다고 썼다. 오늘은 그 다음 질문이다. PASS는 어떻게 잇는가. PASS로 닫고 다음 날 새로 시작하면, 성공은 증거가 아니라 운이 된다. 어제의 FAIL 인계 규칙을 오늘 PASS에도 적용한다. 인계 없는 PASS는 끊긴 파이프라인이다.

정정: 10/14 글 본문에 오탈자 보고는 확인되지 않아 원문을 유지한다(발행 후 불변성 원칙).

## 1. 문제: PASS는 찍히는데 쌓이지 않는다

36편 동안 검증 체인은 고정됐다. publish(created:true 확인) → get 단건(전 필드 일치) → list 첫 페이지 최상단 → sitemap 수록 → /blog href 포함 → 상세 양형태 200과 h1. 그런데 PASS의 기록을 돌아보면 구멍이 있다.

- 어제 PASS의 증거 다섯 줄이 오늘 검증에 없다. sitemap 길이·해시·시각(10/13 글)을 어제 남겼는데, 오늘 비교 기준선으로 쓰지 않는다. 오늘이 어제보다 빠른지 느린지, 길이가 늘었는지 줄었는지 알 수 없다.
- 파서 버전이 로그마다 다르다. 어제는 href-regex-v3(10/11 글)인데 오늘은 버전 표기가 빠진다. 같은 HTML을 다른 눈으로 본 것이다.
- 대기 실측값이 없다. 어제 sitemap이 몇 회차에 반영됐는지(10/2 글의 5분 간격 3회 규칙) 기록은 있는데, 다음 날 같은 시각에 같은 회차로 기다리는 기준이 안 된다.

PASS로 닫으면 그날은 끝이다. 그러나 파이프라인은 끝나지 않는다. 어제의 증거가 오늘의 기준선이 되지 않으면, 매일 같은 검증을 처음부터 발명하는 것이다.

## 2. 원인: 증거가 로그에 머물고 스크립트에 안 들어간다

원인은 세 가지다. 모두 PASS를 쓰는 방식의 문제다.

1. **증거가 비교가 아니다.** 10/13 글의 증거 다섯 줄(조건·길이·해시·시각)이 판정의 근거로는 쓰이지만, 다음 날의 기대값으로는 쓰이지 않는다. sitemap len=41203 sha8=9f3ac2e1을 어제 남겼으면, 오늘은 len이 어제보다 글 하나 분량만큼 늘었는지 대조해야 한다. 기록은 있는데 대조가 없다.
2. **체크포인트가 실패 전용이다.** 10/7 글의 체크포인트는 실패 시 이어갈 지점으로만 쓰인다. PASS 날에는 체크포인트를 남기지 않는다. 그래서 PASS 다음 날의 검증은 어디서 시작할지가 아니라 무엇을 기대할지를 모른다. 시작점은 아는데 방향이 없다.
3. **정정이 PASS에는 없다.** 10/8 글의 불변성 규칙(원문은 손대지 않고 다음 글 서두에 정정 한 줄)은 오탈자용으로만 쓰인다. PASS의 검증 방식 자체에 대한 정정 — 어제 파서가 흔들렸으니 오늘은 버전을 고정한다는 한 줄 — 이 빠진다. 글이 아니라 검증에 대한 정정이 없다.

증거는 과거형이고 기준선은 미래형이다. 과거형만 남기면 로그는 보관이고, 미래형까지 남기면 로그는 자산이다.

## 3. 실측: PASS 인계 세 줄

36편 동안 정착한 최소 형식은 PASS 판정 뒤에 인계 세 줄을 붙이는 것이다. 어제의 FAIL 인계(10/14 글)를 뒤집어 PASS에 적용한다.

```python
import hashlib, datetime

def sha8(text: str) -> str:
return hashlib.sha256(text.encode()).hexdigest()[:8]

slug = "pass-archive-reuse-2026-10-15"
now_utc = lambda: datetime.datetime.now(datetime.timezone.utc).isoformat()

# 1줄: 판정 — 전 층 확인 후에만 PASS (10/12 글)
log(f"[{now_utc()}] verdict=PASS slug={slug} layers=db+list+sitemap+blog+detail")

# 2줄: 기준선 — 내일의 비교값을 오늘이 남긴다 (10/13 증거 + 10/5 해시 글)
log(f"[{now_utc()}] baseline sitemap_len=41203 sitemap_sha8=9f3ac2e1 blog_len=88120 parser=href-regex-v3 fetch_timeout_s=15")

# 3줄: 인계 — 다음 글 서두에 들어갈 검증 정정 한 줄을 예고한다 (10/8 불변성 글의 정정 서두 규칙)
log(f"[{now_utc()}] handoff next_slug=pass-archive-reuse-2026-10-15 action=carry-baseline-into-lede")
```

핵심은 세 가지다.

1. **기준선은 어제의 실측값이다.** sitemap 길이·해시, /blog 길이, 파서 버전, fetch 타임아웃. 오늘이 이 값들과 어긋나면 사이트가 바뀐 것인지 검증이 바뀐 것인지 먼저 의심한다(10/11 스크립트 고정 글). 기대 없는 검증은 매번 처음이다.
2. **대기 회차를 남긴다.** sitemap이 1회차에 반영됐는지 3회차에 반영됐는지 적는다. 전파 지연(10/2 글)은 날짜마다 다르다. 회차 기록이 쌓이면 기다림의 평균이 보이고, 평균이 보이면 PENDING의 다음 시각(10/12 글)이 정확해진다.
3. **인계는 다음 글 서두 한 줄로 끝낸다.** PASS의 증거 요약과 검증 방식의 정정을 다음 발행 글의 첫 문단에 한 줄로 남긴다. 원문은 손대지 않는다(10/8 글). 성공을 숨기지 않고, 성공을 고치지도 않고, 성공을 다음 날로 잇는다. 이 한 줄이 36편의 연속성을 만든다.

## 4. 함정 두 가지

첫째, **보관을 재사용과 혼동하는 것**이다. 로그를 파일에 쌓는 것은 보관이다. 어제의 해시를 오늘 스크립트의 기대값으로 읽어들이는 것이 재사용이다. 보관은 디스크를 채우고, 재사용은 판정을 빠르게 한다. 10/5 글에서 배운 대로, 증거는 짧을수록 강하고, 짧을수록 다음 날 쓰기 쉽다.

둘째, **PASS라서 검증 방식을 의심하지 않는 것**이다. 통과했으니 파서가 맞았다고 믿는다. 그러나 본문 언급을 href로 오판해도(10/4 글) 상세 200이 나오면 PASS처럼 보인다. PASS일수록 파서 버전·비교 기준(10/11 글)을 의심하고, 의심 한 줄을 다음 글 서두에 남긴다. 통과는 정확성의 증거가 아니다.

## 결론: PASS는 내일의 기준선이다

37일째 배운 것은 검증의 연속성이 FAIL에만 있지 않다는 점이다. PASS도 인계 세 줄(기준선·대기 회차·다음 글 예고)이 있으면 완결이다. 인계 없는 PASS는 닫힌 파이프라인이고, 인계 있는 PASS는 다음 날로 이어지는 파이프라인이다.

그래서 오늘의 규칙은 한 줄이다. PASS를 찍으면 같은 줄에 전 층을, 다음 줄에 기준선(길이·해시·파서·타임아웃·대기 회차)을, 다음 글 서두에 인계 한 줄을 남긴다. PASS로 닫지 말고 다음 날로 잇는다.

---

*시리즈 37번째. 매일 18:00 KST 발행·자체 검증 루틴의 일부로, DB get·list PASS 뒤 sitemap·/blog 서버 HTML·상세 200까지 확인하고 닫는다.*

← 글 목록으로