Skip to content

🐛 이미지 검증: data URI 썸네일 오판과 과잉 수정 범위 수정 - #18

Closed
Kevinlee7250 wants to merge 966 commits into
latestfrom
claude/blog-automation-system-KAbtE
Closed

Kevinlee7250 wants to merge 966 commits into
latestfrom
claude/blog-automation-system-KAbtE

Conversation

@Kevinlee7250

Copy link
Copy Markdown
Owner

무엇이 문제였나

이미지 검증(#17)을 처음 돌린 결과입니다.

검사 431건 · 문제 341건
이미지 부족 282 · 링크 깨짐 227 · 관련성 의심 15

링크 깨짐 227건은 전부 오판이었습니다. 사유가 예외 없이 "URL 형식 아님"이었고, 실제 URL을 열어 보니 전부 이렇습니다.

data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIC4uLg==

이 시스템이 만드는 썸네일은 파일이 아니라 본문에 직접 박힌 인라인 SVG입니다. 죽을 수가 없는데 check_alive가 startswith("http")만 보고 죽은 링크로 처리했습니다.

스케줄 실행은 --ai 없이도 broken을 자동 수정하므로, 다음 일요일에 멀쩡한 썸네일 227장을 교체·삭제할 상태였습니다.

변경 내용

파일 변경
image_audit.py check_alive — data:image/* 는 살아있음, 그 외 data URI만 broken
_image_terms — base64 덩어리를 파일명으로 쓰지 않음 (alt만 사용)
relevance_score — data URI 썸네일은 그 글을 위해 생성된 것이므로 1.0
fix_post(post, audit, kinds) — 손댈 문제 유형을 호출 쪽에서 결정
DEFAULT_FIX_KINDS에서 insufficient 제외 + --attach-insufficient 플래그
.github/workflows/image-audit.yml 주석을 실제 동작에 맞춤
tests/test_image_audit.py 회귀 테스트 6건
HANDOFF.md 반증 표에 이 오판 기록

insufficient를 기본에서 뺀 이유

282건은 전체 431건의 65%입니다. 기본 수정 대상으로 두면 사실상 모든 게시글에 이미지를 한 장씩 밀어 넣게 되고, 이는 검증 도구가 아니라 일괄 편집입니다. 워크플로 주석은 원래도 "스케줄은 broken/missing만 고친다"고 적혀 있었는데 코드가 그와 달랐던 것이라, 코드를 주석에 맞췄습니다.

검증

462 passed in 3.06s

추가된 회귀 테스트는 data URI가 살아있음으로 판정되는지, base64가 파일명으로 새지 않는지, insufficient가 기본으로는 수정되지 않고 옵트인 시에만 수정되는지를 고정합니다.

남은 것

insufficient 282건과 suspect 15건은 판정만 되고 손대지 않은 상태로 남습니다. 실제로 이미지를 늘릴지는 CHARS_PER_IMAGE(현재 2500자당 1장) 기준이 이 블로그에 맞는지 먼저 볼 문제라 이 PR에서는 정하지 않았습니다.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RgLYqM9puPW1aqHTccbX69


Generated by Claude Code

github-actions Bot and others added 23 commits August 20, 2026 23:24
측정 결과 발행 글 431건 중 175건(40.6%)이 들어오는 내부 링크 0개였고,
최근 고아 50건은 전부 8월 발행분이었습니다. 오래된 글은 새 글이 계속
링크해 인바운드가 쌓이는데(최대 17) 새 글은 아무도 가리키지 않는 구조입니다.

⚠️ 기대치를 분명히 해둡니다: 같은 측정에서 색인 검사 20건 중 고아 10건과
링크 있는 글 10건이 똑같이 미색인이었습니다. 내부 링크를 만든다고 색인이
풀린다는 근거는 없습니다(표본이 전부 미색인이라 인과 판정 불가).
이 작업은 색인 해결책이 아니라 사이트 구조상 정당한 개선입니다.

발행된 글을 수정하므로 안전장치를 우선했습니다:
- 기본 dry-run — --apply가 있어야 실제 반영
- 고아당 링크 2개, 출처 글당 최대 3개 (본문이 링크 목록이 되는 것 방지)
- 관련성 점수 임계값 미만이면 링크하지 않음 (억지 링크 금지)
- 본문에 자연스럽게 쓸 표현이 없으면 문장을 지어내지 않고 건너뜀
- 고아보다 먼저 발행된 글만 출처로 사용
- 관련성이 같으면 인바운드가 많은 글 우선 — 크롤 경로를 잇기 위함
- 제목·기존 앵커·script/style 안에는 삽입하지 않음
  → internal_linker의 검증된 삽입 로직을 재사용 (규칙을 두 번 구현하지 않음)

테스트 13건 추가 (전체 434건 통과)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RgLYqM9puPW1aqHTccbX69
- inbound-links.yml: 주 1회(토요일 08시 KST) 자동 + 수동 실행
  · 링크 생성 전에 internal_link_audit로 고아 목록을 먼저 갱신
  · 수동 실행 기본값은 미리보기 — 발행된 글을 수정하는 작업이므로
    apply를 명시적으로 켤 때만 반영합니다 (스케줄 실행은 반영)
- 대시보드 색인 현황 위에 "내부 링크 구조" 패널
  · 고아 건수·비율, 블로그별 분포, 최근 고아 10건
  · 색인과의 인과가 확인되지 않았다는 점을 패널에 명시 —
    숫자만 보고 원인으로 단정하지 않도록
  · 미리보기 / 링크 생성 버튼 (건수 지정, 실행 전 확인)

테스트 434건 통과

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RgLYqM9puPW1aqHTccbX69
고아 40.6%는 사실로 확인됐지만, 색인과의 인과는 근거를 못 찾았습니다.
링크 있는 글 10건도 똑같이 미색인이었고 표본이 전부 미색인이라
대조군이 없어 판정 자체가 불가능합니다.

도구(inbound_linker + PR #16)는 만들되 "색인 해결책"이 아니라
사이트 구조상 개선으로 위치를 명시했습니다. 반증 표에도 추가.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RgLYqM9puPW1aqHTccbX69
기존 이미지 도구가 다루지 않던 빈틈을 채웁니다:
  fix_unlicensed_images → 저작권(화이트리스트)
  fix_duplicate_images  → 같은 이미지 중복
  image_audit(신규)     → 이미지가 없는가 / 링크가 죽었는가 / 내용과 맞는가

판정 3종과 조치:
  missing/insufficient → 관련 이미지 첨부
  broken               → 교체, 대체 못 구하면 삭제
  irrelevant           → 교체, 대체 못 구하면 삭제
  suspect              → 확정 판정 전이므로 손대지 않음

관련성은 2단계입니다. 파일명·alt를 본문 핵심어와 대조해 거르고(무료),
애매한 것만 --ai로 Claude에게 확정 판정을 받습니다. 모든 이미지를 AI로
판정하면 비용이 크고, 반대로 문자열 매칭만으로 "무관"을 확정하면
오삭제가 나기 때문입니다.

오삭제 방지를 설계 원칙으로 삼았습니다 — 판단이 서지 않으면 항상 유지:
- 네트워크 오류·5xx는 살아있는 것으로 간주 (404/410만 죽음으로 판정)
- Content-Type이 이미지가 아닐 때만 형식 오류로 판정
- AI 호출이 실패하면 "관련 있음"으로 처리
- 비교할 핵심어가 없으면 판단하지 않음
- AI 생성 썸네일은 그 글을 위해 만든 것이므로 항상 관련 있음

교체·삭제·캡션 동기화는 fix_unlicensed_images의 검증된 함수를 재사용합니다
(화이트리스트 규칙을 두 번 구현하면 반드시 어긋납니다).

- image-audit.yml: 주 1회(일요일 07시 KST) + 수동. 수동 기본값은 검사 전용.
  스케줄 실행은 AI 판정 없이 돌아 broken/missing만 고칩니다
- 대시보드 패널: 검사만 / AI 관련성 판정 / 수정 실행 버튼과 결과 표시
- 테스트 22건 추가 (전체 456건 통과)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RgLYqM9puPW1aqHTccbX69
첫 실행 결과 431건 중 broken 227건이 전부 오판이었습니다. 이 시스템이
만드는 썸네일은 <img src="data:image/svg+xml;base64,..."> 로 본문에
직접 박혀 있는데, check_alive가 startswith("http")만 보고 "URL 형식
아님"으로 죽은 링크 처리했습니다. 일요일 스케줄이 돌면 멀쩡한 썸네일
227장을 교체·삭제할 상태였습니다.

- check_alive: data:image/* 는 살아있음, 그 외 data URI만 broken
- _image_terms: data URI의 base64 덩어리를 파일명으로 쓰지 않음
- relevance_score: data URI 썸네일은 그 글을 위해 생성된 것이므로 1.0
- fix_post에 kinds 인자 추가, DEFAULT_FIX_KINDS에서 insufficient 제외
  (282건 = 전체의 65%라 기본 적용 시 사실상 전 게시글을 수정하게 됨)
  --attach-insufficient 로만 켜지고, 워크플로 주석의 기존 설명과도 일치
- 회귀 테스트 6건 추가 (총 462건 통과)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RgLYqM9puPW1aqHTccbX69
github-actions Bot added a commit that referenced this pull request Aug 24, 2026
github-actions Bot added a commit that referenced this pull request Aug 25, 2026
github-actions Bot added a commit that referenced this pull request Sep 9, 2026
github-actions Bot added a commit that referenced this pull request Sep 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants