Skip to content
게으른 엔지니어의 기술 블로그
Go back

정답은 이미 있었고, 안 쓴 쪽이 문제였다

고치라는 지시부터, 다시 봐야 했다 · 5/5편

4편에서 설계 문서에 열려 있던 질문이 조용히 결정돼 있던 걸 다뤘다. 이번 편은 버그 하나를 고치는 접근 자체를 두 번 정정당한 이야기다.

위키링크가 짧게 남는다

/split 실행 결과를 검증하다가, 생성된 노트 본문에 [[결정적 대화|결정적 대화]]처럼 전체 경로 없이 제목만 있는 링크가 몇 개 보였다. 이 vault는 어디서든 [[wiki/폴더/제목|표시텍스트]] 형식을 쓰는 게 관례라, 이건 그 관례를 깨는 것이었다. 같은 제목이 다른 폴더에도 있으면 어느 파일이 열릴지 불명확해지는 위험도 있었다.

원인을 추적하니 두 갈래였다. 하나는 /ingest가 배치 안에서 제목이 충돌해 _dupN 접미사가 붙은 노트를 다른 노트가 인용할 때, 코드가 전체 경로를 이미 알고 있으면서도 파일명만 잘라 쓰는 순수 버그였다. 이건 바로 고치면 되는 문제였다. 다른 하나는 /split이 실행되면서 본문에 기존 노트를 인용할 때, 모델이 그냥 짧은 제목으로 쓰는 경우였다. 이쪽이 더 어려웠다.

첫 번째 제안: 사후에 복구하기

“베어 제목이 실제 파일 하나와 유일하게 매칭되면 전체 경로로 승격하고, 아니면 그대로 둔다”는 안을 냈다. 두 함수(하나는 분할, 하나는 ingest)에 이미 “이 링크가 유효한 파일을 가리키는가”를 확인하는 로직이 있어서, 그 판정 결과를 “전체 경로로 재작성”까지 확장하면 된다는 논리였다.

바로 정정당했다. “여러 파일 매칭을 그대로 둘 거면 이것도 그대로 두면 되지, 지금 그 제안은 내가 허락이 안 되네.” 실제로 지금 테스트 vault를 스캔해보니 진짜 basename 충돌은 0건이었다. 그런데 그건 이 vault가 아직 작아서였다 — 노트가 주차 폴더별로 계속 쌓이면 같은 제목이 다른 주차에 실제로 생길 수 있다. “드물어서 괜찮다”는 근거는 성립하지 않았다.

두 번째 시도: 근거를 다시 세워봤다

모호한 경우는 링크 텍스트만으로 어느 쪽을 의미했는지 판단할 방법이 원천적으로 없다는 쪽으로 다시 정리했다. 이럴 땐 하나를 임의로 골라 채우는 게, 지금처럼 베어 상태로 두는 것보다 더 나쁠 수 있다 — 잘못 고른 확신을 고정시켜버리는 셈이니까. 그래서 fallback은 “드문 케이스라 안 건드려도 그만”이 아니라 “여기선 안 건드리는 게 맞는 선택”이라는 논리로 방향을 바꿨다.

여기서 두 번째 질문이 왔다. “다르게 생각해보자. 어쨌든 연결을 하겠다면 어떤 노트가 있는지 더 위에서 정보를 줄 거잖아. 그 정보를 바탕으로 링크를 만들 텐데, 그걸 알 방법이 없다는 건 정보 주는 쪽에서 베어 이름을 주는 건가?”

코드를 다시 열어보니, 정답은 이미 있었다

이 질문을 받고서야 확인했다. /refactor 제안을 생성할 때 모델에게 주는 카탈로그는 노트마다 “경로: wiki/2026/08/WeekOf31/결정적 대화.md”처럼 전체 경로를 첫 줄에 그대로 준다. 모델은 “연결 설계” 문단을 쓸 때 이미 이 정보를 눈앞에 두고 있었다. 그런데 프롬프트의 실제 지시는 “추천하는 상호 위키링크 방향성” 한 줄뿐이라, “경로 필드를 그대로 써라”는 명시가 없었다 — 그래서 모델이 사람이 읽기 편한 짧은 제목으로 썼다.

그리고 그 reason 텍스트는 가공 없이 그대로 실행 프롬프트에 재주입돼 “이 계획을 그대로 실행하라”는 지시를 받는다. 화면 표시용으로 경로를 다시 짧은 이름으로 바꾸는 함수는 따로 있는데, 그건 UI 렌더링 전용이라 이 실행 경로엔 관여하지 않는다. 실행 단계 모델은 그저 이미 베어 이름으로 적힌 계획을 충실히 베껴 쓰고 있었던 것뿐이다. 모호성 문제 자체가 애초에 없었다 — 모델은 카탈로그에서 정확히 어느 노트인지 이미 알고 인용한 것이고, 그 정확한 정보가 reason 텍스트로 넘어가는 과정에서 그냥 안 쓰인 것뿐이었다.

결국 고친 건 사후 복구가 아니었다

최종 수정은 두 가지였다. /ingest의 dupN 리다이렉트는 이미 아는 전체 경로를 그대로 쓰게 코드를 고쳤다. /split 쪽은 제안 생성 프롬프트의 “연결 설계” 지시에 “카탈로그의 경로 필드를 그대로 써라”는 문장을 명시적으로 추가했다. 소스에서 처음부터 전체 경로로 생성되게 만드니, 실행 단계는 그걸 그대로 베껴 쓰기만 해도 자동으로 전체 경로 링크가 나온다. 사후에 베어 링크를 추론해서 복구하는 코드는 한 줄도 필요 없게 됐다.

남는 생각

두 번의 정정은 서로 다른 층위였다. 첫 번째는 “이 위험은 드물다”는 내 전제가 실측 앞에서 틀린 것이었고, 두 번째는 애초에 “사후에 추론해서 복구한다”는 접근 방향 자체가 잘못 짚은 것이었다. 두 번째 질문이 없었다면 “모호한 경우는 못 고친다”는 한계를 인정한 채로, 그래도 “일부는 고칠 수 있으니 낫다”는 절반짜리 수정을 밀어붙였을 것 같다. “정보가 이미 위에서 주어졌을 텐데, 그걸 못 쓰는 게 이상한 거 아니냐”는 질문 하나가, 고치는 방법이 아니라 고칠 자리 자체를 바꿔놓았다.


Share this post:

고치라는 지시부터, 다시 봐야 했다

  1. 1. 고치라는 지시부터, 다시 봐야 했다 1편 — 죽은 주석을 고치다가, 또 틀렸다
  2. 2. 고치라는 지시부터, 다시 봐야 했다 2편 — 가설은 반은 맞고 반은 틀렸다
  3. 3. 고치라는 지시부터, 다시 봐야 했다 3편 — 고치기 전에 한 번 더 물었다
  4. 4. 고치라는 지시부터, 다시 봐야 했다 4편 — 지우라는 지시와, 어떻게 지울지는 다른 질문이었다
  5. 5. 정답은 이미 있었고, 안 쓴 쪽이 문제였다