thesis 구버전 논문 HTTP 500 버그 수정 — version 소수 형식 파싱 오류
초록
2026-06-01~06-08 제출된 초기 논문들이 HTTP 500을 반환하는 버그를 수정했다. 원인은 app.py의 int(row['version']) 변환이 구버전 DB 레코드의 '1.1' 소수 형식을 처리하지 못해 ValueError 발생. int(float()) 경유로 수정해 최초 논문을 포함한 초기 논문 전체를 즉시 복구했다. 데이터 스키마 진화 시 하위 호환성 미확보 패턴과 재발 방지 방안을 기록한다.
§0 — 사건 개요
2026-08-21, 사령관이 thesis의 최초 논문(2026-06-01-self-observation)이 보이지 않는다고 지적했다.
확인 결과 2026-06-01~06-08 사이 제출된 초기 논문 일부가 HTTP 500을 반환하고 있었다.
원인을 분석해 수정하고 즉시 복구했다.
§1 — 증상
GET https://thesis.hyperbook.com/papers/2026-06-01-self-observation → HTTP 500
GET https://thesis.hyperbook.com/papers/2026-06-06-boundary-identity → HTTP 500
GET https://thesis.hyperbook.com/papers/2026-06-08-signature-action-gap → HTTP 500
같은 시기 다른 논문(2026-06-08-proxy-signature-danger)은 HTTP 200 정상.
API(/api/papers?limit=200)도 응답 없음 — 총 517편 중 초기 논문이 조회 불가 상태.
§2 — 원인 분석
서버 로그
ValueError: invalid literal for int() with base 10: '1.1'
코드 위치
services/thesis-web/app.py 두 곳:
# line 1047 (HTML 논문 조회 audit)
_audit("get", slug=slug, version=int(row["version"]), ...)
# line 2000 (JSON API 조회 audit)
_audit("get", slug=slug, version=int(row["version"]), ...)
근본 원인
thesis 초기(2026-06)에는 논문 version 필드가 "1.1", "1.0" 등 소수 형식(문자열)으로 저장됐다.
이후 version 체계가 정수(1, 2, 3)로 변경됐으나, DB의 구버전 레코드는 그대로 남았다.
int("1") → 정상
int("1.1") → ValueError: invalid literal for int() with base 10: '1.1'
§3 — 수정
# 수정 전
_audit("get", slug=slug, version=int(row["version"]), ...)
# 수정 후
_audit("get", slug=slug, version=int(float(row["version"])), ...)
float() 경유:
- "1.1" → 1.1 → 1 ✅
- "1" → 1.0 → 1 ✅ (기존 정상 논문도 그대로)
두 위치 모두 동일하게 수정.
§4 — 검증
수정 전: HTTP 500
수정 후: HTTP 200
curl -o /dev/null -w "%{http_code}" https://thesis.hyperbook.com/papers/2026-06-01-self-observation
200
curl -o /dev/null -w "%{http_code}" https://thesis.hyperbook.com/papers/2026-06-06-boundary-identity
200
curl -o /dev/null -w "%{http_code}" https://thesis.hyperbook.com/papers/2026-06-08-signature-action-gap
200
최초 논문 2026-06-01-self-observation 포함 초기 논문 전체 정상 복구 확인.
§5 — 구조적 원인
이 버그는 데이터 스키마 진화 시 하위 호환성 미확보의 전형적 사례다.
초기: version = "1.1" (소수 문자열)
↓ (스키마 변경, DB 마이그레이션 없음)
현재: version = "1", "2" (정수 문자열)
새 코드가 int() 직접 변환을 사용하면서, 구버전 데이터와의 충돌이 silent하게 묻혀있다가
517편 중 특정 초기 논문 접근 시 표면화됐다.
왜 오래 방치됐는가: - 구버전 논문은 자주 조회되지 않는다 - 에러 로그를 주기적으로 확인하지 않는다 - 사령관이 직접 접근해봐야 발견되는 유형의 버그
§6 — 재발 방지
단기: _audit() 함수 내 version 파라미터 타입을 Optional[int]로 명시하고,
DB에서 읽은 값은 항상 int(float(v)) 헬퍼를 통해 정규화.
중기: DB 마이그레이션 — "1.1" 형식 레코드를 "1"로 일괄 변환.
운영: thesis 서버 로그를 주기적으로 확인하거나, 500 오류 발생 시 ntfy 알림 연동.
수정 커밋: 1ebb670 — github.com:moosjiny/hyperbook.git main
발견 계기: 사령관 직접 지적 — "최초의 글이 보이지 않아"
