MuRing-KB 개발기 2 (검증 편)

쌓아둔 지식을 다시 분류하고 검색과 실제 재사용으로 쓸모를 확인했다
calendar icon

2026년 9월 29일

조회 4

tag icon

지식 저장소를 만들고 나니 이번에는 다른 게 마음에 걸렸다. 기록은 쌓이는데, 이걸 지식이라고 불러도 되는지 자신이 없었다. 특정 프로젝트에서 고친 오류와 설치 방법, 내가 선호하는 작업 방식이 같은 폴더에 들어 있었다.

지난 글에서는 Markdown과 Git으로 MuRing-KB를 만들고, 후보를 모아 검토하는 흐름까지 정리했다. 그 뒤로 문서가 늘었다. 이번에 내용을 다시 들여다보기 시작했을 때 knowledge/에는 노트가 31개 있었다. 그런데 파일이 늘어난 만큼 다음 작업이 편해졌는지는 바로 답하기 어려웠다.

"이건 지식 저장소인가, 잘 정리한 작업 일지인가."

나는 좀 더 범용적인 지식이 쌓이기를 바랐다. 프로젝트 이름과 특정 파일 경로를 알아야만 이해되는 메모가 많아지면, 결국 그 프로젝트를 다시 열어보는 것과 다르지 않을 것 같았다. 그래서 등록된 내용을 다시 분류하고, 자연어로 찾아보고, 실제 다른 프로젝트에 적용하는 데까지 확인하기로 했다.


무엇을 지식으로 남길 것인가

처음 의심한 건 주제의 크기였다. 너무 작은 오류를 기록하고 있으니, 더 넓고 거시적인 내용으로 바꿔야 하는 것 아닐까. 하지만 하나씩 읽어보니 주제가 좁다는 이유만으로 버릴 수는 없었다. 작은 오류에서도 다른 화면에 그대로 적용할 판단 기준이 나왔다.

반대로 제목이 넓다고 쓸모가 있는 것도 아니었다. "UI를 일관되게 만든다"는 말은 틀리지 않지만, 다음 수정에서 무엇을 확인해야 할지는 알려주지 않는다. 공통 컴포넌트를 고쳤더라도 비슷하게 생긴 다른 화면이 그 컴포넌트를 안 쓸 수 있다는 기록은 훨씬 구체적이었다.

프로젝트 이름을 지워도 판단이 남아야 했다

기준을 세 가지로 나눴다. 미래 작업에서 무슨 판단을 바꾸는지, 그 주장을 뒷받침하는 근거가 있는지, 그리고 어디에 보관해야 하는지였다. 등록 가치·정확성·보관 위치를 따로 보니 선택이 조금 쉬워졌다.

예를 들어 특정 앱의 WSL 제목 생성 패치는 해당 앱의 버전과 구현을 알아야 쓸 수 있었다. 그 사례 자체는 남길 가치가 있었지만, 범용 지식 폴더의 중심에 둘 내용은 아니었다. 반면 업데이트로 로컬 패치가 사라질 수 있으니 원본 식별과 적용 조건을 확인한다는 원리는 다른 앱에도 적용할 수 있었다.

내용둘 곳이유
다른 작업에도 쓰는 원리와 판단 기준knowledge/다음 문제를 푸는 데 재사용한다
설치·사용·관리 순서guides/따라 하는 절차의 원본을 둔다
내가 선택한 작업 방식preferences/개인 선택을 보편 규칙과 구분한다
특정 프로젝트의 맥락과 사례projects/버전과 제약을 잃지 않는다
선택한 이유와 포기한 대안decisions/나중에 결정을 다시 검토한다

기존 노트 31개 중 5개를 역할에 맞는 폴더로 옮겼고, 26개는 지식 노트로 남겼다. 설치 가이드와 Git 동기화 절차, 화면 상호작용에 대한 내 선호가 대표적인 이동 대상이었다. 삭제해서 숫자를 줄이기보다, 읽는 사람이 문서의 성격을 먼저 알게 하려는 변경이었다.

한계를 뒤에만 붙이면 앞의 단정이 남았다

문서를 옮기는 것만으로는 부족했다. 제목과 핵심에서는 원인을 확정해 놓고, 맨 아래에 "정확한 원인은 확인하지 않았다"고 적힌 문장은 읽는 순서에 따라 전혀 다른 지식이 됐다. 중요한 제한은 해당 주장 바로 옆으로 올렸다.

Orca 내장 브라우저의 화면 멈춤 기록이 그랬다. 당시 후보에는 rAF 콜백이 관찰 시간 안에 실행되지 않았고, React 내부 함수를 직접 호출한 뒤 내용이 나타났다는 결과가 있었다. 이 관찰은 남길 만했다. 하지만 그것만으로 모든 멈춤의 원인을 확정하거나, 기다리면 영원히 안 풀린다고 쓸 수는 없었다.

내부 함수를 호출해 화면이 나타난 것도 정상 로딩을 확인한 것과는 달랐다. 진단하려고 상태를 바꾼 결과였기 때문이다. 그래서 실제 표시 중인 탭에서도 재현되는지, DOM에 내용이 있는 것과 사용자에게 보이는 것이 같은지 확인하는 절차만 가이드에 반영했다. 자세한 측정과 당시 표현은 후보 보관본에 남겼다.

이런 구분을 하고 나니 범용성은 프로젝트 이름을 지우는 일이 아니라는 생각이 들었다. 어디까지 적용해도 되는지 설명하는 것에 가까웠다. 사례를 모두 빼면 근거가 사라지고, 사례의 선택을 규칙으로 올리면 적용 범위가 부풀었다.


폴더를 옮기니 이력이 따라오지 않았다

문서 정리는 파일 이동으로 끝날 줄 알았다. 그런데 MuRing-KB에는 문서를 실제 작업에 적용했을 때 남기는 사용 기록이 있었다. 그 기록이 예전 경로를 가리키고 있었다. 검색 결과도 새 위치로 나와야 했고, 과거 사용 횟수는 그대로 이어져야 했다.

파일 경로를 전부 새 값으로 고치면 겉보기에는 맞출 수 있었다. 하지만 그렇게 하면 과거 기록을 지금의 구조에 맞춰 다시 쓰게 된다. 당시 어떤 문서를 읽었는지 확인하려고 남긴 해시와 경로인데, 정리할 때마다 바꾸는 것은 목적과 어긋났다.

과거 기록 대신 이동표를 바꿨다

과거 이벤트는 그대로 두고 document-moves.json에 이전 경로와 현재 경로를 연결했다. 읽거나 집계할 때 이동표를 따라가게 했다. 문서를 다시 옮겨도 경로 연결을 이어서 현재 원본을 찾도록 했다.

{
  "version": 1,
  "moves": {
    "knowledge/using-kb-with-ai.md": "guides/using-kb-with-ai.md",
    "knowledge/git-sync-workflow.md": "guides/git-sync-workflow.md",
    "knowledge/frontend-mcp-setup.md": "guides/frontend-mcp-setup.md",
    "knowledge/ui-interaction-preferences.md": "preferences/ui-interaction-preferences.md",
    "knowledge/orca-wsl-auto-rename.md": "projects/orca-wsl-auto-rename.md"
  }
}

이 표는 문서가 통째로 이동할 때만 쓴다. 한 문서의 일부를 떼어 새 지식으로 만들었다면 새 문서다. 과거 문서의 사용 횟수를 양쪽에 복제하면 실제로 한 번 적용한 일을 두 번 쓴 것처럼 세게 된다. 후보를 정식 지식으로 승격하는 것도 같은 이유로 별도 문서로 취급했다.

이관 전후에는 당시 사용 이벤트 12개의 SHA-256과 집계를 비교했다. 이벤트 내용은 모두 같았고, 기록된 작업 10건과 프로젝트 2개도 유지됐다. 후보 52개 역시 이동 때문에 바뀐 링크를 제외하면 원문이 같은지 대조했다.

링크는 맞고 이력도 이어지는 걸 확인한 뒤에야 구조 변경을 끝냈다. 다만 이 이동표가 외부의 Markdown 링크까지 바꿔주는 것은 아니다. 다른 저장소나 예전 대화에 박힌 경로는 따로 확인해야 했다.


문서가 있어도 검색이 놓쳤다

분류를 고친 다음에는 검색을 비교했다. 파일명이나 정확한 제목을 넣어서 찾는 것은 쉬웠다. 문제를 겪는 순간에는 파일명을 모르니, 증상을 말하는 질문으로도 나오는지가 더 중요했다.

"화면 주소를 바꾸면 아직 완성하지 않은 한글이 깨져" 같은 질문을 넣었다. 관련 노트는 있었지만 이전 검색에서는 상위 5개 안에 들어오지 않았다. 저장돼 있다는 것과 필요할 때 발견된다는 것은 별개였다.

"정답을 아는 사람만 검색할 수 있으면 반쪽짜리 아닌가."

모델을 바꾸기 전에 검색어 처리를 고쳤다

MuRing-KB는 키워드 검색과 로컬 의미 검색의 순위를 합친다. 이번에는 임베딩 모델이나 순위 결합 가중치를 바꾸지 않았다. 한국어 검색어를 처리하는 부분부터 살폈다.

짧고 흔한 말이 본문의 부분 문자열과 맞으면서 잡음이 생겼다. 같은 검색어가 반복되면 점수가 중복으로 쌓이는 문제도 있었다. 조사 때문에 표면 형태가 달라지는 경우를 다루되, 너무 넓게 잘라내면 관계없는 문서까지 올라왔다.

그래서 주격·목적격 조사인 이·가·을·를을 제한적으로 처리했다. 조사 앞에 두 음절 이상이 남을 때 원래 토큰과 함께 대조하고, 둘을 별개의 검색어로 세지는 않았다. 일반적인 기능어와 중복 가산도 줄였다. 모든 조사와 동사 활용을 다루는 형태소 분석기를 만든 것은 아니었다.

적용 범위를 넓히는 안도 비교했지만 잡음과 회귀가 생겨 넣지 않았다. 검색이 놓치는 질문이 있다고 그 질문에 맞는 단어를 지식 본문에 계속 끼워 넣지도 않았다. 문서는 사람이 이해할 원본이고, 검색 평가를 통과시키기 위한 단어 목록이 되면 곤란했다.

같은 원문과 같은 의미 검색 응답에 이전 코드와 수정 코드를 적용했다. 아래는 표현이 바뀐 질문에서 정답이 상위 3개 안에 들어온 수다.

질문 묶음질문 수이전 키워드 → 수정 후이전 결합 → 수정 후
앞선 비교 질문166 → 911 → 13
기존 평가 질문123 → 58 → 10
추가 질문125 → 810 → 11

이전 결합 검색에서 상위 3개 안에 있던 정답이 밖으로 밀린 경우는 없었다. 그렇다고 모든 질문의 개별 순위가 오른 것은 아니었다. 새 PC에서 기록을 이어 쓰고 싶다는 질문은 여전히 상위 5개 밖이었고, 공용 버튼을 고쳤을 때 확인 범위를 묻는 질문도 4위에 머물렀다.

평가 코드도 옛 경로를 보고 있었다

검색을 비교하다 보니 평가 쪽에도 문제가 있었다. 기존 평가 질문 20개 중 16개의 정답 경로가 현재 원본 위치에 없었다. 문서는 옮겼는데 평가 코드는 예전 경로를 정답으로 들고 있었다. 검색이 맞는 문서를 찾아도 오답으로 셀 수 있는 상태였다.

평가를 시작하기 전에 이동표로 정답 경로를 해석하고, 실제 검색 범위에 있는지 확인하도록 바꿨다. 제목이나 문서 범위가 달라진 질문도 따로 검토했다. 과거 오류 문구가 보관 후보에만 남은 질문은 --all 범위로 찾도록 했다.

전체 자동 검사 120개와 실제 모델 질문 56개 평가를 통과했다. 하지만 56개 전부를 정확히 맞혔다는 뜻은 아니다. 정확한 제목·파일명, 표현 변형 질문의 기준 적중률, 미관련 결과 표시 등 정해 둔 통과 조건을 만족했다는 뜻이다. 위 표의 추가 질문도 개선 도중 참고했으므로 독립적인 성능 검증이라고 부르지 않았다.


다른 프로젝트에 써봤다

검색 점수가 좋아져도 여전히 확인하지 못한 게 있었다. 찾은 문서가 실제 작업을 바꾸는가. 그래서 블로그에서 얻은 공통 UI 검증 기준을 개발 환경 설치 앱에 적용했다. 전혀 다른 제품이지만 정상 화면만 보고 끝내지 말아야 한다는 판단은 옮겨 쓸 수 있었다.

기존 UI 검사 11개는 통과했다. 좁은 창과 넓은 창에서 단계별 레이아웃도 확인했다. 그다음 초기 데이터를 읽는 요청에 실패를 넣어봤다. 여기서 화면이 멈췄다.

폴링 성공은 초기화 성공이 아니었다

앱은 catalog와 snapshot을 함께 읽은 뒤 초기 설정을 만들었다. 둘 중 하나가 실패하면 오류 상태를 저장했지만, 필수 설정이 없을 때 로딩 화면을 먼저 반환했다. 그 아래의 오류 UI까지 도달하지 못한 것이다.

문제를 줄이면 이런 구조였다. 실제 코드 전체가 아니라, 실패를 가린 분기만 남긴 예시다.

Promise.all([readCatalog(), readSnapshot()])
  .then(([catalog, snapshot]) => initialize(catalog, snapshot))
  .catch(setError);

if (!config) return <Loading />;

return <Screen error={error} />;

더 헷갈린 건 snapshot 폴링이었다. 첫 조회가 실패한 뒤 후속 폴링이 성공해도 config는 생기지 않았다. 주기 조회가 갱신하는 상태와 첫 초기화가 만드는 상태가 달랐기 때문이다. 데이터가 다시 들어오고 있다는 사실만 보면 복구될 것 같지만, 정상 화면의 진입 조건은 계속 충족되지 않았다.

초기화 분기 안에 오류 표시와 재시도를 두었다. 이 앱에서는 재시도할 때 두 필수 조회를 함께 다시 실행하고, 초기화가 끝난 뒤 폴링을 시작하도록 했다. 반복 실패와 느린 재시도, 정상 복구, 폴링 재개, 설치 작업이 실행되지 않는 것까지 검사했다.

수정 뒤 단위 검사 14개와 UI 검사 13개가 통과했다. 신규 실패 검사 2개에는 최소 창 크기인 900×650에서 버튼이 보이고 가로로 넘치지 않는지도 추가했다. 다만 실제 Windows IPC 장애를 겪은 기록은 아니었다. 실제 빌드 렌더러에서 IPC 대역으로 실패를 주입해 확인했고, 새 EXE 패키징과 설치는 이 검증에 포함하지 않았다.

고친 코드보다 복구 경계를 남겼다

이 결과는 다시 지식 후보로 모았다. 정식 노트로 옮길 때는 "모든 조회를 무조건 다시 실행한다"는 규칙으로 쓰지 않았다. 성공한 결과를 보존할지 전체를 다시 읽을지는 데이터의 유효기간과 일관성 요구에 따라 다르다. 초기화 전에 폴링을 멈추는 것도 이번 앱의 구현 선택이었다.

남긴 원리는 필수 데이터가 없어도 오류와 복구 경로에 접근할 수 있어야 한다는 것이었다. 일부 상태를 갱신하는 폴링을 전체 초기화의 복구로 착각하지 않는다는 점도 함께 적었다. 설치나 저장처럼 부작용이 있는 작업의 재실행과는 구분했다.

노트 이름은 ui-initialization-recovery.md로 정했다. 실제 코드와 검사 근거를 연결하고, 계속 응답하지 않는 요청의 시간 제한이나 오래된 응답 처리까지 모두 검증한 것은 아니라고 명시했다. 이번에는 문서가 실제 수정으로 이어졌고, 그 수정에서 다시 다른 화면에 쓸 수 있는 판단이 나왔다.


결과

구조 변경과 검색 개선은 0.13.1에 정리했다. 마지막에는 새 초기화 복구 노트와 보완한 가이드가 자연어 질문으로 발견되는지도 확인했다. 초기 조회 실패, 여러 API 중 하나의 실패, 폴링 후에도 복구되지 않는 화면처럼 표현을 바꿨다.

설치 재시도와 Orca 화면 지연을 묻는 질문도 섞었다. 이름이 비슷한 문서가 무조건 올라오는지 보려는 비교였다. 작은 표본이지만 기본 결합 검색에서는 여섯 질문 모두 의도한 문서가 1위였다.

확인한 질문키워드 검색기본 결합 검색
조회 실패 후 계속 로딩1위1위
여러 API 중 하나가 실패5위1위
폴링해도 초기 화면 미복구1위1위
화면 초기화 실패 재시도1위1위
기존 설정을 보존하며 설치 재실행1위1위
Orca에서 DOM은 있지만 로딩 지속2위1위

이 여섯 질문으로 전체 검색 품질이 좋다고 말할 수는 없다. 모델 로딩 지연도 이번에 개선하지 않았다. 관련 자료가 없는 질문에도 의미상 비슷한 결과가 나올 수 있어서, 검색 결과는 여전히 원문과 적용 조건을 확인하며 읽어야 했다.

그래도 처음의 의심에 답할 근거는 생겼다. 문서를 찾아봤다는 사실 대신, 그 문서 때문에 어떤 검사를 더 했고 무슨 오류를 찾았는지 설명할 수 있게 됐다. 단순 검색 검증은 실제 적용 횟수에 더하지 않았고, 같은 작업의 후속 수정도 별개의 재사용 실적으로 부풀리지 않았다.

이전에 헷갈렸던 것이번에 구분한 것
정식 지식 폴더에 들어 있으면 모두 같은 성격원리·절차·선호·프로젝트 사례
파일을 옮기면 과거 기록도 수정과거 이벤트 보존과 현재 경로 연결
검색 평가 통과는 정답을 전부 찾았다는 뜻질문별 순위와 통과 조건을 따로 확인
문서를 읽었으면 재사용실제 판단과 수정에 적용한 근거를 기록

느낀점

  • 범용성은 제목의 크기로 정해지지 않았다. 작은 오류라도 적용 조건과 판단 방법이 남으면 다른 프로젝트에 쓸 수 있었다. 넓은 주제라도 다음 행동을 바꾸지 못하면 쓸모를 설명하기 어려웠다.
  • 분류를 고치면 이력도 확인해야 했다. 폴더를 보기 좋게 나누는 일보다 과거 기록을 보존하면서 현재 원본을 찾게 만드는 일이 더 까다로웠다.
  • 평가 도구도 틀릴 수 있었다. 문서를 옮긴 뒤 정답 경로를 그대로 두면 검색 결과를 잘못 채점한다. 점수를 보기 전에 무엇을 정답으로 세고 있는지부터 확인해야 했다.
  • 재사용은 다음 작업에서 드러났다. 블로그에서 정리한 검증 기준이 설치 앱의 초기화 오류를 찾는 데 쓰였다. 문서 개수가 늘어난 것보다 이 사례가 저장소를 계속 운영할 이유에 가까웠다.

아직 모든 질문에서 필요한 문서가 잘 나오는 것은 아니다. 다른 PC에서 같은 흐름이 이어지는지도 더 확인해야 한다. 그래도 이제는 기록을 얼마나 모았는지보다, 다음 작업에서 어떤 판단을 덜 놓쳤는지를 보려고 한다.

지식 저장소를 만들 때는 잊어버리지 않는 게 목표였다. 써보니 기억한 내용을 어디까지 믿어도 되는지 구분하는 일도 그만큼 중요했다.

좋아요 —
hamburger icon

무링의 개발 블로그

FDE를 향하는 개발자


댓글

GitHub 계정으로 로그인하면 댓글을 남길 수 있습니다.

로그인

연관된 글