- Hybrid BM25 + HNSW vector search with context enrichment - Knowledge graph with entities, relations, and community detection - Host-following LLM route with fallback backends - 3-tier lint system (static + HNSW dup + contradiction detection) - Q&A Synthesis (Karpathy LLM Wiki pattern) - 16 MCP tools for agent-driven workflows - Incremental wiki generation with checkpointing - SQLite-backed item store with FTS5 + vector indexes
9.7 KiB
9.7 KiB
PLAN-WIKI-LINT.md — 카파시 스타일 위키 린트 시스템
상태: ✅ 완료 (Phase 1~3 전체 구현)
작성: 2026-04-18
완료: 2026-04-18
목표: hw_lint를 frontmatter 검사에서 → 카파시 LLM-Wiki의 린트 개념에 맞는 종합 위키 정합성 검사로 확장
1. 배경
Andrej Karpathy의 LLM-Wiki에서 린트(Lint)는 세 가지 핵심 작업 중 하나:
- 인제스트: 소스 추가 → 위키 업데이트 (이미 구현됨)
- 쿼리: 위키 질문/검색 (이미 구현됨)
- 린트: 페이지 간 모순, 고립 페이지, 정합성 점검 ← 이거 지금 부실함
현재 hw_lint는 frontmatter 누락/타입 오류만 잡는다. 위키가 500페이지 규모로 커지면 의미 없는 검사.
2. 현재 코드베이스 현황
이미 있는 것 (재사용)
| 컴포넌트 | 파일 | 상태 |
|---|---|---|
| 기본 린트 | src/vault/lint.ts |
frontmatter만 검사. 확장 필요 |
| 모순 감지 (규칙) | src/wiki/contradiction.ts |
상태/날짜/사실 충돌 감지 + contradictions 테이블 |
| 모순 핸들러 | handleContradictions() |
list/get/resolve/scan/stats 구현됨 |
| KG (엔티티/관계) | src/db/kg.ts |
링크 기반 고립 탐지 가능 |
| HNSW 벡터 | src/search/hnsw.ts + vector.ts |
의미적 중복 탐지 가능 |
| FTS5 | src/db/items.ts |
키워드 중복 탐지 가능 |
| content_hash | src/db/hashing.ts |
구버전 감지 가능 (getChangedItems) |
| 위키 파일 wikilink 파싱 | src/wiki/generator.ts |
[[]] 추출 로직 있음 |
새로 만들어야 할 것
| 컴포넌트 | 설명 |
|---|---|
src/wiki/linter.ts |
종합 린트 오케스트레이터 (새 모듈) |
확장된 LintResult 타입 |
세부 이슈 카테고리 포함 |
handleLint() 확장 |
기존 frontmatter + 새 린트 항목 통합 |
hw_lint 스키마 확장 |
checks 파라미터로 선택적 실행 |
3. 린트 검사 항목
Tier 1: LLM 없이 가능 (빠름, 무료)
3.1 고립 페이지 (Orphan Pages)
- 정의: incoming wikilink가 0인 위키 페이지
- 방법:
~/wiki/wiki/하위 모든 .md 파일 수집- 각 파일에서
[[]]wikilink 추출 - 링크 대상 역인덱스 구축 (target → [source files])
- incoming link가 0인 파일 = 고립
- 예외:
index.md,overview.md,log.md는 글로벌 네비게이션이므로 제외 - 출력:
{ file, title }[]
3.2 파손 링크 (Broken Wikilinks)
- 정의:
[[]]로 링크했는데 대상 파일이 없음 - 방법:
- 모든 위키 파일에서
[[]]추출 - 각 링크 대상이
~/wiki/wiki/<target>.md또는~/wiki/<target>.md에 존재하는지 확인
- 모든 위키 파일에서
- 출력:
{ source, target, line_number }[]
3.3 구버전 페이지 (Stale Pages)
- 정의: 원본 아이템 content가 변경됐는데 위키가 재생성 안 됨
- 방법:
getChangedItems(db)활용 — 이미 content_hash 비교 구현됨 - 출력:
{ item_id, title, wiki_slug, hash_changed_at }[]
3.4 미생성 아이템 (Ungenerated Items)
- 정의: DB에 아이템은 있는데 위키 페이지가 아직 없음
- 방법:
getWikiGenerationCounts(db)활용 - 출력:
{ total, ungenerated }[]
3.5 Frontmatter 검사 (기존)
- 기존
lintVault()그대로 유지 - frontmatter 누락, type 불일치, title 누락 체크
Tier 2: HNSW 활용 (빠름, 로컬 연산)
3.6 의미적 중복 (Semantic Duplicates)
- 정의: 내용이 거의 같은 위키 페이지가 여러 개
- 방법:
- 모든 위키 페이지 임베딩 (이미 벡터 DB에 있으면 재사용)
- HNSW에서 각 페이지의 최근접 이웃 조회
- cosine distance < 0.15 (임계값 튜닝 필요)인 쌍을 중복 후보로 표시
- 출력:
{ page_a, page_b, similarity_score }[] - 주의: 같은 카테고리 내에서만 비교하면 잡음 감소
Tier 3: LLM 필요 (느림, 토큰 소모)
3.7 의미적 모순 (Semantic Contradictions)
- 정의: 같은 주제를 다루는데 서로 다르게 서술
- 방법:
- Tier 2의 중복 후보 중 similarity가 높은 쌍 (0.15~0.4 구간)을 모순 후보로
- 후보 쌍만 LLM에게 비교 요청
- 프롬프트: "두 페이지가 모순되는 내용을 포함하는지 검사. 모순 있으면 요약, 없으면 '모순 없음'"
- 기존
contradictions테이블에 결과 저장
- 출력: 기존 Contradiction 인터페이스 재사용
- 선택 옵션:
hw_lint --with-llm또는checks: ["contradictions"]시에만 실행
4. 구현 설계
4.1 새 모듈: src/wiki/linter.ts
// 타입
interface LintOptions {
checks?: LintCheckType[]; // 비어있으면 전체
withLlm?: boolean; // Tier 3 포함 여부
}
type LintCheckType =
| "orphans" // 3.1
| "broken_links" // 3.2
| "stale" // 3.3
| "ungenerated" // 3.4
| "frontmatter" // 3.5
| "duplicates" // 3.6
| "contradictions" // 3.7 (LLM)
interface LintReport {
timestamp: string;
total_checks: number;
duration_ms: number;
results: {
orphans: OrphanResult;
broken_links: BrokenLinkResult[];
stale: StaleItem[];
ungenerated: { total: number; count: number };
frontmatter: string[]; // 기존 이슈
duplicates: DuplicatePair[];
contradictions: Contradiction[]; // LLM 결과
};
summary: {
critical: number; // 파손 링크, 구버전
warnings: number; // 고립, 중복
info: number; // 미생성
};
}
4.2 메인 함수
export async function lintWiki(
config: WikiEngineConfig,
options?: LintOptions
): Promise<LintReport>
내부 흐름:
- DB 연결, vault 경로 확보
- 모든 위키 파일 스캔 → 파일 목록 + wikilink 역인덱스 구축
- options.checks에 따라 각 검사 함수 호출
- 결과 취합 → LintReport 반환
4.3 핸들러 확장
기존 handleLint()를 확장:
export async function handleLint(
args: {
checks?: string[];
withLlm?: boolean;
},
config: WikiEngineConfig
): Promise<string>
4.4 MCP 툴 스키마 확장
hw_lint의 inputSchema에 파라미터 추가:
{
"checks": {
"type": "array",
"items": { "type": "string" },
"description": "특정 검사만 실행: orphans, broken_links, stale, ungenerated, frontmatter, duplicates, contradictions"
},
"withLlm": {
"type": "boolean",
"description": "LLM 기반 모순 감지 포함 (default: false)"
}
}
5. 파일 변경 목록
| 파일 | 변경 유형 | 설명 |
|---|---|---|
src/wiki/linter.ts |
신규 | 종합 린트 오케스트레이터 |
src/types.ts |
수정 | LintReport, LintOptions 등 타입 추가 |
src/mcp/handlers.ts |
수정 | handleLint() 시그니처 변경, 새 린트 호출 |
src/mcp/tools.ts |
수정 | hw_lint 스키마에 checks/withLlm 추가 |
src/mcp-server.ts |
수정 | handleLint 호출부 args 전달 |
건드리지 않는 파일 (안정성):
src/vault/lint.ts→ 기존 frontmatter 검사 함수 그대로, 새 linter.ts에서 호출만 함src/wiki/contradiction.ts→ 기존 모순 시스템 그대로, 새 linter.ts에서 결과만 참조src/wiki/generator.ts→ wikilink 추출 유틸만 import
6. 구현 순서
Phase 1: 인프라 (Tier 1)
src/types.ts에 LintReport, LintOptions 타입 추가src/wiki/linter.ts신규 생성lintOrphans()구현 — wikilink 역인덱스 + 고립 탐지lintBrokenLinks()구현 — 파손 링크 탐지lintStale()구현 — getChangedItems 래핑lintUngenerated()구현 — getWikiGenerationCounts 래핑- 기존
lintVault()를 frontmatter 서브체크로 통합 handleLint()확장 + 스키마 업데이트- 빌드 + 스모크 테스트
Phase 2: 의미 검사 (Tier 2)
lintDuplicates()구현 — HNSW 유사도 기반- 임계값 튜닝 (0.15 시작)
Phase 3: LLM 모순 (Tier 3)
lintContradictions()구현 — LLM 프롬프트- 기존 contradictions 테이블과 통합
--withLlm플래그 연동
7. 검증 기준
hw_lint실행 시 7가지 검사(orphan, broken, stale, ungenerated, frontmatter, duplicates, contradictions) 결과 반환- 고립 페이지가 실제로 incoming link 0인 파일만 포함
- 파손 링크가 실제로 존재하지 않는 대상만 포함
- 기존
hw_contradictions기능이 영향 없이 동작 npm run build에러 없음- Phase 1은 LLM 호출 없이 5초 이내 완료 (500페이지 기준) → 266ms
- Phase 2 (HNSW duplicates) 벡터 유사도 ≥ 0.95 → 228쌍 검출, 1.7s
- Phase 3 (contradictions) 룰 기반 검출 동작,
--with-llm옵션 연동
8. 구현 결과
커밋
6c711a7— Phase 1 + DB fix + Codex 모듈 (44파일, +10,479줄)53b9a32— Phase 2 + Phase 3 (2파일, +214줄)
스모크 테스트 결과 (2026-04-18)
Duration: 1727 ms | Checks: 6
Orphans: 14 | Broken links: 53 | Stale: 0
Ungenerated: 0/504 | Duplicates: 228 | Contradictions: 0
Summary: { critical: 53, warnings: 242, info: 0 }
향후 개선
- LLM 기반 모순 검출: 현재 룰 기반만 구현,
--with-llm시 LLM 프롬프트로 의미적 모순 검출 추가 가능 - 중복 임계값 튜닝: 데이터셋 성격에 따라 0.95~0.98 범위에서 조정
9. 위험 요소
| 위험 | 대응 |
|---|---|
| wikilink 파싱 불완전 (이스케이프, 중첩) | generator.ts 기존 파싱 로직 재사용 |
| HNSW 임계값 튜닝 어려움 | 0.15에서 시작, 실패 시 조정 |
| 대규모 위키에서 린트 속도 | 파일 스캔은 I/O-bound, 병렬화 불필요 |
| LLM 모순 감지 토큰 비용 | Tier 3은 명시적 opt-in만 |