2026-09-09
RSS 가 유효한 XML 이 아니었다 — 보이지 않는 문자 하나
- 글 53887 제목 안에 백스페이스(U+0008)가 한 글자 박혀 있었다. 브라우저로 /rss 를 열면 멀쩡해 보이고 HTTP 200 에 크기도 정상이라 오래 안 잡혔다 — 엄격한 파서만 거부한다. xmllint 가 PCDATA invalid Char value 8 로 문서 전체를 버리고, 그런 RSS 리더는 피드를 통째로 못 읽는다
- 이스케이프로는 못 막는다.  도 XML 1.0 에서는 불법이라 참조로 바꿔도 여전히 거부당한다 — 실체를 지워야 한다. escapeXml 안에서 strip 을 escape 보다 먼저 돌린다. 순서를 바꾸면 이스케이프된 문자열에 제어문자가 그대로 남아 아무 효과가 없다
- 한 건인 줄 알고 DB 만 고치려다 전수 조사부터 했다. content 8,642행에서 title 3 · excerpt 2 · content 61건. U+0008 말고 U+0014 · U+001D · U+001E 도 섞여 있었다. 전부 20년치 WordPress·네이버 이관 찌꺼기다 — 그래서 DB 세 줄 고치는 걸로 끝날 문제가 아니라 직렬화 경계에 방어를 뒀다
- 제목 3건은 그래도 따로 정리했다. 목록·검색·OG 에도 그대로 나가는 보이는 텍스트라서다. 본문 61건은 두었다 — 코드가 막고, 사람 눈에는 안 보인다
- 제어문자를 소스에 리터럴로 적으면 안 된다. 에디터에서 안 보이고 diff 에도 안 뜨며 복붙하면 조용히 사라진다. 테스트는 초록인데 실제로는 아무것도 검사하지 않는 상태가 만들어진다. 전부 String.fromCharCode(0x08) 로 만들었다 — 이 작업 하면서 세 번 밟고 나서야 규칙으로 굳혔다
- DB 만 고치고 배포를 안 했으면 prod 는 최대 한 시간 옛 응답을 계속 줬다. /rss 는 max-age 3600 이고 확인 시점 age 가 1144 로 캐시 HIT 였다. 배포가 캐시까지 같이 날린다