검토 5라운드 회수 43건: 직전 수정이 만든 회귀 8건
웹소설 집필 도구를 만들고 있다. 이번 판에서 고치려던 것은 하나였다. 끌 수 없는 경고.
세 자리에서 같은 일이 벌어지고 있었다. 원고 폴더에 규칙 문서(README.md)를 두면 매 실행 "대조에서 빠진 파일" 경고가 떴다. 복선이라 일부러 비워 둔 칸에도 매번 "채워야 스캔된다"가 붙었다. 키워드 조용이 「조용해야 했다」라는 은신 서술 네 줄에 걸려서 가장 무거운 진단인 정보 격차 위반 후보로 올라갔다.
셋 다 옳은 경고를 내려다 만든 것이다. 그런데 매번 뜨는 경고는 곧 안 보게 되고 안 보기 시작하면 같은 자리의 진짜 결함도 같이 묻힌다. 프롤로그.md가 대조에서 빠진 것과 원고 폴더의 README 가 같은 줄에 뜬다.
첫 수정과 첫 되돌림
낱말 경계를 넣었다. 키워드 앞에 한글이 붙어 있으면 다른 낱말의 꼬리로 보고 뒤에 한글이 이어지면 그게 조사일 때만 등장으로 센다.
로컬 검사 17개가 전부 초록이었다. 그 상태로 독립 검토를 띄웠다. 검토 쪽에서 원고 여섯 편을 직접 만들어 돌려 보고 이렇게 짚어 왔다.
스승 → hits 0 / filtered 3
현수막 → hits 0 / filtered 3
query --spoiled → ## 들킨 반전 후보 / _없음_
원고에 「스승님」이 여섯 번 나오는데 키워드 스승의 등장이 0이었다. 조사만 받고 님·들 같은 접미사를 안 받은 탓이다. 거짓 양성을 고치면서 같은 무게의 거짓 음성을 만들었다.
이게 다섯 라운드 내내 반복된 형태다. 회수 43건 중 8건이 직전 라운드의 회수가 만든 오류였다.
한 자리를 네 번 놓친 기록
가장 오래 걸린 건 /wn-adopt --force 였다. 기존 프로젝트를 다시 등록하는 명령인데, 작가가 손으로 적은 설정을 지우고 있었다.
1차로 설정을 통째로 갈아끼우던 코드를 update 로 바꿨다. 2라운드가 짚었다. 그 cfg 는 기본값 사본이라 update 가 기본값을 덮을 뿐이고 코드는 안 고쳐졌다. 주석과 패치노트만 참이 됐다.
2차로 기존 설정을 바닥에 깔고 병합했다. 3라운드에서 두 레인이 각각 돌려 보고 같은 걸 짚어 왔다. 덮을지 말지를 "값이 다른가"로 판단했는데, 덮는 쪽이 기본값 사본이라 기본값이 작가 값을 이겼다.
before: title='내 작품', exclude=['메모*.md'], count_whitespace='exclude'
after : title=None, exclude=['README*', ...], count_whitespace='include'
3차로 추론 함수가 자기가 실제로 채운 키 목록을 같이 돌려주게 했다. 판단이 "값 비교"에서 "출처 확인"으로 바뀌었다.
4라운드가 네 번째를 짚었다. 그 목록에 paths.index·style_profile·reveal 이 들어 있었는데, 그건 찾은 값이 아니라 박아 둔 문자열이다. 작가가 설정/색인 으로 옮겨 둔 경로가 .webnovel/index 로 되돌아갔다.
5라운드가 다섯 번째를 짚었다. paths.aliases 도 같았다. 그건 bible 로 조립한 값이지 찾은 값이 아니다.
위치로 가를 수 없는 것
4라운드에서 회수 계획 판정도 고쳤다. 「영구 미공개」가 회수 계획으로 판정되고 있었다. 공개 를 부분 문자열로 찾아 「미공개」 안에서 걸린 것이다. 함께 "안 하기로 정한 것은 회차 번호가 붙어 있어도 계획이 아니다"를 넣었다.
5라운드가 그 수정이 만든 회귀를 짚었다.
17화에 회수. 그 전까지는 밝히지 않는다 → 계획인데 미기입으로 떨어짐
3부 중반에 공개, 그 전에는 안 밝힌다 → 계획인데 미기입으로 떨어짐
노출 시점을 적는 가장 흔한 형태가 전부 사라졌다. 그런데 「3부에서 안 밝히기로 결정」은 거부가 맞다.
셋의 구조가 문제였다. 셋 다 지점이 부정보다 앞에 온다. 앞뒤 순서로는 구분이 안 된다. 쉼표와 마침표로 절을 나눠서 거부도 미결도 없는 절에 회수 지점이 있으면 계획으로 판정하도록 바꿨다. 그러자 셋이 갈렸다.
자기 규격이 자기 추론을 깬 자리
5라운드가 하나 더 짚었다. 바이블 정본 파일 이름 00-core.md 가 회차 패턴 ^(\d{1,4})[\s_.-] 에 걸려 0화로 읽히고 있었다. 설정 디렉토리가 회차 디렉토리로 세어지고, 원고 루트 추론이 두 디렉토리의 공통 조상으로 밀리고, --force 가 그 값을 저장해 작가의 paths.manuscript 가 "." 이 됐다.
이 도구가 만들라고 시킨 파일 이름이 이 도구의 추론을 깬 것이다.
오래 안 보인 이유가 있다. --force 가 값을 보존하지 않던 시절에는 이 추론이 틀려도 그냥 틀린 채로 덮였다. 보존을 넣고 나서야 "무엇을 덮고 무엇을 안 덮는가"가 중요해졌고 그때 추론의 정확도가 처음으로 문제가 됐다.
검토 레인이 죽고 초록을 반환한 자리
4라운드는 12개 에이전트 중 11개를 세션 한도로 잃었다. 최종 반환은 이랬다.
{"total":10,"now":[],"issue":[]}
겉보기에는 아무 문제 없음이다. 살아남은 것은 지적을 낸 레인 하나였고 죽은 것은 그 지적을 검증하는 쪽이었다. 검증이 없으면 결과 배열이 비고, 비면 초록으로 읽힌다.
반환값을 안 믿고 실행 기록에서 원본 지적 10건을 꺼내 직접 돌려 봤다. 10건 전부 재현됐고 그중 셋이 심각한 것이었다.
이 저장소는 무인 판정 도구에 "조회 실패와 할 일 없음은 다른 결과다"를 종료 코드로 박아 뒀다. 검토 레인에는 안 박혀 있었다.
검사로 고정하고 죽여 보기
같은 판단 셋이 라운드마다 반대 방향으로 틀렸다. 라운드마다 예를 새로 만들어 확인했고 그 예는 어디에도 안 남았다.
통합 점검 스크립트에 케이스 표를 넣었다. 낱말 경계 13개, 회수 계획 판정 19개, 건수 선언 15개. 각 줄이 실제로 한 번씩 틀렸던 자리다. --force 값 보존도 같은 형태로 고정했다.
그리고 검사를 각각 죽여 봤다. 저장소 밖에 스킬 폴더를 복사해서 절 규칙과 병합 루프를 원래대로 되돌린 뒤 돌렸다.
❌ 판정식 회귀 케이스 | 의도 「150화까지 비공개, 151화에 공개」 True≠False ...
❌ --force 가 작가 값을 보존 | manuscript.exclude: ['메모*.md']→['README*', ...]
붉어지지 않는 검사는 없는 검사다.
고친 뒤의 값
같은 원고 여섯 편에서 키워드 스승의 등장이 0에서 4로 돌아왔고 「들킨 반전」이 _없음_에서 실제 후보를 낸다. 경계에서 걸러진 히트는 수만이 아니라 꼬리 문자열까지 나온다.
--force 재등록에서 보존되는 키가 0개에서 13개가 됐다. 커밋되는 설정 파일에 윈도우 경로 구분자가 안 들어간다.
결함이 하나도 없는 프로젝트가 "이상 없음"에 도달한다. 전에는 건수 선언 문장이 없다는 이유로 영구히 경고 1건이었고 이 도구가 배포하는 문서 틀에는 그 문장이 없다.
통합 점검은 55개에서 58개가 됐다. 회귀 케이스는 0개에서 47개다.
남은 것
조사 목록이 못 담는 꼬리가 있다. 「현수막이었고」의 이었고 같은 연결형이다. 목록을 넓히면 「조용해야」류가 다시 들어오므로 안 넓혔다. 대신 걸러낸 꼬리를 화면에 적는 것으로 두었다. 이게 충분한지는 실제 원고에서 재 보지 않았다.
두 음절 이상 키워드의 접미사 오탐도 남았다. 아가가 「아가씨」에 걸린다. 음절 수 조건으로는 못 가른다.
"확인 못 함" 사유에서 경로를 줄이는 처리가 윈도우 드라이브 경로만 본다. 리눅스 절대경로는 그대로 남는다. 이 도구를 쓰는 사람 대부분이 윈도우라 뒤로 미뤘고 미뤘다는 사실만 적어 둔다.