wiki-lint은(는) 무엇을 하나요?
최초 실행 전, 키트 내
docs/GOTCHAS.md를 읽으십시오(알려진 거짓 양성, 운영 참고 사항).
위키(wiki.config.json의 wiki_root)에 대한 읽기 전용 건강 검사와 세 가지 복구 도구를 제공합니다. 모든 코드는 Python 표준 라이브러리로 작성되어 Windows, macOS, Linux에서 동일하게 실행됩니다. 모든 위키별 규칙(폴더, 상태 분류, 필드 맵, 예외, 동사 목록, 플레이스홀더 패턴, 임계값)은 설정 파일에 있으므로, 위키에 새로운 필드, 폴더 또는 검사가 추가되어도 로직은 변경되지 않습니다. 3,000개 이상의 노트 규모에서도 빠르게 동작하도록 설계되었습니다(전체 실행은 몇 초, 단 Check 13은 해당 규모에서 약 30초 소요).
관련 기술
wiki-ingest,wiki-ingest-book: 이 기술이 검사할 노트를 작성합니다(상태 결정 및 인덱스 라우팅에 동일한 설정 사용).wiki-synthesize: Check 15가 작업 목록을 생성하고, Check 32가 씰을 감사합니다.vocabulary-update: Check 30에 대한 해결 도구입니다.
레이아웃
skills/wiki-lint/
SKILL.md
scripts/
lint.py # 검사 실행 (--only, --out-dir, --self-test)
fix.py # 복구 도구: 인덱스 제안, Check 12 백링크, 드래프트 승격
references/
check-origins.md # 각 검사가 존재하는 이유 (단일 권위)
cli-reference.md # 플래그, 설정 키, 출력 파일, 보고서 형식
wikikit/lint/ # 구현: context.py, checks_*.py, fixes.py, defaults.json
tests/fixtures/lint/ # 모든 검사를 실행하는 합성 미니 위키 + expected_counters.txt
각 사실 종류가 위치하는 곳(중복 금지): references/check-origins.md = 검사가 존재하는 이유; 이 파일 = 수행하는 작업; wikikit/lint/checks_*.py = 구현 방법; tests/fixtures/lint/expected_counters.txt = 픽스처 값이 그렇게 설정된 이유. 실행 후 도구는 발생한 각 검사에 대해 check-origins.md 포인터를 출력하므로, 적중이 실제 오류인지 잡음인지 판단할 때 동기를 알 수 있습니다.
엔지니어링 불변 규칙 (위반 금지)
- 모든 파일 I/O는
wikikit.textio를 통해 수행 (바이트 수준 UTF-8, BOM 없음, 줄 끝 변경 금지). 기본 newline 처리가 포함된 텍스트 모드open()을 절대 사용하지 마십시오: CRLF 파일을 해당 방식으로 읽고 다시 쓰면 자동으로 변환됩니다. - CRLF가 포함될 수 있는 텍스트에 대해
$와 함께 멀티라인 정규식을 절대 사용하지 마십시오:$는 CR과 LF 사이에 위치하여 쌍을 분리합니다. 줄 단위로 편집하십시오 (frontmatter.set_key,fixes._insert_backlinks). - 설정이 단일 진실 공급원입니다. 위키에 필드, 폴더, 상태 또는 예외가 추가되면
wiki.config.json(lint섹션)을 편집하고, 코드를 수정하지 마십시오. 기본값은wikikit/lint/defaults.json에 있습니다. - 스텁 예외는 균일합니다.
lint.stub_exempt_checks는status: stub노트를 건너뛰는 검사 번호를 나열합니다. 설정에서 목록을 읽고, 절대 본문에서 다시 기술하지 마십시오. Check 10과 11은 인라인으로 스텁을 제외합니다(파일 시스템 개수). - 플레이스홀더 탐지는 비해결시에만 적용됩니다. 볼트 인덱스에서 대상이 확인되는 위키링크는 이름이 패턴과 일치하더라도 절대 플레이스홀더로 플래그되지 않습니다. 정당한 ALL-CAPS 약어 노트는 플래그되지 않아야 합니다.
- 로직 변경 전 자체 테스트를 수행하십시오. 검사에 대한 모든 편집(새 검사, 임계값 변경, 휴리스틱 리팩토링)은 반드시 통과해야 합니다:
python skills/wiki-lint/scripts/lint.py --self-test. 변경이 의도된 경우tests/fixtures/lint/와expected_counters.txt를 함께 업데이트하십시오. 픽스처가 차별화됨을 증명하십시오: 로직 변경을 되돌리고 재실행하여 카운터가 이동하는지 확인하십시오. 변경 전후 모두 통과하는 픽스처는 아무것도 보호하지 않습니다. - 0은 위키의 측정값이 아니라 탐지기의 측정값입니다. 새 검사의 0을 신뢰하기 전에 양성 사례를 주입하고 플래그가 발생하는지 확인하십시오.
- 경고 마커 소유권은 위치 기반이며, 정규식 체인이 아닙니다(Check 22). 위키는
[[Paper]]⚠와⚠[[Paper]]를 모두 사용할 수 있습니다. 글리프의 소유자는 왼쪽으로 트리밍된 텍스트가]]로 끝나는 경우 바로 왼쪽의 링크이고, 그렇지 않으면 오른쪽의 링크입니다. 인접한 링크가 없는 글리프는 일반 텍스트 주의사항입니다. 두 개의 연결된 정규식으로 이를 해결하지 마십시오(두 번째 정규식이 이웃 링크의 마커를 먹어버리고 검증되지 않은 소스의 플래그를 조용히 제거합니다). 마커의 대량 편집은 변경 전후에 인용별 인구 조사가 필요합니다.
검사 작동 방식
| # | 이름 | 플래그 대상 | 예외 |
|---|---|---|---|
| 1 | 고립 개념 | 어떤 논문/책에서도 역링크가 없음(인라인 링크 또는 concepts_touched) AND 형제 개념에서도 없음(인라인 또는 related_concepts); 형제 항목은 합성 허브가 오탐하는 것을 방지 | 스텁 |
| 2 | 고립 방법 | 논문/책에서 역링크가 없음 AND 논문/책으로의 링크가 없음 | 스텁 |
| 3 | 빈 concepts_touched | 필드가 null, 비어있거나 []인 논문 노트 (일괄 수집 시 프론트매터 손상의 지표) | 스텁 |
| 4 | 출처 없는 주장 | 최소 unsourced_threshold개 라인에 주장 동사(verb_list)가 포함되어 있고, 위키링크가 +/-unsourced_radius 라인 내에 없거나 위키링크된 제목 아래에 없는 개념 노트 | 스텁 |
| 5 | 깨진/플레이스홀더 위키링크 | 전체 볼트 인덱스에 없는 대상(broken), 또는 확인되지 않을 때 placeholder_wikilink_patterns와 일치(placeholder), 또는 비어 있음([[]], empty-target) | link_target_ignore_patterns (Bases 임베드) |
| 6 | 드래프트 | promote: 최소 min_distinct_sources_for_final개의 고유한 소스 작업을 인용하는 드래프트(책과 해당 장은 하나의 작업). stale: 기준 미만이거나 날짜가 없는 stale_days보다 오래된 드래프트 | 없음 |
| 7 | 인덱스 커버리지 | 베이스명이 index.md에서 위키링크가 아닌 노트 | 스텁; index_mode가 bases인 경우 건너뜀 |
| 7b | 인덱스 섹션 잘못 배치 | 잘못된 ## 섹션 아래의 - [[X]] (index_sections) | bases 모드에서 건너뜀 |
| 8 | 책 chapters_ingested 동기화 | 선언된 세트가 디스크의 {book}_ChNN.md 파일과 다름 | 스텁 장 |
| 9 | book: 없는 장 | book: 링크가 없거나 확인되지 않는 *_ChNN 노트 | 없음 |
| 10 | 빠른 통계 이탈 | ## Quick Stats에 선언된 개수가 매핑된 폴더의 실제 파일 개수와 다름 (quick_stats_labels) | 없음 |
| 11 | 필드별 커버리지 이탈 | ## Coverage by Field의 개념/방법 열이 실제 비스텁 개수와 다름(필드 행은 field: 기준, -> 하위필드 행은 [[MOC_*]] 링크를 기준으로 subfield: 기준; 하위필드에 노트가 있지만 행이 없으면 MISSING-ROW) | 스텁; 필드 없는 노트는 INFO |
| 12 | 양방향 concepts_touched | paper -> concepts_touched[token]에서 대상이 [[paper]] 역링크가 없음(asymmetry, 자동 수정 가능) 또는 노트로 확인되지 않음(missing_target, 토큰 트라이징) | 없음 |
| 13 | 링크 없는 별칭 | 다른 개념/방법의 본문에서 표준 노트로 링크 없이 사용된 문서화된 별칭(독특한 약어 또는 다중 단어 구문). INFO | 스텁; alias_link_stoplist; 인용구는 검색되지 않음 |
| 14 | 언어 레이더 | 위키 언어가 아닌 언어의 제목(H2-H6) 또는 본문에서 최소 prose_threshold개의 중지 단어 적중. 보고 전용; language_radar.enabled가 아닌 경우 비활성화됨 | 스텁 |
| 15 | 합성 레이더 | final 개념/방법 중: missing = 지식 상태 블록 자격이 있지만 없음; stale = 블록이 인용된 작업의 가장 최근 last_verified보다 오래됨 | 비최종 |
| 16 | 상태 어휘 | status가 status_by_type[type]에 없음, status 또는 type 누락, 또는 템플릿 누수(`draft | final`) |
| 17 | source_verification 없음 | 씰이 없는 논문; abstract로 시작하는 값은 씰이 아님. INFO 백로그 | 스텁 |
| 18 | 확인되었지만 불완전 | volume 또는 pages가 없고 날짜가 있는 check18_exempt: "YYYY-MM-DD, reason"가 없는 씰이 있는 논문; 학술회의 논문 및 논문은 장소와 형태로 예외 | 스텁 |
| 19 | evidence_level 어휘 외 | evidence_level_vocab에 없는 값 (논문만 해당) | 없음 |
| 20 | 유용한 인용구 ]] | ## Useful Quotes 아래의 인용구에 누출된 ]] | 없음 |
| 21 | 전문 이전 코호트 | synthesis.prefulltext_cutoff 이전 날짜의 논문으로 전문 수준 씰이 없음. INFO | 스텁 |
| 22 | 오래된 전문 이전 마커 | 이미 전문 씰이 있는 논문을 소유한 위키링크에 대한 ⚠, 세 가지 꼬리 예외(본문 주의사항, 날짜가 있는 이탤릭 주석, (N src 신뢰도) 후. 실제 거짓 양성이 있음 | 없음 |
| 23 | 채워지지 않은 주장 플레이스홀더 | unfilled_claim_patterns와 일치하는 라인(출처는 명명되었지만 주장이 작성되지 않음) | 없음 |
| 24 | 사용 중단된 프론트매터 키 | deprecated_frontmatter_keys에 있는 키 (기본값 journal에서 venue로); 정확히 일치하므로 거짓 양성 없음 | 없음 |
| 25 | 인용되지 않은 그림 | 위키링크가 반경 내에 없는 통계 수치(numeric_claim_patterns), cited / block / methods / domain으로 분류. INFO. 아무것도 예외되지 않음 | 스텁; 인용구 건너뜀 |
| 26 | 표 열 불일치 | 행의 셀 수가 구분자 행과 다른 표 (유일한 구조적 검사) | 없음 |
| 27 | 모지바케(Mojibake) | encode('cp1252').decode('utf-8') 왕복 시 다른 문자열이 되는 라인 | 없음 |
| 28 | last_verified 없는 씰 | source_verification이 있지만 last_verified가 없는 논문/책 (Check 15 stale에 보이지 않음). INFO | 없음 |
| 29 | 볼트 외부 슬러그 링크 | memory_slug_prefixes의 슬러그에 대한 위키링크, 볼트 전체. 목록이 비어 있지 않은 경우에만 활성화 | memory_slug_exempt_files |
| 30 | 어휘 동기화 | _VOCABULARY.md가 활성 개념/방법을 누락(missing)하거나 사라진 노트의 행을 보유(ghost). INFO; 해결책 /vocabulary-update | 없음 |
| 31 | 텍스트 없는 씰 | 최대 60자이고 어떤 채널에도 설명 텍스트가 없는 씰. INFO | 없음 |
| 32 | 씰 없는 쌍 | (노트, 지식 상태 블록에서 인용된 작업) 쌍으로 소스 노트 씰이 노트를 명명하지 않음. 차단; seal_debt_file에 선언된 부채는 보고되지만 계산되지 않음 | 선언된 부채 |
| 33 | 제목 또는 학회지 없음 | title 또는 venue가 비어 있는 논문 | 스텁 |
호출
볼트(위쪽으로 가장 가까운 wiki.config.json이 설정)에서:
python skills/wiki-lint/scripts/lint.py # 모든 검사; 목록은 _temp/에
python skills/wiki-lint/scripts/lint.py --only 5,12 # 선택된 검사
python skills/wiki-lint/scripts/lint.py --self-test # 픽스처와 expected_counters.txt 비교
python skills/wiki-lint/scripts/fix.py check12 --dry-run
python skills/wiki-lint/scripts/fix.py promote _temp/promote_batch.txt
python skills/wiki-lint/scripts/fix.py index # index_mode "manual" 및 이전 lint 실행 필요
플래그, 설정 키 및 각 검사가 작성하는 파일: references/cli-reference.md.
무엇을 언제 편집할지
- 새 위키 폴더 (예:
datasets/):wiki.config.json의folders에 추가하십시오. 노트가 생성되기 전에 등록되어야 합니다. 그렇지 않으면 모든 링크가 깨진 것으로 읽힙니다. - 새 상태 값:
lint.status_by_type.{type}에 추가하십시오. 새 노트 유형: 허용 상태와 함께 유형을 추가하십시오. - 개념/방법의 새 필드:
field_titlecase_map에 슬러그를 추가하십시오. - Check 4 개선:
lint.verb_list. 허용 범위 완화/강화:lint.defaults.unsourced_radius. - 새 플레이스홀더 패턴:
lint.placeholder_wikilink_patterns(확인되지 않는 대상에만 적용됨을 기억하십시오). - 검사가 스텁을 건너뛰어야 함:
lint.stub_exempt_checks에 번호를 추가하십시오. - 언어 레이더 활성화:
examples/languages/es.json을 복사하거나 (또는 직접 목록을 작성하여)lint.language_radar에 넣으십시오. - 새 검사 추가:
wikikit/lint/checks_*.py에 구현하고, 카운터를expected_counters.txt에 추가하고, 검사를 실행하는 픽스처를 추가하며,references/check-origins.md에 항목을 작성하십시오. 동기가 문서화되지 않은 검사는 처음으로 잡음처럼 보일 때 비활성화됩니다. 동기를 찾을 수 없으면 "not documented"라고 작성하십시오. 절대 임의로 만들지 마십시오.
안전 규칙
- 린트는 위키에 대해 읽기 전용입니다.
--out-dir(기본값_temp/)에 검사별 목록만 씁니다. fix.py는 보고된 부분(역링크, 상태)에서만 노트를 변경하고, 각 파일의 줄 끝을 유지하며, 모든 변경 사항을 롤백을 위해 로깅합니다.- 휴리스틱 변경이 올바른지 확실하지 않으면 먼저 픽스처를 작성하고, 자체 테스트가 실패하는지 확인한 후 변경하십시오.
- 캐시 디렉터리는 절대 버전 관리되지 않습니다 (
_temp/및 기타는.gitignore에 유지). 버전 관리된 측정은 오늘의 것처럼 몇 달 후에 읽힙니다.