Files
HaBraid/docs/plans/PLAN-WIKI-LINT.md
Contributor 5d5336757d feat: HaBraid v0.1.0 — host-following memory visualization engine for Obsidian
- 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
2026-04-18 15:46:42 +09:00

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인 위키 페이지
  • 방법:
    1. ~/wiki/wiki/ 하위 모든 .md 파일 수집
    2. 각 파일에서 [[]] wikilink 추출
    3. 링크 대상 역인덱스 구축 (target → [source files])
    4. incoming link가 0인 파일 = 고립
  • 예외: index.md, overview.md, log.md는 글로벌 네비게이션이므로 제외
  • 출력: { file, title }[]
  • 정의: [[]]로 링크했는데 대상 파일이 없음
  • 방법:
    1. 모든 위키 파일에서 [[]] 추출
    2. 각 링크 대상이 ~/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)

  • 정의: 내용이 거의 같은 위키 페이지가 여러 개
  • 방법:
    1. 모든 위키 페이지 임베딩 (이미 벡터 DB에 있으면 재사용)
    2. HNSW에서 각 페이지의 최근접 이웃 조회
    3. cosine distance < 0.15 (임계값 튜닝 필요)인 쌍을 중복 후보로 표시
  • 출력: { page_a, page_b, similarity_score }[]
  • 주의: 같은 카테고리 내에서만 비교하면 잡음 감소

Tier 3: LLM 필요 (느림, 토큰 소모)

3.7 의미적 모순 (Semantic Contradictions)

  • 정의: 같은 주제를 다루는데 서로 다르게 서술
  • 방법:
    1. Tier 2의 중복 후보 중 similarity가 높은 쌍 (0.15~0.4 구간)을 모순 후보로
    2. 후보 쌍만 LLM에게 비교 요청
    3. 프롬프트: "두 페이지가 모순되는 내용을 포함하는지 검사. 모순 있으면 요약, 없으면 '모순 없음'"
    4. 기존 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>

내부 흐름:

  1. DB 연결, vault 경로 확보
  2. 모든 위키 파일 스캔 → 파일 목록 + wikilink 역인덱스 구축
  3. options.checks에 따라 각 검사 함수 호출
  4. 결과 취합 → 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)

  1. src/types.ts에 LintReport, LintOptions 타입 추가
  2. src/wiki/linter.ts 신규 생성
  3. lintOrphans() 구현 — wikilink 역인덱스 + 고립 탐지
  4. lintBrokenLinks() 구현 — 파손 링크 탐지
  5. lintStale() 구현 — getChangedItems 래핑
  6. lintUngenerated() 구현 — getWikiGenerationCounts 래핑
  7. 기존 lintVault()를 frontmatter 서브체크로 통합
  8. handleLint() 확장 + 스키마 업데이트
  9. 빌드 + 스모크 테스트

Phase 2: 의미 검사 (Tier 2)

  1. lintDuplicates() 구현 — HNSW 유사도 기반
  2. 임계값 튜닝 (0.15 시작)

Phase 3: LLM 모순 (Tier 3)

  1. lintContradictions() 구현 — LLM 프롬프트
  2. 기존 contradictions 테이블과 통합
  3. --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만