AI

내가 쓴 규칙을 소스로 검증했더니 근거가 틀려 있었다

규칙도 썩는다

앞의 두 글에서 규칙을 어떻게 나누고 어떻게 쌓았는지 썼다. 이번엔 반대다. 쌓아둔 규칙을
다시 읽어보니 틀린 것들이 있었다.

틀린 방식이 세 가지였다. 동작은 맞는데 이유가 틀린 것, 가리키던 대상이 사라진 것, 그리고
숫자를 재본 적이 없는 것.

셋 다 에러가 나지 않는다. 그래서 읽어보기 전에는 몰랐다.

하나 — 동작은 맞았고 이유가 틀렸다

작업이 클 때 어느 실행 모드를 쓸지 정하는 규칙을 이렇게 써놨었다.

모드 선택: 독립 작업 다수 → ultrawork, 끝까지 가야 하는 단일 목표 → ralph

두 모드를 병렬 선택지로 기술했다. 작업이 여러 갈래면 앞의 것, 하나로 이어지면 뒤의 것.
말이 되는 것 같았다.

플러그인 소스를 열어보니 아니었다.1

근거 내용
keyword-detector.mjs:1823-1827 hasRalph && !hasUltrawork 이면 ultrawork 를 강제 활성화한다
README.md:410 ralph 는 “automatically includes ultrawork’s parallel execution”
ultrawork/SKILL.md:9 ultrawork 는 “a component, not a standalone persistence mode”
ralph/SKILL.md:13 ralph 가 ultrawork 를 “wraps” 한다

ralph 가 ultrawork 를 포함하고 있었다. 코드 레벨로 강제된다. 그러니 “병렬 작업이 여럿
이냐”는 애초에 선택 기준이 될 수 없었다. 둘 다 병렬로 돈다.

실제 갈림길은 다른 데 있었다. ralph/SKILL.md:29 에 이렇게 적혀 있다 — “User wants manual
control over completion → use ultrawork directly”. 완료 시점을 누가 판단하느냐가 기준
이었다. 그렇게 고쳤다.

- 독립 작업 다수→ultrawork, 끝까지 가야 하는 단일 목표→ralph
+ 완료 시점을 직접 판단하면→ultrawork, 완주·검증까지 맡기면→ralph(= ultrawork 포함)

여기서 중요한 건 커밋에 적어둔 마지막 줄이다.

동작 변화는 없다 — 기존 규칙도 결과적으로 맞는 모드를 골랐고, 틀린 것은 이유 설명이었다.

결과가 맞았으므로 틀린 걸 알아챌 방법이 없었다. 잘 돌아가고 있었다. 소스를 읽어보기
전까지는.

이런 규칙이 위험한 이유는 경계 상황에서 무너지기 때문이다. 평소엔 우연히 맞는 답이
나오지만, 애매한 경우가 오면 틀린 기준으로 판단한다. 그리고 그때도 에러는 안 난다.

둘 — 가리키던 것이 사라졌다

같은 줄을 17일 뒤에 또 고쳤다. 이번엔 틀린 이유가 다르다.

2026-07-07 독립 작업 다수 → ultrawork 단일 목표 → ralph 2026-08-10 완료 시점을 누가 판단하나 ralph = ultrawork 포함 2026-08-27 ultrawork → execute 모드가 삭제됨 틀린 이유가 서로 다르다 근거가 틀렸다 병렬성은 선택 기준이 될 수 없었다 — 동작은 맞았다 대상이 사라졌다 스킬 41 → 31 없는 모드로 라우팅 — 동작이 깨졌다 공통점 둘 다 에러가 나지 않았다 읽어보기 전까지 몰랐다

플러그인이 5.0.0 으로 올라가면서 스킬을 41개에서 31개로 줄였고, 그 과정에서 ultrawork
가 삭제됐다.
CHANGELOG 에 “removes 17 legacy names outright” 라고 적혀 있다.

플러그인 지침 파일을 5.0.0 으로 갱신한 것이 8월 24일이고, 이 줄을 고친 것이 27일이다.
그 사이 사흘 동안 없는 모드로 라우팅하고 있었다.2

확인은 간단했다.

ls .../oh-my-claudecode/5.0.0/skills/ | grep -c ultrawork  →  0
4.15.10 에는 41개, 5.0.0 에는 31개

앞의 경우와 성격이 다르다. 그때는 동작이 맞았고 이유만 틀렸다. 이번엔 동작 자체가 깨졌다.
없는 이름을 가리키고 있으니 그 규칙은 아무것도 하지 못한다.

그런데도 에러는 안 났다. 규칙 파일은 그냥 텍스트라서, 존재하지 않는 것을 가리켜도
아무도 검사하지 않는다.

이게 컨텍스트 파일의 구조적 약점이다. 코드였다면 import 가 깨져 빌드가 실패했을 것이다.
문서는 조용히 낡는다.

셋 — 재본 적 없는 숫자를 써왔다

세 번째는 이 블로그 때문에 발견했다.

규칙 팩 하나를 일부러 제외하면서 근거로 “≈40K” 라는 숫자를 적어뒀었다. 상시 로드 비용이
크다는 뜻이다. 글에 이 수치를 인용하려고 검증했더니 — 재본 값이 아니었다.3

실제로 재보니 이랬다.

대상 파일 글자
제외한 common 10 545 17,429
도입한 4개 팩 21 1,970 61,405

어느 단위로 봐도 40K 가 아니다. 어디서 온 숫자인지도 모른다.

다만 여기서 결론까지 뒤집지는 않았다. 제외 근거 자체는 유효했다. 다만 근거가 숫자가
아니라 구조였을 뿐이다 — common 10개 파일 전부 frontmatter 가 없어서, 특정 언어 파일을
다룰 때만 로드되는 스코프가 아예 없다. 그래서 모든 세션에 실린다.

grep -l 'paths:' → 0

숫자를 지우고 이 사실을 근거로 바꿨다. 그리고 경고를 하나 남겼다 — 측정한 버전이 도입
시점과 다르므로 이 값은 “도입 당시”가 아니라 “재측정 시점”의 값이다.

세 가지가 다른 종류다

정리하면 이렇다.

유형 동작 어떻게 발견했나
근거가 틀림 정상 소스를 읽어봄
대상이 사라짐 깨짐 버전 올린 뒤 확인
숫자가 미검증 정상 인용하려다 검증

첫 번째와 세 번째는 동작에 문제가 없었다. 그래서 계기가 없으면 영원히 안 고쳐진다.
내가 소스를 열어보거나, 블로그에 쓰려고 다시 재보지 않았으면 그대로 남아 있었을 것이다.

세 번째가 특히 그렇다. 규칙 파일에 숫자를 적으면 그 순간부터 그건 근거처럼 보인다.
재봤는지 아닌지는 파일에 안 남는다. 그래서 지금은 실측한 값에 날짜와 기준 버전을 같이
적는다. “2026-08-26, ECC d8409a4 기준” 처럼.

그래서 무엇을 바꿨나

이 세 건을 겪고 나서 규칙 쓰는 방식을 바꿨다.

숫자에는 출처와 날짜를 같이 적는다. 안 적힌 숫자는 다음에 인용할 때 또 검증해야 한다.

남의 도구를 가리키는 규칙에는 근거 위치를 적는다. “ralph 는 ultrawork 를 포함한다”가
아니라 “ralph/SKILL.md:13 이 wraps 라고 명시” 라고 쓴다. 그러면 다음에 확인할 때 어디를
볼지 알 수 있다.

버전이 올라가면 그 도구를 가리키는 규칙을 훑는다. 자동으로 깨지지 않으므로 사람이 봐야
한다. 지금은 이걸 자동화하지 못했다 — 스킬 목록을 대조해 없는 이름을 찾아내는 검사는 만들
수 있을 것 같은데, 아직 안 만들었다.

한계

이 글에는 전후 수치가 없다. 규칙을 고쳐서 무엇이 얼마나 좋아졌는지 재지 못했다.

첫 번째 건은 커밋 자체가 “동작 변화 없음”이라고 적고 있으니 잴 것이 없다. 두 번째 건은
깨져 있던 걸 고쳤지만, 그 규칙이 없는 이름을 가리키던 사흘 동안 무엇이 얼마나 잘못됐는지는
로그가 없어 모른다. 세 번째는 문서 정확성 문제다.

그래서 “이렇게 하니 산출물이 몇 % 좋아졌다”고는 못 쓴다. 쓸 수 있는 건 하나다 —
틀린 줄 몰랐던 규칙 세 개를 찾아서 고쳤고, 셋 다 에러 없이 조용히 틀려 있었다.

  1. 커밋 618e6a4 (2026-08-10) “OMC 모드 선택 기준을 완주 여부로 교체”. 근거는 설치본 oh-my-claudecode 4.15.7 기준. 

  2. 커밋 5609c92 (2026-08-27) “자동 실행 규칙이 가리키던 ultrawork 를 execute 로 교체”. 

  3. 커밋 d13fda9 (2026-08-27) “rules/common 제외 근거의 ≈40K 를 실측값으로 교체”. 상세는 claude/plugins-manifest.md