# watermarks-remover

> AI 티를 지우는 도구를 검사 게이트 점검용으로 열었습니다. 그런데 AI를 잡으라고 만든 지표가, 사람이 쓴 제 글을 먼저 잡았습니다. 그래서 긴 글 전용으로 좁혀서만 넣었습니다(2026-09-29).

- 수치: 수확 4 → 1.5
- 사람이 보는 화면: https://aitryed.com/ko/teardowns/qa/watermarks-remover/
- 반대 언어: https://aitryed.com/en/teardowns/qa/watermarks-remover/index.md
- 저장소: https://github.com/guillaumemeyer/watermarks-remover
- 이 사이트 안내(AI용): https://aitryed.com/ko/llms.txt

---

**AI가 만든 파일에 남는 「AI가 만들었다는 흔적」을 지워 주는 도구입니다. 저는 지우려고 연 게 아니라 제 검사 장치를 점검하려고 열었습니다. 그런데 AI를 잡으라고 만든 잣대가, 사람이 쓴 제 글을 먼저 잡았습니다.**

> **[도판]** 포맷 20종을 세는 것으로는 이 물건이 안 보인다. 검산되는 층과 안 되는 층을 코드 경로부터 갈라 놓은 것이 정체다.
>
> 이 도구는 입력을 먼저 라우터에 태워 종류를 정하고, 모르는 바이트는 통과가 아니라 거부한다. 그다음 세 갈래로 갈라지는데 보이지 않는 유니코드를 지우는 결정론 층과 파일 메타데이터 층은 검산이 되고, 토큰 샘플링 워터마크를 LLM 재작성으로 공격하는 층은 스스로 검산 불가라고 규정한다. 같은 엔진이 CLI와 의존성 없는 HTTP 서비스와 코드를 담지 않는 에이전트 스킬 세 얼굴로 나온다.

## 먼저 — 「AI가 만들었다는 흔적」이 뭔가요

AI로 글이나 그림을 만들면, 결과물에 **「이건 AI가 만들었습니다」라는 표시가 몰래 들어갑니다.** 세 가지 방식이 있습니다.

| 방식 | 비유하면 |
|---|---|
| **눈에 안 보이는 글자** | 글 사이에 폭이 0인 유령 글자를 섞어 넣음 |
| **단어 고르는 습관에 심기** | 만들 때부터 특정 패턴이 나오게 확률을 살짝 비틂 |
| **파일 안에 이름표** | 사진 파일 구석에 「누가 언제 만들었다」를 적어 둠 |

이 도구는 그 셋을 찾아서 지웁니다. 만들어진 지 **11일 만에 「좋아요」가 16,619개** 붙었습니다.

## 저는 지우려고 연 게 아닙니다

오해가 없게 적어 둡니다. 제가 이걸 연 이유는 **제 사이트를 배포하기 전에 돌리는 검사 장치를 점검**하려는 것이었습니다. 두 가지가 궁금했습니다.

1. 제 검사 장치에 **새는 곳**이 있나
2. 제가 규칙으로만 적어 두고 **검사기는 안 만든 항목**이 하나 있는데, 그걸 기계가 잴 수 있나

결론부터 말하면 **도구는 전면 기각**이고, 궁금증 두 개 중 하나는 풀렸고, **예상 못 한 게 하나 나왔습니다.**

## 잘 만든 부분 — 「모를 때 어떻게 하는가」가 좋았습니다

이 도구에서 값나가는 부분은 지우는 코드가 아니라 **모르는 상황을 다루는 태도**였습니다. 넷을 적어 둡니다.

**하나 — 모르는 파일은 건드리지 않고 죽습니다.** 예전엔 정체를 모르면 「일단 글이겠지」 하고 처리했습니다. 지금은 **아무것도 안 쓰고 오류를 내며 종료**합니다. 잘못 건드려서 파일을 망가뜨리느니 멈추는 쪽을 고른 것입니다.

**둘 — 같은 글자라도 앞뒤를 보고 다르게 처리합니다.** 유령 글자 중에는 **정상적으로 쓰이는 것**도 있습니다. 이모지를 이어 붙일 때 쓰는 글자가 그렇습니다. 그래서 「이 글자는 무조건 삭제」가 아니라 <strong>「이모지 사이에 있으면 살린다」</strong>처럼 자리를 봅니다.

특히 인상적인 주석이 하나 있었습니다 — **「분류만 보고 지우면 갓 만들어진 진짜 글자를 파괴한다.」** 실제로 그 사고를 겪고 고친 흔적이 남아 있었습니다.

**셋 — 지운 뒤에 다시 검사합니다.** 「지웠다」로 끝내지 않고 **결과물을 다시 검사기에 넣어 봅니다.** 그래서 「깨끗해짐」과 <strong>「지웠는데 아직 남아 있음」</strong>이 다른 결과로 나옵니다.

**넷 — 자기 검사 결과를 스스로 못 믿습니다.** 발견한 것을 **네 등급**으로 나누고, 그중 제일 거친 검사 방법은 **스스로 최하 등급**으로 내립니다. 주석에 이유가 적혀 있습니다 — **「검사기가 걸었다는 건 신호이지 판정이 아니다.」**

## 제 자료에 돌려 봤더니 — 잡을 게 0건이었습니다

여기서 기각이 확정됐습니다. 이 도구의 검사기를 그대로 가져와 **제 사이트 전량에 돌렸습니다.**

| 무엇을 쟀나 | 결과 |
|---|---|
| 글 196편 + 완성된 웹페이지 238장 (6.1MB) | **0건** |
| 청소 기능을 돌려 보고 전후 비교 | **196편 전부 한 글자도 안 바뀜** |
| 발행한 이미지 14장 | **14장 전부 이름표 없음** |

즉 **제 자료에는 애초에 지울 게 없었습니다.** 도구가 나쁜 게 아니라 **제게 해당되는 문제가 아니었던 것**입니다.

→ 배운 것: **검출 도구를 들이기 전에 내 자료에 먼저 돌려 봐야 합니다.** 좋다고 들여놨는데 잡을 게 0건이면, 그건 그냥 돌아가는 비용만 내는 장치입니다.

## 그런데 탐났던 잣대 하나를 제 글에 돌렸더니

이 편의 제목이 되는 자리입니다.

이 도구에는 「AI 냄새」를 점수로 매기는 기능이 따로 붙어 있습니다. 세 가지를 봅니다. 그중 제가 탐냈던 게 <strong>「문장 길이가 얼마나 들쭉날쭉한가」</strong>였습니다.

원리는 이렇습니다. **사람이 쓴 글은 문장 길이가 제멋대로**입니다. 세 글자짜리 문장 다음에 마흔 글자짜리가 오기도 합니다. **AI가 쓴 글은 길이가 고르게 정돈되는 경향**이 있습니다.

제가 이걸 탐낸 이유는, 제 글쓰기 규칙에 「문장 리듬을 단조롭게 만들지 말 것」이 **규칙으로만 있고 검사기가 없었기** 때문입니다.

그래서 제 글에 돌려 봤습니다. **사람이 쓴 제 글이 잡혔습니다.**

이게 도구가 고장 난 게 아닙니다. **문장 길이가 고르다는 것과 AI가 썼다는 것은 같은 게 아닌데**, 이 잣대는 앞의 것만 잽니다. 정돈해서 쓴 사람 글은 그대로 걸립니다.

→ **잣대가 재는 것과, 그 잣대로 판정하려는 것이 같은지 먼저 봐야 합니다.**

## 그래서 반쪽만 가져왔습니다

「문장 리듬」 항목은 **가져왔는데 조건을 붙였습니다.**

- **긴 글에만 씁니다.** 문장이 몇 개 안 되면 들쭉날쭉을 잴 수가 없습니다
- **짧은 글용 기준은 안 만듭니다** — 제 짧은 글 표본으로 다시 재 보기 전까지는
- **「AI가 썼나」를 판정하는 데 안 씁니다.** 제 글이 단조로워졌나 보는 데만 씁니다

**(2026-09 점검)** 이 반쪽도 점검 때는 만들지 않은 상태였습니다. 문장 리듬을 재는 검사기가 제 쪽에 없었습니다.

**(2026-09-29) 이제 넣었습니다.** 사이트를 배포하기 전에 도는 검사 줄에 «문장 리듬» 검사를 하나 더 세웠습니다. 긴 글의 문장 길이가 너무 고르면 배포가 멈춥니다. 위의 세 조건은 그대로 지켰습니다.

| 조건 | 이렇게 정했습니다 |
|---|---|
| 긴 글에만 | 문장이 20개 이상인 것만 잽니다 |
| 쉬운 설명과 자세한 기록 | 한 편 안에서도 따로 잽니다 — 쓴 때도 말투도 달라서 |
| 멈추는 선 | 들쭉날쭉한 정도가 0.35 아래 (8월에 쓴 선 그대로) |

처음 돌리자마자 두 편이 걸렸습니다. 둘 다 **쉬운 설명** 부분이었습니다. 쉽게 쓰려고 문장을 짧게 끊다 보니, 박자가 똑·똑·똑·똑 고르게 늘어선 것입니다. 걸린 문단만 내용은 그대로 두고, 이어지는 두세 문장을 한 문장으로 묶어 고쳤습니다.

그리고 8월에 쓴 계산기는 남아 있지 않았습니다. 새로 만든 계산기로 8월 글에 다시 돌려 보니 선 아래로 떨어지는 건 이번에도 짧은 페이지 두 편뿐이었습니다. 다만 점수 자체는 8월 숫자와 다르게 나옵니다 — 문장을 어디서 자르느냐에 따라 숫자가 흔들리기 때문입니다.

## 진짜 수확은 제 코드의 결함 하나였습니다

이 조사의 실제 산출은 남의 기법이 아니라 **제 규칙 위반 한 건**이었습니다.

제 전역 규칙 첫 줄이 이렇습니다 — **「애매하거나 실패하면 안 하는 쪽이 기본값.」** 그리고 제 배포 검사 장치의 설명 주석에도 자기가 그렇게 동작한다고 적혀 있습니다.

그런데 **실제 코드는 반대**였습니다.

| | 적혀 있던 것 | 실제 동작 |
|---|---|---|
| 모르는 종류의 파일을 만나면 | 멈춘다 | **그냥 통과시킨다** |

검사할 파일을 고를 때 **「아는 확장자만」** 골랐습니다. 모르는 확장자는 검사 대상에서 조용히 빠집니다.

지금 당장 새는 건 0건입니다. 그런데 **새로운 종류의 파일이 결과물에 하나 생기는 순간, 경고 한 줄 없이 무검사로 통과**합니다. 그리고 그건 **아무 화면에도 안 나타납니다.**

**(2026-09-28) 고쳤습니다.** 점검해 보니 그때까지도 배포 검사는 아는 확장자 여덟 가지만 읽고 나머지는 건너뛰고 있었습니다. 9월에 AI용 마크다운 판 226장이 새로 생겼을 때 검사를 탄 것도, 마크다운이 마침 처음부터 목록에 있던 운이었습니다. 이제는 **읽을 목록에도, 건너뛸 목록(그림 두 종류·빈 파일)에도 없는 파일이 나오면 배포가 멈춥니다.** 모르는 확장자 파일 하나를 일부러 넣고 배포를 돌려, 올리기 전에 멈추는 것까지 확인했습니다.

## 덤 — 제 수집기가 원본이 아니라 복제본을 물어 왔습니다

마지막으로 하나 더 나왔습니다.

제가 만든 자동 수집기가 후보 목록에 이 도구를 올렸는데, **원본이 아니라 복제본**이었습니다.

| | 원본 | 복제본 |
|---|---|---|
| 만든 날 | 8월 11일 | **8월 19일** (8일 뒤) |
| 좋아요 | 16,619 | 929 (**3일 만에**) |
| 설명문 | 1,120줄 | 1,063줄 중 **1,058줄이 원본과 똑같음** |

복제본인데 **「복제본」 표시가 안 붙어 있었습니다.** 원본을 그대로 베껴서 새로 올린 것이라 시스템상으로는 별개의 물건으로 잡힙니다. 사람이 안 대 보면 못 가릅니다.

## 다시 열어 볼 조건

기각이지만 영원히는 아닙니다. 넷 중 하나가 생기면 다시 엽니다.

1. 반년에 한 번 다시 훑을 때 **표식이 처음으로 1건이라도 나올 때**
2. **한국어에서 검증된 탐지기**가 나올 때 (지금은 검증 수단 자체가 없어 판정이 불가능합니다)
3. 이 도구의 알려진 결함들이 고쳐져 새 판이 나올 때 — ⚠ 다만 **도구가 고쳐져도 잡을 게 없으면 여전히 기각**이라 1번부터 다시 잽니다
4. 제가 이미지나 문서를 **외부에 배포하는 일**이 생길 때

## 여기부터는 자세한 기록입니다

**지운 것은 하나도 없고, 대신 제 배포 스크립트가 제 규칙을 어기고 있는 걸 찾았습니다.** watermarks-remover 는 AI 생성물에 박히는 프로버넌스 표식을 걷어내는 파이썬 엔진입니다. 11일 만에 별 16,619개. 제가 이걸 연 이유는 표식을 지우려는 게 아니라 **제 발행 파이프라인의 검사 게이트를 점검**하려는 것이었습니다 — 배포 전 마커 스캔이 새는 곳이 있나, 규칙으로만 있고 검사기가 0인 「균일한 문장 리듬」을 결정론 코드로 만들 수 있나. 도구는 전면 기각했습니다. 제 발행 코퍼스 6.1MB 를 이 레포의 스캐너로 훑으니 **표식이 0건**이었기 때문입니다. 그런데 유일하게 탐났던 지표 하나를 제 글에 돌렸을 때 제일 값비싼 사실이 나왔습니다 — **AI 를 잡으라고 만든 지표가, 사람이 쓴 제 글을 먼저 잡았습니다.**

## 무엇을 하는 물건인가 — 「확실한 것」과 「최선노력」을 리포트에서 합산하지 않는다

**AI 가 만든 파일에서 「이건 AI 가 만들었다」는 증거를 걷어내는 엔진입니다.** 증거를 세 종류로 봅니다. 눈에 안 보이는 유니코드로 심어진 캐리어, 생성 시 토큰 선택 확률을 비틀어 심는 통계 워터마크, 파일 안에 구조로 박히는 프로버넌스 메타데이터.

**설계의 중심은 이 셋의 성격이 다르다는 걸 인정한 데 있습니다.** 유니코드는 결정론 코드로 지우고 몇 개 지웠는지 세서 돌려줍니다. 파일 메타데이터도 지운 뒤 자기 출력물을 다시 스캔해 잔존을 신고합니다. 반면 통계 워터마크는 외부 LLM 에게 글을 다시 쓰게 하는 것 말고 방법이 없고, 그건 검산이 불가능합니다. 레포 방침이 이렇게 적혀 있습니다 — *"리포트는 검증 가능한 작업과 최선노력 작업을 반드시 분리해야 한다."* **이 한 줄이 여기서 제일 값나가는 문장입니다.**

| 항목 | 실측 (2026-08-22) |
|---|---|
| 규모 | 151 파일 · 약 1.13MB · 별 16,619 · 포크 1,902 |
| 엔진 / 테스트 | `service/scripts` **14,141 LOC** · 테스트 41파일 10,592 LOC · `def test_` **549개** |
| 의존성 | **런타임 0** (Python 3.10+ stdlib). dev 4종만 정확 핀 |
| 라이선스 | MIT — ⚠ 픽셀 계열 백엔드는 우산 밖(상류에 라이선스 없음 / 비상업 연구용) |
| 활동 | 08-11 생성 → 08-21 마지막 push. **활동 기간 11일**, 커밋 141, 릴리스 5회 |
| 기여 분포 | 27명이지만 오너가 63/122 — **버스 팩터 1** |

**11일짜리 스프린트입니다.** 별 16,619개는 채택이 아니라 바이럴이고, 장기 유지보수 이력은 아직 없습니다. CI 는 3-OS 매트릭스에 lint·의존성 감사·OpenAPI 스펙 검증까지 걸려 있어 나이에 비해 단단해 보이는데, 뒤에서 그 단단함이 무엇을 못 잡는지가 나옵니다.

## 대표 기법 — 값이 나가는 건 지우는 코드가 아니라 「모를 때 어떻게 하는가」다

| 기법 | 내용 |
|---|---|
| **fail-closed 라우팅** | 확장자에도 매직바이트에도 안 걸리는 입력은 예전엔 텍스트로 폴백했습니다. 지금은 파일을 쓰지 않고 종료코드 2로 죽습니다. *"UTF-8 로 못 읽힌다"* 만으로는 바이너리 판정을 하지 않아 다른 인코딩 텍스트는 살립니다 |
| **문맥 인지 스트립** | 같은 코드포인트라도 앞뒤를 보고 다르게 처리합니다 — ZWJ 는 이모지 사이에서만, 한글 필러는 같은 자모 뒤에서만 살립니다. 그리고 미할당 문자를 유니코드 카테고리로 잡지 않고 **명시 레인지로만** 잡습니다. 근거가 주석에 있습니다 — <strong>"Cn 규칙은 갓 할당된 진짜 문자를 파괴한다."</strong> 실제로 그 사고를 겪고 사후 수리한 이력이 있습니다 |
| **PDF 2단 파이프라인** | 메타데이터 제거 도구가 PDF 를 증분 갱신합니다 — 종료코드 0, 뷰어엔 안 보이는데 **원본 바이트는 남고 되돌릴 수 있습니다.** 유일한 단서가 "파일이 오히려 커진다"입니다. 그래서 뒤에 재직렬화를 한 단계 붙여 참조 잃은 객체를 실제로 떨굽니다 |
| **청소 후 재검사** | *"지웠다"* 로 끝내지 않고 산출물을 다시 검사에 태워 잔존을 돌려줍니다. 「청소 완료」와 「청소했지만 남았다」가 종료코드로 갈립니다 |
| **소견 신뢰도 4등급** | 모든 발견을 confirmed / probable / informational / **likely_false_positive** 로 매핑하고, 전체 바이트 스캔은 스스로 최하 등급으로 강등합니다 — <strong>"스캐너 히트는 신호이지 판정이 아니다."</strong> |
| **도구 버전 프로브** | PATH 에 있다고 available 이라 하지 않고 실제로 `--version` 을 돌려 종료코드를 봅니다 — <strong>"`which` 하나로는 틀린 질문에 답하게 된다."</strong> |

**한 가지 더 있습니다 — 이 편의 주인공입니다.** 워터마크가 아니라 **「AI 냄새」를 통계로 채점**하는 스코어러가 따로 붙어 있습니다. 세 항의 가중합입니다 — 상투구 사전 밀도 0.45, **문장 길이 변동계수** 0.45, 어휘 다양도 0.10. 문장이 둘 미만이라 변동계수를 못 재면 그 항을 빼고 나머지로 재정규화합니다.

## 깨본 결과 — 지배적 실패는 오작동이 아니라 「거짓 무죄 판결」이다

**확실히 지운다던 절반부터 흔들립니다.** C2PA 2.x 표준에는 소프트 바인딩 해석 API 가 정식으로 들어가 있습니다. 파일에 박힌 매니페스트가 뜯겨도 비가시 워터마크나 지각 지문으로 원격 저장소를 조회해 프로버넌스를 되찾는 구조입니다. **이 레포가 지우는 것은 표준이 이미 「없어져도 되게」 설계해 둔 쪽**이고, 레포도 소프트 바인딩은 범위 밖이라고 적습니다.

**간판인 벤더 커버리지 네 칸 중 둘은 살아 있는 탐지 경로가 없습니다.** Claude 의 표식은 공식 발표상 토큰 생성의 난수원을 바꾸는 통계 워터마크이지 유니코드 캐리어가 아닙니다. 즉 결정론적으로 검산되는 층은 그 표식을 아예 못 건드리고, 코드의 해당 탐지기는 로직 없는 예약 슬롯입니다. Gemini 칸은 레포가 스스로 사망 선고를 적어 뒀습니다 — 상류가 API 에서 텍스트 워터마킹을 철회했습니다.

**효능 수치는 어디에도 없습니다.** README 73,956바이트에 퍼센트 형태의 효능 수치가 **0건**, 벤치 폴더에 커밋된 실행 결과도 **0건**입니다. 그리고 **오너 본인이 「결과를 낼 수 있게 만드는」 PR 을 두 번 올렸다가 두 번 미머지로 닫았습니다.** 숫자가 아직 없는 게 아니라, 숫자를 낼 장치를 두 번 들였다가 두 번 물렀습니다.

**반복 결함은 한 가지 모양입니다 — 못 지웠는데 깨끗하다고 인증합니다.** 6일 만에 같은 모양의 이슈가 9건 열렸습니다. 잘린 오디오 태그를 소견 0건으로 보고하고 그 파일에 청결 인증을 찍고, 이미지 점수기가 죽었을 때와 워터마크가 없을 때가 똑같이 clean 으로 읽힙니다. **파싱 실패를 「없음」으로 접는 패턴**이고, 사례별로 하나씩 잡고 있어 남은 포맷에서 또 나올 것으로 봐야 합니다. 그중 하나는 되돌릴 수 없습니다 — 제자리 수정을 두 번 돌리면 백업 파일을 청소본으로 덮어써 원본이 영구히 사라지는데, 같은 함수의 독스트링이 *"원본은 절대 부분 손실되지 않는다"* 고 약속하고 있습니다.

**테스트 549개가 왜 이걸 못 잡느냐**의 답이 트래커에 있습니다. *"기여자들이 Claude 를 쓰는 건가요"* 라는 질문에 오너가 그렇다고 답했습니다. 11일에 코드 14k + 테스트 10.6k LOC 입니다. **코드와 테스트가 같은 생성기의 같은 패스에서 나오면, 테스트는 생성기의 사각지대를 원리적으로 못 덮습니다.** 커버리지 게이트 부재보다 이쪽이 본질입니다.

**공정하게, 제 1차 판정 둘을 취소합니다.** 광고된 동영상 경로가 파일을 손상시킨다던 이슈는 **이미 고쳐져 있었습니다** — 삭제할 박스를 같은 크기의 0 채움 박스로 치환해 오프셋 테이블이 유효하게 남습니다. ⚠ 관련 문자열이 코드에 없다고 미수정으로 읽으면 오진합니다. 다른 하나는 이슈 제목의 **SSRF 라는 이름을 그대로 옮긴 것**이 과장이었습니다 — 엔드포인트가 공격자 입력이 아니라 운영자 환경변수라, 실제 결함은 내부망 피벗이 아니라 리다이렉트 시 인증 토큰과 본문이 새는 것입니다. **이슈 제목은 사실이 아니라 남의 판정입니다.**

**못 한 것.** 이 레포의 벤치를 직접 못 돌렸습니다 — GPU 와 외부 체크아웃 4종이 필요하고 코퍼스 씨앗 8개가 전부 영어입니다. 그래서 *"얼마나 지워지는가"* 는 이 페이지에서도 **미측정으로 남습니다.** 워터마크가 실제로 박힌 파일에 대 본 적도 없습니다. 제 환경에 그런 파일이 없어서입니다.

## 내 환경에 대봤다 — 잡을 것이 0건이었다

레포 HEAD 의 스캐너를 그대로 임포트해 제 발행 코퍼스 전량에 돌렸습니다.

| 무엇을 쟀나 | 결과 |
|---|---|
| 보이지 않는 유니코드 — 문서 196편 + 정적 HTML 238장 + 원고 7편 (6.1MB) | **0건** |
| 청소 함수 라운드트립 — 같은 196편, 기본·파라노이드 양쪽 | **196/196 바이트 동일** = 순수 no-op |
| 발행 이미지 14장의 C2PA·AI 메타데이터 | **14/14 전부 없음** — 헤드리스 렌더 산출물이라 애초에 안 박힌다 |
| 로컬 뇌 파일까지 확대 (스킬 195편 + 메모리 180편) | 5파일에 7개 — 전부 발행 경로 밖, 조치 불필요 |

**표적이 없었습니다.** 훼손 위험 0이면서 동시에 변경 0이면, 그건 게이트가 아니라 장식입니다.

**유일하게 탐났던 AI 냄새 스코어러는 한국어에서 절반이 죽습니다.** 상투구 패턴 24개 중 비ASCII 가 **0개**라 가중치 0.45짜리 항이 영원히 0입니다. 같은 성격의 대조군을 두 언어로 만들어 채점하니 영어 0.887(HIGH) 대 한국어 0.438(LOW) — **임계 0.65 는 한국어가 도달할 수 없는 값**입니다(이론 천장 약 0.55). 그래서 언어 중립인 한 항만 떼서 재봤습니다.

> **[도판]** 장문 98편에서는 임계 아래가 2편이었다. 실제 적용처인 짧은 원고로 다시 재니 1/6 이었다.
>
> 문장 길이 변동계수를 세 코퍼스에 같은 계산기로 돌린 결과. 사이트 장문 98편은 중앙값 0.668로 널찍하지만, 이미 게시까지 끝낸 짧은 원고 한 편은 0.298로 임계 0.35 아래에 떨어진다. 한국어 AI 대조군은 0.055다. 짧은 사람 글이 긴 사람 글보다 AI 쪽에 더 가까이 앉아 있다.

**사이트 장문 98편은 중앙값 0.668 로 널찍하게 흩어져 있습니다.** 임계 0.35 아래는 2편뿐이었고 둘 다 색인 성격의 짧은 페이지라, 1차에는 *"오탐 2%"* 로 적고 넘어갔습니다. **그런데 이 게이트를 실제로 걸려던 자리는 장문이 아니라 짧은 발행 원고였습니다.** 그쪽 6편을 다시 재니 0.298~0.550 의 좁은 띠에 눌려 있었고, 그중 하나 — **제가 손으로 쓰고 게시까지 끝낸 글** — 이 0.298 로 임계 아래였습니다. 짧은 글은 사람이 써도 균일합니다. **이 지표가 재는 것은 「누가 썼나」가 아니라 「얼마나 길게 썼나」입니다.**

## 수확 — 4종에서 1.5종으로

| 후보 | 판정 | 사유 |
|---|---|---|
| **문장 리듬 변동계수 한 항** | **채택(반쪽)** | 결정론 리듬 검사기가 제게 정말 0건이 맞습니다. 다만 **장문 전용**이고, 짧은 채널 임계는 별도 코퍼스로 다시 재기 전까지 만들지 않습니다 |
| 가중합 3항 골격 + 결측 항 재정규화 | ⛔ **기각** | 3주 전에 제가 더 나은 형태로 만들어 뒀습니다 — [테스트케이스 파이프라인](/ko/built/tc-team/index.md)의 확신도 채점기에 규칙표·상한 클램프·선택 입력·임계 역산 스윕·기대표 잠금이 있고, *"축이 다른 감점을 상쇄 금지"* 같은 함정 수리가 주석에 박혀 있습니다 |
| fail-closed 파일 선택 | **원칙만** | 남에게 배울 기법이 아니라 **제 준수 결함 1건**이었습니다. 아래 |
| 보이지 않는 유니코드 검출 세트 | **조건부 보류** | 이득이 실측 0 이라 보험으로만 정당화됩니다. host 도 이미 있습니다 — 기존 링크 검사기가 dist 전량을 훑고 눈에 보이는 글자만 뽑는 루프를 돌립니다. 신규 파일이 아니라 그 안 세 줄입니다 |

**세 번째 줄이 이 조사의 실제 산출입니다.** 제 전역 규칙 첫 줄이 *"애매하거나 실패하면 하지 않는 쪽이 기본값"* 이고, 배포 게이트의 라이브러리 헤더 주석은 자기 자신을 fail-closed 라고 규정합니다. 그런데 그 게이트가 파일을 고르는 방식은 **확장자 화이트리스트** — 아는 확장자만 검사하는 fail-**open** 입니다. 지금 실누락은 0건이지만, `.mjs`·`.rss` 같은 게 산출물에 생기는 순간 **경고 한 줄 없이** 무검사로 통과합니다.

⚠ **그리고 여기서 남의 구현은 들이지 않기로 했습니다.** 레포는 매직바이트 28종 + NUL + 제어문자 비율로 판정하는데, 259 파일 규모에서 그 표는 유지보수 부채입니다. 같은 fail-closed 를 세 줄로 얻습니다 — 아는 목록 어디에도 없는 확장자가 나타나면 그냥 멈춥니다. **원칙은 채택, 구현은 기각.**

**(2026-09-28) 들어갔다.** 점검 때까지 마커 스캔은 `/\.(html|css|js|json|xml|txt|svg|md)$/i` 에 안 맞으면 그냥 `continue` 였다 — 2026-09-17 에 마크다운 판 226장이 생겼을 때 스캔을 탄 것은 `md` 가 8월 배포 배선 때부터 목록에 있었기 때문이다. 이제 건너뛸 것도 목록으로 정한다(`SKIP = /\.(webp|png)$/i` — 그날 `dist` 의 비텍스트 종류 전부: 표지·게임 그림·공유 카드). 두 목록 어디에도 없는 종류가 크기 0 이 아니면 **push 전에 멈춘다**(빈 `.nojekyll` 은 샐 게 없어 통과). 틀린 표본(`public/` 에 넣은 `.rss` 한 장)으로 실제 배포 경로를 돌려 스캔 단계에서 exit 1·push 없음을 확인했고, 표본을 빼고 다시 빌드하면 정상 `dist` 는 텍스트 517·건너뜀 20·모름 0 이다. 리듬 변동계수 한 항은 아직 어디에도 구현돼 있지 않다.

## 부수적으로 — 제 수집기는 원본이 아니라 복제본을 후보로 올렸습니다

후보 목록에 `Leutenegger/watermarks-remover` 가 올라와 있었습니다. 피드에 실린 것은 `guillaumemeyer/watermarks-remover ★16,619` 입니다. **둘은 다른 저장소입니다.**

| | 원본 | 복제본 |
|---|---|---|
| 생성 | 2026-08-11 | **2026-08-19** (8일 뒤) |
| 별 | 16,619 | 929 (**3일 만에**) |
| 포크 플래그 | false | **false** — 깃허브 포크가 아니다 |
| README | 1,120줄 | 1,063줄 중 **1,058줄이 원본과 일치** (99.5%) |

**복제본 README 안에 원저자 저장소를 가리키는 링크가 15개 그대로 남아 있습니다** — CI 배지가 남의 저장소를 가리킵니다. 포크 관계만 끊긴 통짜 복사본입니다. 제 후보 다리는 별 수와 낱말 규칙만 보니 **원본과 복제를 구분하지 못합니다.** 별이 빠르게 붙는 건 도구가 좋다는 신호가 아니라 화제가 붙었다는 신호이고, 복제본은 그 화제만 빌려 가면 됩니다.

## 판정

| 항목 | 판정 |
|---|---|
| 레포·서비스·스킬·도커 도입 | ⛔ **기각.** 파일 한 톨도 제 트리에 들이지 않습니다 |
| 파일 메타 / 이미지 / 문서 경로 | ⛔ **기각.** 필요해지면 기성 도구를 직접 부릅니다 — 그쪽은 제자리 수정을 안 해서 원본 소실이 구조적으로 불가능합니다 |
| 수확 | **1.5종** — 리듬 변동계수 한 항(장문 전용) + fail-closed 준수 복구 |
| 회사 파이프라인 반입 | ⛔ **부적절.** 기술 판정과 별개입니다 |

**(2026-09-28 기준)** 수확 1.5종 중 **fail-closed 는 들어갔고**(위 절), 리듬 한 항은 아직 없다.

**(2026-09-29) 리듬 한 항도 들어갔다 — 배포 게이트 `check-rhythm.mjs`.** 문장마다 어절 수를 세고 변동계수(모표준편차 ÷ 평균)를 낸다. 문장은 마침표·물음표·느낌표 뒤에 띄어쓰기가 올 때와 줄 끝에서 자르고, 본문 글자만 센다 — 머리말·도판·코드·표·제목 줄은 뺀다. 표를 빼는 이유는 실측이다. 표·제목까지 문장으로 세면 표 한 장이 아주 긴 «문장» 하나가 되어, 쉬운 설명 층이 자세한 기록보다 오히려 들쭉날쭉하게 나온다(중앙값 0.872 대 0.682). 본문만 세면 반대다(0.484 대 0.537). 층(쉬운 설명·자세한 기록)은 따로 재고, 문장 20개 미만인 층은 안 잰다 — 전수 464층 중 ko 23·en 24층이고 거의 전부 색인·자리표시 페이지다. 15·20·25 어디에 두어도 걸리는 층이 같았다. 선은 0.35 그대로, ko·en 둘 다 건다.

⚠ **8월 계산기는 남아 있지 않다.** 새 계산기로 같은 98편(이 편을 들인 커밋의 부모)을 다시 재면 선 아래는 역시 짧은 페이지 2편(11·13문장)이지만, 중앙값은 0.524 로 당시 0.668 과 다르다. 판정은 재현되고 숫자는 재현되지 않는다 — 옛 숫자와 새 숫자를 나란히 놓지 말 것.

첫 전수에서 선 아래 긴 층은 ko 쉬운 설명 2층이었다 — 「Loki › 기능」 0.334, 「(가칭) 무협 게임」 0.340. 게이트가 같이 찍는 «가장 평평한 곳»(7·8·8·7어절, 6·5·7·5어절)만 내용 그대로 박자를 바꿔 0.436·0.476 이 됐다. en 은 0층. 통과한 층 중 가장 고른 것이 0.354(en 쉬운 설명 한 층)라 여유는 크지 않다. `--selftest` 7/7 — 한 박자 25문장은 물고, 들쭉날쭉한 것은 안 물고, 10문장짜리는 안 재고, 표·제목·도판은 안 섞고, 0.35 같은 소수는 안 자르고, ko·en 경계 제목으로 층을 가른다. 고치기 전 두 편(HEAD 판)에 돌리면 exit 1 로 멈추는 것도 확인했다.

⚠ **쉬운 설명 층이 더 잘 걸린다** — 116편 중 91편에서 쉬운 설명 쪽 박자가 더 고르다. 짧게 끊어 쉽게 쓰는 습관과 이 게이트가 부딪히는 자리다. 고칠 때 긴 문장을 억지로 끼우지 않고, 이어지는 두세 문장을 한 문장으로 묶었다.

**다시 여는 조건 넷** — ① 반기 1회 재스캔에서 표식이 처음으로 1건이라도 나올 때. ② 한국어에서 검증된 텍스트 워터마크 탐지기가 나올 때. 그 전까지 재작성 층은 검증 수단이 없어 판정 자체가 불가능합니다. ③ 데이터 손실·허위 clean 4종의 PR 이 머지되고 다음 릴리스가 나올 때. ⚠ 그때도 **도구가 고쳐져도 표적이 없으면 여전히 기각**이라 ①부터 다시 잽니다. ④ 이미지·PDF 를 외부에 배포하는 워크플로가 생길 때.

**이 편에서 값을 치른 교훈은 도구가 아니라 순서입니다 — 검출기를 들이기 전에 자기 코퍼스로 오탐률부터 재라.** 그것도 **실제로 걸 자리의 코퍼스로** 재야 합니다. 저는 사이트 장문에서 재고 「오탐 2%」라 적었는데, 그 규칙이 사는 채널로 옮겨 재니 1/6 이었고 걸린 것은 제가 쓴 글이었습니다.

그리고 하나 더. 별 16,619개짜리 레포를 뜯어서 남은 게 **제 규칙 문서 한 줄을 제 배포 스크립트 한 줄이 어기고 있더라는 자기 대조 1건**이었습니다. 남의 물건을 보는 값은 가져올 것에만 있지 않습니다 — 남의 원칙을 들고 제 코드를 보면, 제 원칙으로 볼 때는 안 보이던 것이 보입니다.
