목록으로

임계 0개인 표가 내리는 판단: 정렬과 표시 상한

2 조회
개발 도구 신뢰성
#웹소설 툴킷#설계 결정#코드리뷰#릴리스

TL;DR

  • 임계를 일부러 안 붙인 표를 경과 내림차순으로 정렬했더니 1화에 깔고 잘 자란 항목이 1위에 섰다. 찾던 것은 꼴찌였다
  • 같은 커밋의 다른 파일에는 표본 1개로 박은 임계가 있었다. 나쁜 원고와 통제 원고의 1위가 같은 낱말이고 11%와 12.2%다
  • 표시 상한 15줄이 정렬과 겹쳐서, 할 일이 정해진 두 종류가 언제나 먼저 화면 밖으로 나갔다

웹소설 집필 도구에 진단 하나를 넣었다. 오래전에 깔아 놓고 한 번도 다시 안 나온 복선을 세는 표다. 코드는 webnovel-toolkit/skills/webnovel-reveal/scripts/reveal.pyq_starved 에 있다.

증상: 숫자 하나만 있고 경고가 없던 자리

이 도구는 독자 지식 원장을 들고 있다. 어떤 설정이 몇 화에 처음 나왔고 몇 화에 공개됐는지를 적는 파일이다. reveal.py query 를 돌리면 이런 줄이 나온다.

- 미공개 잔여: 10건

숫자만 있고 그중 무엇이 위험한지가 없다. 실제로 한 작품에서 1화에 깔아 둔 복선이 20화까지 한 글자도 안 열렸는데, 이 도구는 20화 내내 같은 문장만 냈다. 원장은 그 사실을 정확히 들고 있었다. 처음 나온 화도, 그 뒤로 한 번도 안 나왔다는 것도 파일에 적혀 있다. 세는 자리만 없었다.

반대 방향은 이미 있었다. 너무 많이 흘려서 반전이 들켰을 항목을 세는 표, 마지막으로 나온 뒤 오래 방치된 것을 세는 표. 처음 던진 뒤 안 자란 것만 빠져 있었다.

반전 1: 임계 없는 표의 정렬 키

이 저장소에는 규칙이 있다. 표본 없이 박은 숫자는 검사를 통과하는 순간 인증된 오답이 된다. 그래서 새 표에도 경고 임계를 안 붙였다. 경과와 재언급 횟수만 적고 판단은 작가에게 넘겼다.

독립 검토를 띄웠더니 검토자가 이런 표를 돌려 왔다. 최소 재현을 줄여 옮긴 것이다.

| 항목            | 층 | 처음 나온 화 | 경과 | 그 뒤 언급 |
|---|---|---|---|---|
| 잘 자란 떡밥     | 🟨 | 1화        | 19화 | 14화      |   ← 1위
| 사라진 떡밥      | 🟥 | 3화        | 17화 | 0화       |
| 정말 굶은 떡밥   | 🟥 | 12화       | 8화  | 0화       |   ← 꼴찌

정렬 기준이 경과였다. 1화에 깔린 것은 무조건 위로 온다. 20화 중 14화에 다시 나온 멀쩡한 항목이 표의 첫 줄이고, 찾으려던 것은 맨 아래였다.

표 이름은 "던져 놓고 안 자란 것"인데 순서는 "오래된 것"이었다. 경고를 안 붙였다고 판단을 안 하는 것이 아니다. 읽는 순서가 판단이다. 사람은 표를 위에서부터 읽고 위에 있는 것을 중요한 것으로 받는다.

정렬 키를 재언급 횟수 오름차순으로 바꿨다. q_starvedrows.sort(...) 한 줄이다. 한 줄도 안 지웠고 아무것도 안 걸렀다.

반전 2: 같은 커밋의 반대 잣대

같은 릴리스에 문체 지표도 하나 넣었다. 대사를 뺀 서술 문장(지문)이 어느 낱말로 끝나는지를 세는 것이다. 한 원고에서 "있었다"가 서술 문장의 11%를 차지했고 검토자가 그 원고를 단조롭다고 했기에 10%를 경계로 삼았다. 코드는 styleprofile.py 다.

검토자가 문장을 겹치지 않게 흩뜨린 통제 원고를 하나 만들어 넣었다.

- 지문 문장 820개
- 있었다: 100회 (12.2%)
...
- ⚠️ 서술 문장 12%가 `있었다` 로 끝난다. 종결어미를 골고루 써도 같은 낱말로 착지하면 같은 소리가 난다

통제 원고의 1위도 "있었다"였고 12.2%였다. 나쁜 사례보다 높다. 두 값은 서로 가릴 수 있는 거리가 아니다.

걸린 낱말을 보면 전부 보조용언이다. "걸어오고 있었다", "고여 있었다", "않았다". 진행상과 부정을 쓰려면 한국어에서 달리 적을 방법이 없다. 다르게 끝내라는 조언이 그 문법을 쓰지 말라는 말이 된다.

근거 쪽이 더 문제였다. 나쁜 사례 하나는 쟀는데 정상 원고의 값은 안 쟀다. 그 상태로 알려진 나쁜 값 바로 아래에 선을 그으면, 그 선이 정상 분포의 어디쯤인지 아무도 모른다. 통제 원고는 표본 하나이고 검토자 본인이 대표성이 없다고 적었다. 그래도 걸린다는 사실은 남는다.

같은 커밋의 reveal.py 에는 이 docstring 이 있었다.

    **임계를 안 붙인다.** 무엇이 「너무 오래」인지는 회차 길이와 층에 따라 다르고,
    이 저장소에 그 분포가 없다.

한쪽은 분포가 없어서 뺐고 다른 쪽은 표본 하나로 박았다. 두 파일을 같은 날 같은 사람이 썼다. 상수를 지우고 비율만 내는 쪽으로 바꿨다.

반전 3: 정렬과 상한이 겹치는 자리

표가 길어져서 15줄 상한을 얹었다. STARVED_TOP = 15 다. 정렬은 "못 센 항목"과 "원고에서 사라진 항목"을 맨 뒤로 보내고 상한은 뒤에서 자른다. 둘을 겹치면 언제나 그 둘부터 잘린다.

하필 그 둘이 할 일이 정해진 항목이다. 원고에서 사라진 것은 개고할 때 그 대목을 들어냈다는 뜻이다. 원장을 고치고 다시 스캔하면 된다. 그것이 "잘 자란 떡밥 15줄"에 밀렸다. 잘린 이유로 찍히는 문장도 틀렸다. 재언급이 많아서 밀렸다고 적는데 잘린 것은 재언급을 못 센 항목이었다.

상한을 실측된 항목에만 걸었다.

확인 방법

세 건 다 검토자가 직접 돌려 보고 출력을 붙여 왔다. 저장소 밖에 가짜 원장과 원고를 만들어 reveal.py query --starvedstyleprofile.py <원고> 를 그대로 실행한 것이다. 코드를 읽어서 나온 지적이 아니다.

여기서 갈린 것이 하나 더 있다. 1라운드에 렌즈를 둘로 나눠 띄웠다. 하나는 판단이 뒤집혔을 때 어디까지 영향이 가는지를 봤고 다른 하나는 작가가 실제로 받는 화면과 상수의 근거를 봤다. 각각 9건씩 냈는데 같은 결함을 짚은 자리는 하나였다. 나머지 열일곱 중 셋은 같은 함수를 서로 다른 형태로 짚었고 열넷은 한쪽만 봤다.

정렬 문제는 뒤엣 렌즈에서 나왔다. 코드만 읽으면 정렬 한 줄은 그냥 정렬이다. 40항목짜리 원장을 만들어 돌려 보고 나서야 첫 줄에 무엇이 서는지가 보인다.

개선

고치기 전고친 뒤
던져 놓고 안 자란 것 표의 1위재언급 14화짜리재언급 0화짜리
문체 경고 임계표본 1개로 박은 10%없음. 비율만 출력
상한에 먼저 잘리는 것원고에서 사라진 것과 못 센 것재언급 많은 항목

남은 것

서술 착지의 임계는 뺐고 대신 세운 것이 없다. 몫만 내고 판단은 읽는 사람에게 넘겼다. 선을 다시 그으려면 정상 원고의 1위 착지 몫이 몇 %인지 알아야 하는데, 통제 원고 하나로는 모른다. 그 하나는 검토자가 쓴 글이고 본인이 대표성이 없다고 적었다.

정렬도 같은 자리에 있다. 지금 순서는 재언급이 적은 것부터인데, 그것이 찾는 순서와 맞는지는 여러 작품에서 재 봐야 안다. 원장이 하나뿐이라 아직 못 쟀다.


댓글

댓글 작성