# 2026-W25 Worklog
AI Summary
Purpose:
- Tracks development work across repositories for this week.
Key points:
- Add coding work entries here after meaningful agent sessions.
- Keep entries concise.
- Promote durable knowledge to
ai/repo-notes/orai/wiki/.
Relevant when:
- Reviewing this week's development work.
- Creating weekly report.
- Resuming context.
Do not read full document unless:
- The task concerns this week.
Linked documents:
ai/worklog/index.mdai/decisions/2026-06-15-malicious-package-openssf-collection.mdhuman/reports/2026-malicious-package-collection.md
Work Items
Study blog MySQL core chapter added
- Date: 2026-06-15. Repo:
llm-wiki. - Added published Korean study chapter
human/study/content/mysql-core/01-index-and-innodb-engine.md. - Added new study series metadata
human/study/content/mysql-core/series.json. - Updated
ai/study/curriculum.mdso the MySQL core chapter is recorded as published. - Topic: MySQL index usage, composite index leftmost prefix,
EXPLAIN, InnoDB clustered/secondary index behavior, and operational index checklist.
OpenSSF 악성 패키지(MAL) RAW 수집 PoC + 설계 확정
- Date: 2026-06-15. Repos:
~/labrador/tool/openssf-malicious(신규, 미커밋),llm-wiki. - 방향 결정: 방안 1(독립 수집) — OpenSSF
ossf/malicious-packages(OSV 포맷,MAL-YYYY-NNNN)를
우리 인벤토리와 즉시 조인하지 않고 독립 RAW 자산으로 수집. 인벤토리 매핑은 이후 레이어로 분리.
- 수집 PoC(
collect.py): git clone(최초)/pull(증분), repo 자체가 raw 저장소
(osv/malicious/<eco>/<pkg>/MAL-*.json), data/manifest.json에 head_commit·생태계 카운트 기록.
- 실측(2026-06-15): 227,060건 / 896MB. npm 213,926(94%) · pypi 11,340 · rubygems 970 ·
nuget 773 · go 18 · vscode 20 · crates.io 9 · maven 2 · packagist/git 1. OS 배포판 0건 (OpenSSF malicious-packages는 언어 레지스트리 전용).
- 데이터 특성(raw 실측):
affected=정규화 결론(매핑용) vsdatabase_specific.malicious-packages-origins
=출처/감사추적(다중 출처 신뢰도). 버전 표현 ranges만 89.6% / versions만 7.4% / 둘 다 3.1%. 상한 있는 케이스 희소(fixed 33 / last_affected 128 / introduced≠0 1,709) — 탈취 후 수정된 고가치 케이스. versions는 불연속 많음(min~max 합치기 금지). 한 product에 range 다중 747건.
- 설계 확정(설계 문서 2종:
ai/decisions/2026-06-15-...md,human/reports/2026-...md):
- 스키마: 단일 TB_COMP_LIB_MAL(RAW는 git 보존, RAW_DATA/_RAW/V1 없음), PK (VULN_ID, ECOSYSTEM, PRODUCT_KEY) — 실측상 advisory당 1패키지·중복 0 검증. - VULN_RANGE: | 구분 토큰(구간/단일버전)의 합집합. versions는 v1|v2|v3, range 다중은 union. - DEPRECATED(0/1) 소프트삭제 + VIEW_COMP_LIB_MAL(활성만) — 배포(distribution) sync로 흘러가므로 물리 삭제 금지(상태 전이). - ecosystem 정규화: OSV→내부 대문자 코드(Packagist→COMPOSER, crates.io→CARGO, Go→GOLANG …), 케이싱 불일치(pypi/PYPI, Cargo/CARGO)는 조인 시 UPPER() 흡수, vscode/git은 매핑 없음 → 스킵+로그. - 증분 복구: prev 유효성은 merge-base --is-ancestor로 판정, 무효 시 commit_time 폴백(반드시 내림 ≤), 최후엔 full reconcile(HEAD 트리 ↔ DB 활성 행 대조, 주기 실행 시 self-heal). 상태는 TB_CRAWLER_STATUS TYPE='OPENSSF_MAL'에 {commit_id, commit_time}.
- 인적 문서화: 온보딩 HTML/슬라이드 HTML/내부 정본 md 3종 작성(설계 단계·미구현 명시).
- Open Question 해소: npm
PRODUCT_KEY해시 = AES-CBC —PRODUCT_KEY=base64(AES-CBC(pkg_name)),
key=IV=b'NPMNPMNPMNPMNPMN', ai/labradorlabs/util/aesCbc.py(deterministic). 2026-W24 npm missing-products 작업에서 확인된 것과 동일. → 적재 시 npm만 이 해시 적용하면 됨.
- 미해결: takedown 패키지의 인벤토리 정합률 정량화(매핑 레이어 단계), 배포 sync가
DEPRECATED
상태 전이를 소비하는 연동 방식.
- 검증:
collect.py전량 수집 + 무결성(disk 227,060 = manifest,MAL-2022-1파싱 OK).
DB 적재/증분은 미구현(설계만). llm-wiki 커밋: 35bc508(문서 3종) → 638b951(정규화/스키마/RANGE) → 27e61df(증분 복구).
OpenSSF MAL 수집기 구현 + DAG + K8s 배포 디버깅
- Date: 2026-06-16. Repos:
~/labrador/platform/labrador-scrapers(브랜치
dat-3242/openssf_created→main), ~/labrador/platform/labrador-data-platform (DAT-3242/openssf_mal→main), llm-wiki. 설계의 "미구현"을 실제 구현·배포로 진행.
- 구현(scrapers
etl_components/openssf_mal/,osv_vuln컨벤션 차용):BaseScraper
서브클래스 + LabradorDB, 모델 TB_COMP_LIB_MAL(+공유 CrawlerStatus), repo_sync.py (git clone/pull·증분 기준점 복구), mal_transform.py(REPOSITORY 정규화·npm AES PRODUCT_KEY·RANGE | 합집합), main.py. 커밋 f3e8a4e(pre-commit black/isort/pylint/ mypy/docstring 전부 통과).
- 컬럼명 변경: 설계의
ECOSYSTEM→ 기존 테이블 패밀리와 일치하도록REPOSITORY
로 통일(코드+설계 문서 4종).
- DAG(data-platform
dags/openssf_mal.py+envs/images.py의openssf_mal):
단일 태스크, /resources PVC 마운트, schedule="0 6 * * *", full_reconcile param. osv_vuln.py 모델. 커밋 0ed7e6a.
- 검증:
mal_transform를 수집한 실제 raw 227k 중 npm 2,000건 무에러 + 케이스별
(rustdecimal=CARGO (,), pyrefly=NPM 해시키, easyascii=불연속 v1|v2|..., styled-components=range 다중 union (,), intercom-php=COMPOSER 5.0.2, pyphetools=[0.9.120,0.9.121)) 변환 확인. (DB/git/컨테이너 동작은 클러스터에서.)
- 배포 이슈: K8s PVC git "dubious ownership"(exit 128) 3연속 디버깅:
- 067b83f git -c safe.directory=* → git은 -c(CLI)의 safe.directory를 보안상 무시 → 실패. - df0a56a GIT_CONFIG_GLOBAL env → 베이스 이미지 bullseye git 2.30이 미지원(2.32+) → 실패. - 94609dd HOME의 .gitconfig에 * + 명시 repo 경로 등록 → 명시 경로는 전 버전 지원 → 해결. - 교훈: python:3.12-slim-bullseye = git 2.30.x. safe.directory 명시 경로가 버전 무관 안전. _git 실패 시 stderr를 예외에 포함하게 바꿔 원인 가시화.
- repo 컨벤션 메모: scrapers
prepare-commit-msg훅이 브랜치명에서DAT-XXXX티켓을
추출해 검증 → main 직접 커밋 불가, feature 브랜치 커밋 후 FF 머지가 정석. data-platform은 prepare-commit-msg(bash 3.2 ^^ 비호환)·pre-push(astro 미설치)가 로컬에서 깨져 그 커밋만 훅 우회(품질검사 black/mypy는 통과 확인).
- 문서: 정본 md
human/reports/2026-malicious-package-collection.md§4.5에 초기 수집/증분
mermaid 시퀀스 추가(파서 호환 위해 ;/%%/alias 괄호 제거).
- 상태: 코드·DAG·문서 모두 main 반영. Jenkins 재빌드(#490+) 후 실행 검증 진행 중 — PVC 클론
소유권 통과까지 확인, 이후 파싱·적재 단계 검증 예정.
OpenSSF MAL: advisory 메타 테이블 TB_COMP_LIB_MAL_INFO 추가
- Date: 2026-06-16. Repos:
labrador-scrapers(dat-3242/openssf_created→main),llm-wiki. - 요구:
summary/details/references/aliases를 MAL 테이블이 아닌 별도 테이블에 수집,
ID=VULN_ID, 생성·업데이트 라이프사이클은 MAL과 동일하게.
- 신규
TB_COMP_LIB_MAL_INFO(PK=VULN_ID):SUMMARY/DETAILS(TEXT),MAL_REFERENCES(JSON,
osv.references — REFERENCES는 예약어라 MAL_ 접두), ALIASES(JSON, osv.aliases), DEPRECATED(0/1) + RECORD_CREATED/UPDATED. + VIEW_COMP_LIB_MAL_INFO(활성만).
- MAL과 동일 라이프사이클: 같은
run_tsupsert, 증분 시 변경VULN_ID를 MAL/MAL_INFO
양쪽 deprecate→재upsert, full sweep도 양쪽. MAL 행 생긴 advisory에 대해서만 INFO 생성(정합). 같은 컨테이너/DAG가 두 테이블 함께 적재(DAG·이미지 변경 없음).
- 검증:
parse_info를 실데이터(MAL-2022-1)로 확인(SUMMARY/DETAILS/ALIASES/REFERENCES JSON
직렬화), pre-commit(black/isort/pylint 10·mypy·docstring) 통과. 커밋 debf1b7(scrapers branch+main), 설계 문서·repo-note 반영 fb28fd9(llm-wiki).
- 신규 테이블 백필 =
full_reconcile=true1회 실행(전 advisory 재파싱 → MAL+MAL_INFO 채움).
증분은 변경분만 건드려 기존 데이터로는 MAL_INFO가 안 채워짐.
maven 누락 백필: not_found 원인 규명 + collect 버전수집 결함 수정
- Date: 2026-06-16. Repo:
~/labrador/tool/maven_missing_products(코드 미커밋). 작업 산출물은
날짜 워크디렉터리 2026-06-16/(recover99·fill_missing·fill_springai·recover_topup_wd· maven_not_found_reasons.md).
- 발단: 6/8 백필(
maven_missing_products.txt1,404개) 이후~/Downloads/maven_packages_not_found.txt
146건이 여전히 누락 → 원인 규명 요청.
- 스키마 split 주의: product =
labradordb.TB_COMP_LIB_PRODUCT, version =gatheringdb.TB_COMP_LIB_VERSION_JAVA.
기본 DB(gatheringdb)만 보면 java/MAVEN product 0건으로 오판 → 반드시 labradordb 스키마로 조회. 실측 product 909,797건. (MCP mysql-gatheringdb는 동일 서버지만 default db라 product 안 보임.)
- 핵심 결함:
collect_maven_missing.py가 버전 목록을maven-metadata.xml하나에만 의존.
Central은 artifact-level metadata.xml을 항상 보장하지 않음 — (a) metadata 404인데 디렉터리·버전은 실재(org.onosproject:* 등), (b) metadata 200이나 플러그인 그룹 메타데이터라 <versions> 없음 (org.openidentityplatform:openicf). 이 경우들이 통째로 "gone/no-version"으로 스킵됨.
- 수정 1(버전 열거):
fetch_metadata에 디렉터리 리스팅 폴백 추가(fetch_versions_from_listing) —
metadata 404 또는 <versions> 비면 {artifact}/ HTML에서 첫글자 숫자 디렉터리를 버전으로 열거. dir도 404면 gone 유지.
- 수정 2(POM/sha1 파일명):
fetch_pom·fetch_sha1이 파일명을{artifactId}-{version}.pom/.jar로 가정 →
디렉터리명≠artifactId인 비표준 배치(예: org/neodatis/odb/1.9.21.672/에 neodatis-odb-*.pom/.jar)에서 404. 표준명 404 시 버전 디렉터리를 리스팅해 실제 .pom(*-<version>.pom 메인 우선)·.sha1 파일을 찾아 재시도 (헬퍼 _list_dir_files/_pick_pom_file). 표준 경로면 추가 요청 없음. 검증: neodatis odb → POM 파싱 (선언 좌표 org.neodatis.odb:neodatis-odb)·sha1 수집 성공, 표준/gone 케이스 회귀 없음.
- 146건 분류(
maven_not_found_reasons.md): A.meta없음(아티팩트존재) 97(폴백 복구 가능, 단 대부분
POM 없어 thin) / B.404 완전소멸 43(metadata·dir 모두 404, 복구불가) / C.meta있지만 누락 4 (플러그인메타·빈네임스페이스·case불일치) / D.가짜좌표 2(group.springframework.ai:* — groupId가 group.으로 깨진 인덱스 노이즈, 실제 org.springframework.ai:*는 이미 DB 존재).
- 복구 백필(폴백 적용,
--sink both): recover 99 + 케이스민감 topup 3 = 102 product 적재. 단
POM-less coord(onos *-features.xml)가 96개라 version 행 4,104개는 thin(license/sha1/deps null) — POM이 원천 없어 메타 채울 수 없음. 사용자 결정 = thin 유지.
maven_gone_404.txt정리: 디렉터리 재확인으로 143 → 43(진짜 소멸만). 원본.full.txt백업,
제거분 .recoverable.txt.
- 신선 인덱스 finder(
--refresh) 재실행: 고유 product 828,845 비교 → 누락 정확히 146(=not_found와 일치). - upsert 클로버 위험(중요): phase1의
upsert_versions는ON DUPLICATE KEY UPDATE로 license/sha1/
deps를 VALUES(=phase1단계 null)로 덮음. 기존 상세행이 있는 패키지에 phase1 --sink db를 그냥 돌리면 기존 메타 전멸. 안전 절차 = --sink file로 받고 → 기존 DB버전을 out_phase2_done.txt에 seed해 누락분만 phase2 → --phase load(detailed는 upsert, thin은 INSERT IGNORE로 기존 보호).
- 개별 백필(안전절차 적용):
org.wso2.carbon.identity.framework:org.wso2.carbon.user.mgt
(maven 5,160/DB 2,736 → 5,160, 단 신규 2,288은 metadata엔 있으나 실아티팩트 없는 유령 버전=thin, 유지 결정), com.gitee.huanminabc:null-chain(6→15, -release/-RELEASE case는 collation 0900_ai_ci로 병합), org.springframework.ai:spring-ai-bom(35→40, 신규 5버전 POM 상세까지 정상).
- 부수 발견:
com.github.marcioos:bgg-client는 2020년 행이 깨진 키bgg-clienẗ́(t+결합문자)로 존재,
PK collation utf8mb4_0900_ai_ci(악센트/대소문자 무시)라 clean 키 INSERT가 중복판정되어 갱신만 됨. finder는 파이썬 exact 비교라 매번 누락으로 재플래그(고착).
- 미해결/후속: collect 폴백 수정 커밋, metadata 유령버전 필터(실아티팩트 없는 버전 적재 방지) 여부,
깨진 좌표(group.*)·깨진 키(bgg-clienẗ́) 정정. durable 트랩은 repo-note 승격 후보.
dotnet 크롤러: LIST pending(PROCESSED=0) 안 줆 — all-or-nothing 페이지 완료 디버깅 + leaf fetch 재시도
- Date: 2026-06-17. Repo:
~/labrador/crawler/crawler-lib-dotnet(코드 미커밋). DB:211.115.125.165:43316/gatheringdb,TB_COMP_LIB_DOTNET_LIST. - 증상:
check.py(run_check) "list processed"의 pending(PROCESSED=0)이 안 줄어듦(24개, 일부 LAST_UPDATED 5/19~6/7로 정체). PROCESSED 의미: 0=pending,1=completed,2=in_progress,3~7=failed. - 체계적 조사(추측 전 증거): ① 24개 페이지·전체 leaf 단건 fetch 정상(
page225132748 leaf 실패 0) = poison 아님 ② 30초간 분포 무변화·in_progress 0 ③ 마지막DotnetCralwer실행 6/11 START, END_TIME=null(정상종료 못함), 이후 dotnet 에러로그 없음 ④ 진단 시점 Docker 데몬 다운 + 호스트 프로세스 없음 = 아예 안 돌고 있었음. - 근본 원인:
dataCrawling의 페이지 완료가 all-or-nothing. 페이지(카탈로그 page)의 leaf를 전부 순차 처리하다 leaf 1건이라도 실패하면error_flag=True(line 174/188/193) → 마감에서error_flag==False일 때만PROCESSED=1, 아니면PROCESSED=0requeue(line 268-272). 그런데 leaf fetchgetJsonRequests(sw/common.py)가 재시도 없는requests.get(timeout=30)1회라 타임아웃/5xx/429/연결오류/JSON파싱오류 시 즉시 None. leaf 수천 개 페이지는 매 실행마다 일시 실패 ≥1건에 걸려 영영 완료 못 하고 requeue → pending 0 고착. (repo-note open #70 "transient 실패를 PROCESSED=0으로, 재시도 사다리 없음"의 실체.) - 수정(재시도 추가):
getJsonRequests(url, retries=3, backoff=2)— 일시 실패(타임아웃/연결오류/5xx/429/JSON파싱오류)는 2s·4s·6s backoff로 최대 3회 재시도, 404/410(영구)은 즉시 None(낭비 방지).import time추가, 기존 호출부 호환(default 인자). 격리 검증: 200 반환 / 404 즉시 None(0.3s) / 503 3회 재시도. - 도커 검증: 이미지 빌드(
iotcube/dotnetcrawler:0.1.1, 2.14GB; Dockerfile이 Ruby 3.2.2 소스컴파일+licensee라 빌드 ~15분) 후src볼륨마운트로 수정 반영해 실행. 결과: 원래 stuck 24개 중 2개가 PROCESSED=1로 완료(10일간 안 빠지던 것), 크롤러 활성 처리(~0.83 leaf/s, 행 INSERT 진행, requeue 없음). 처리 throughput은 느림(페이지당 leaf 수천 × leaf별 AI 라이선스 호출로 ~55분/페이지) — 버그(영구 requeue)와는 별개. - 잔여: 영구-404 leaf는 여전히
error_flag=True로 페이지 requeue(재시도로 못 고침). 완전 해소엔 leaf 단위 부분진행/스킵 설계 필요(open #70). 이번 증거상 24개는 전부 일시성이라 재시도로 해소됨. - 참고: 호스트 Python 3.13에선 핀된 구버전 deps(greenlet 2.0.1/jpype 등) 빌드 실패 → 반드시 도커(ubuntu22.04/py3.10)로 구동.
버전 단위 누락 체크(maven/rubygems/composer) + composer 165 백필·LATEST 보정
- Date: 2026-06-16~17. Repos:
~/labrador/tool/{maven,rubygems,composer}_missing_products(코드 미커밋). - 신규: 버전(product-version) 단위 누락 체커 3종 (기존 product 단위와 별개로
g:a:v/gem:version/name:version비교):
- maven extract_maven_missing_versions.py: nexus 인덱스 g:a:v − DB gatheringdb.TB_COMP_LIB_VERSION_JAVA(2,057만), sort -u+comm 외부정렬. 결과 누락 1,045,271. - rubygems extract_rubygems_missing_versions.py: rubygems.org/versions 전역 인덱스(yanked 제외, 버전-플랫폼→버전번호) − DB(186만). 결과 누락 9,895. - composer extract_composer_missing_versions.py: Packagist는 전역 버전 인덱스가 없어 패키지별 repo.packagist.org/p2/{name}.json(stable; dev는 ~dev.json이라 자동 제외) 전수(52만), resume 가능. 결과 누락 718,431 버전 / 91,322 패키지 / gone-404 69,874.
- composer 날짜-디렉터리 적용:
extract·collect에--date/--workdir추가(기존 산출물2026-06-08/로 이동,composer_excluded.txt만 top-level 유지) — rubygems와 동일 패턴. - rubygems 버전 백필: 누락 9,895의 고유 gem 3,335개(소문자→원본 case 복원, 대문자 15개)를
collect_rubygems재수집(version 68,755 upsert). LATEST_VERSION stable 보정 77건. - composer 164→165 오타깃 정정(중요): composer만 local
.env가 없어 shareddata_check_script/.env(164:53306)로 가서 백필이 164에 적재되던 것을 발견·중단(164 데이터는 보존, 추후 정리). local.env=165 생성 후 165 재백필. 165 스키마 차이 2건 수정:LICENSE_TABLE=gatheringdb.TB_LICENSE_V2(165는 라이선스가 gatheringdb),_release_date연도 sanitize(1000~9999 밖이면 None —0202-03-07같은 깨진 packagisttime이 MySQL DATETIME INSERT를 죽이던 배치 크래시 방지).--no-ai로 속도 우선(앞 37k는 AI 포함, 이후 no-ai). → llm-wiki에ai/workspace/crawler-db-target.md규칙 못박음(수집=165 only, 절대 164 아님). - composer 165 백필 결과: pkg 90,649 / version 2,332,651 / 404 653(Packagist 삭제) / err 20=전부
http-502(Packagist 일시 장애, 재요청 시 전부 200 확인 → 이름만 추출해 재수집, 20/20 적재). - composer LATEST_VERSION stable 보정(165,
fix_latest_stable.py): collect가 정렬상 마지막(=dev, 예13.x-dev)을 LATEST로 넣어,v제거 후^숫자(.숫자)*$=stable 중 최신으로 재보정. 검사 91,322 → 보정 11,878 / stable없어 보류 1,090. 검증: stable 있는데 LATEST가 dev/pre로 남은 product 0. (164는 165에서 자동 동기화.) - DB 타깃 정리: maven=165
gatheringdb.*VERSION_JAVA, rubygems=165labradordb.*VERSION_RUBY, composer=165labradordb.*VERSION_PHP(license만gatheringdb.TB_LICENSE_V2).
NuGet(dotnet) 버전 단위 누락 체커 추가
- Date: 2026-06-18. Repo:
~/labrador/tool/nuget_missing_products(코드 미커밋). DB:211.115.125.165:43316,labradordb.TB_COMP_LIB_VERSION_DOTNET(13.86M) / productlabradordb.TB_COMP_LIB_PRODUCT(dotnet/NUGET 825,047). - 신규
extract_nuget_missing_versions.py: NuGet catalog 페이지(catalog0/page{N}, 22,651개) item 이 leaf 의nuget:id/nuget:version/@type/commitTimeStamp를 인라인으로 담는 점을 이용 → 개별 leaf(수천만) fetch 없이 페이지만 받아 전역(id,version)확보(825k 패키지별 registration 요청 불필요 = maven nexus 인덱스 방식과 동일 컨셉). 페이지 동시 fetch(24 workers, ~90p/s). - PackageDelete 처리: catalog 는 append 로그라 같은
(id:version)이 Details/Delete 로 여러 번 등장 →id:version\tcommitTimeStamp\tD|Xraw 기록 후sort -k1,1 -k2,2+ awk 로 (id:version)별 최신 이벤트가 Details 면 현존, Delete 면 제외. (재게시(Delete 후 Details)는 현존, 합성 데이터로 로직 검증.) - 현존
(id:version)− DB(소문자)comm -23→ 누락. leaf 이벤트 19,439,585 → 현존 고유 14,185,675 vs DB 고유 13,865,764.--date/--workdir지원. - version 대소문자 버그 수정(중요): 1차 결과 486,158은 거짓 부풀림이었음 — existing 키는
id소문자:version원본인데 DB 덤프는LOWER(id:version)이라, NuGet의 대문자 포함 버전(1.0.0-RC1/-Preview/-Beta등 137,241개)이 거짓 누락으로 잡힘(표본 30/30이 DB에 케이스무시로 이미 존재). 스크립트의 version 도.lower()하도록 수정 + raw(intact)에서 키 전부 소문자화해 재산출 → 보정 누락 351,314 / 68,448 패키지. - 운영 메모: Claude 세션 재생성 시 nohup 백그라운드도 SIGTERM 으로 죽음(폴러 exit 144). macOS엔
setsid바이너리 없음 → 스크립트 첫 줄os.setsid()로 자가 분리(PPID=1)하면 세션 재시작에도 생존. 무거운 산출물(raw 1.3GB·sorted)은 intact 였어서 페이지 재다운로드 없이resume_nuget_versions.py로 현존해소→DB덤프→comm만 재개해 마무리. - 누락 버전 백필(165,
backfill_nuget_versions.py): 안전 패턴 — Phase1--sink file(68,444 패키지 registration → out_versions 전 버전 5,317,851, DB 미기록) → 기존 버전 done-set seed(skip 4,966,547) → Phase2--sink both --no-ai로 누락 351,304개만 catalog leaf 받아 신규 적재. 결과 상세완료 351,304 / 버전404 0 / err 0(총 ~34h). 기존 detail 클로버 없음(누락분만 신규 INSERT). 요구대로 로그 전 줄 타임스탬프(backfill.log,%(asctime)s) +os.setsid분리로 34h 무중단. (LATEST_VERSION stable 보정은 후속.)
go 크롤러 queue-lock stuck 진단 + main indexer↔worker 인터리브(데몬화)
- Date: 2026-06-18. Repo:
~/labrador/crawler/crawler-lib-golang(브랜치feature/go-crawler-indexer-loop). DB:gatherdb01(gatheringdb). - 증상: 워커 전원이 10초 간격으로
failed to claim queue lock: golangcrawler:queue-claim(goCrawler.py:1164) 스팸. 10초 =GET_LOCK(:lock_name, 10)타임아웃이라 = 한 세션이 락을 장시간 점유. - 진단(DB 직접):
IS_USED_LOCK('golangcrawler:queue-claim')= conn86576477(4회 조회 내내 고정 = stuck). MCP 계정에PROCESS권한 없어PROCESSLIST/INNODB_TRX/data_locks조회 불가(크롤러 세션 안 보임).wait_timeout=28800(8h) → 죽은(half-open) 홀더의 named lock 이 8시간 안 풀림. (5670ef4의_reclaimStuckProcessingEvents는 데이터 행(PROCESSED 20-24)만 회수, named lock 자체는 못 풂.) 사용자가 컨테이너 전부 down → 락 해제됨(=holder 가 살아있던 워커 세션이었음). - 재발 원인 규명(중요·오진 정정): 처음엔 "fix 가 master 미머지"로 봤으나
git fetch후 origin/master 가 이미eb1a2f6(5670ef4 포함)임을 확인 — 로컬 origin/master ref 만 stale 했던 것. 서버 소스도grep -c _reclaimStuckProcessingEvents=3(=fix 있음),git pullAlready up to date. → 진짜 원인 = 락이 물렸던 그 프로세스가 fix 이전에 떠 있던 것(Python 은 시작 시 코드 메모리 로드; 호스트 git 이 나중에 갱신돼도 실행 중 프로세스엔 미반영). 이미지 재빌드(./docker.build.sh) 후 재기동이면 해소. - 추가 요구 = main 동작 변경: 현재
run()은indexer 1회(tip 까지 full-walk) → _runV2 가 큐 drain → 큐 비면 return(종료). 원하는 동작 =index → 300건 claim → 배치 끝 → 다시 index반복. 결정: indexer 단위=기존 full-walk 그대로 루프에만, 빈 큐=종료 안 하고 idle sleep(데몬), 게이팅=main 만 index(pure worker 는 claim/sleep). 이 크롤러는 Jenkins 안 씀·docker 직접 배포(main 단독)라 더블-main 우려 없음. - 구현(브랜치 미머지):
_runV2(crawler_name, status_raw_data, index_enabled, index_cursor)로 시그니처 변경 — 루프 매 iteration 에서index_enabled면updatePackageListCrawler(cursor)호출 후 claim/처리, 빈 큐+reclaim 0 이면time.sleep(_idleSleepSeconds())후 continue(종료 분기 제거).run()은 V2 경로에서 line 86 pre-walk 를and not self._isV2ListSchema()로 skip 하고_runV2에index_enabled+커서 전달. 신규 envGO_IDLE_SLEEP_SECONDS(기본 60), 헬퍼_idleSleepSeconds, 모듈import time. - 안전성: 일반 모드(
GO_INDEX_SKIP_EXISTS_CHECKoff)에선_buildV2IndexEvents가 기존 이벤트 skip(goCrawler.py:1307)이라 반복 인덱싱해도 done 이벤트PROCESSED리셋 없음. 데몬 main 은GO_INDEX_SKIP_EXISTS_CHECKOFF 유지 필수. - 테스트: 신규
tests/test_go_crawler_run_loop.py(no-DB,GoCrawler.__new__+MagicMock;time.sleep을BaseExceptionside_effect 로 patch 해while True탈출). 5 케이스(index 게이팅/매 사이클 호출/빈 큐 sleep/reclaim>0 continue/run 와이어링). import 가드에 Config LogPath→tmp 부트스트랩(호스트/workspace/log부재 대응)·skipUnless로 호스트unittest discover그린 유지. 호스트는 deps 핀(pydantic 1.10.x 등) 빌드 불가라 venv(pydantic<2필수) 또는 이미지에서 실행. 결과: venv 65 tests OK(11 skip), 호스트 65 OK(16 skip). - 커밋(브랜치
feature/go-crawler-indexer-loop): 스펙d140205, 계획dc620b7, Task1883e884, Task2561af43. 설계/계획 =docs/superpowers/specs|plans/2026-06-18-*. - 미해결/후속: 브랜치 미머지·미배포(사용자가 master 머지 후 이미지 재빌드+재기동 필요). 권장 안전망 = 크롤러 세션
wait_timeout단축(크래시 홀더 락 자동 해제).db.open()/close()가 루프 반복에서 claim/처리를 안 깨는지 통합 검증은 이미지/클러스터에서.
go "60만 누락" 전수 분해 — 진짜 누락 거의 없음 확인
- Date: 2026-06-18. 신규 도구
~/labrador/tool/golang_missing_products(코드 미커밋,*_missing_products패턴의 Go 판). DB:gatheringdb(165:43316), productTB_COMP_LIB_PRODUCT_GOLANG(go/Golang 1,925,446) / listTB_COMP_LIB_GOLANG_LIST_V2(48.8M,INDEX_PATH인덱스). local.env(165 gatheringdb, 크롤러config.iniDbUrl 과 동일) — shareddata_check_script/.env(164 labradordb)와 다름. - 입력
~/Downloads/gpnf.txt: 과거 누락 체크가index Path(lower)vsLOWER(PRODUCT_KEY)단순비교로 뽑은 not-found 스냅샷 617,525건(중복 0). 사용자 의문 = "이게 다 누락은 아닐 것(하위 패키지면 상위 수집된 거)". analyze_gpnf.py: product 전체를 스트리밍 로드(exact/lower 집합) → 각 path 를 A완전일치/B대소문자/C.gitalias/D상위모듈수집(하위package, trailing 세그먼트 stripping)로 1차 분류, product 로 설명 안 되는 잔여(428,224)는 LIST_V2INDEX_PATH배치조회(IN 5000×86)로PROCESSED/RESOLVE_KIND재분해. 결과2026-06-18/(버킷별 txt +summary.md+residual_detail.tsv). product 키 1.93M 중 lower 유니크 1.86M = 대소문자 충돌 ~65k 존재.- 결과(617,525): A collected_exact 145,844(23.6%) / B case_only 15,825(2.6%) / C git_alias 474 / D subpackage_parent_collected 27,158(4.4%)(예
.../etcd/server/v3→root.../etcd,.../line-bot-sdk-go/v7) / E1 listv2_collected 11 / E2 listv2_resolved_alias 57,161(9.3%)(RESOLVE_KIND 거의 전부declared_diff) / E3 not_found(5) = 0 / E4 pending(PROCESSED=0) 366,798(59.4%) / E5 not_indexed 4,254(0.7%). - 결론: 이미 해소(누락 아님) 246,473(39.9%) + backlog 366,798(59.4%, 큐 대기·영구 누락 아님) + 진짜 없음 0 + 인덱싱 안 됨 4,254(0.7%, github.com 3,780 + gitee/gitlab +
metrics.pikepinetech.com/cnb.cool/github.ink소수 vanity 호스트). → "61.7만이 다 누락"은 아님; 근본원인 = 모듈 부재가 아니라 index path 를 PRODUCT_KEY 처럼 본 옛 비교(declared_diff/subpath/대소문자/stale 스냅샷/큐 backlog 가 전부 not found). 부수발견:ghproxy-9d2.pages.dev(gpnf 6,895)·github.hscsec.cn(2,764)·github.phpd.cn(2,001) 같은 GitHub mirror/proxy 호스트는 go.mod 가 정식 github.com 경로 선언 → E2 declared_diff alias 또는 E4 pending 으로 빠짐(not_indexed 아님). 실제 손볼 거리는 E5 0.7% 검증 + E4 드레이닝뿐. - 기록 갱신: 크롤러 repo
docs/go-missing-index-path-report.md상단에 2026-06-18 정량 섹션 추가(기존 2026-05-28 정성 패턴 카탈로그는 유효해서 보존). llm-wikiai/repo-notes/crawler-lib-golang.mdKey points 에 분해 요약 bullet 추가.
go pending 백필 — "60만 누락" 99.3% 해소 + proxy 실검증
- Date: 2026-06-18~19. Repo:
~/labrador/tool/golang_missing_products(미커밋). DB: gatheringdb(165:43316). - 사용자 지적: DB 멤버십 말고
proxy.golang.org로 진짜 없는지 확인하고.mod선언명 다른 것도 다 보라. proxy_verify.py(크롤러go_utilsescape/parse/classify 재사용,@latest→@v/list→@v/{ver}.mod):not_indexed4,254 전수 = absent_404 88%(찐 gone)/same 9.6%/declared_diff 1.4%;pending표본 ~98% proxy 실재. 핵심: 시스템이PROCESSED=5(not_found)를 안 써서(코드가 go.mod 실패를 retry 로 되돌림, 전역 5=0건) gone 모듈도 pending 으로만 남음 → DB 만으론 gone 판정 불가, proxy 가 정답.backfill_pending.py(크롤러dataCrawlingV2충실 재현): pending 366,798 path = 2,574,469 이벤트. 이벤트별 proxy.mod해결 → 이미 있으면 LIST_V2 마킹(드레이닝), 신규면 version/license/product upsert(gatheringdb, 정확 컬럼/JSON). 신규 1,565,267 수집, product 1.92M→2.22M(+294,792). 전역 LIST_V2 pending 35.44M→32.38M(−3.06M). 120-path 실측으로 포맷·LATEST·마킹 사전검증(go-ethereum LATEST=v1.9.6 정렬확인).- LATEST_VERSION 개선(사용자 요구): product.LATEST_VERSION 을 그 PRODUCT_KEY 버전 테이블 전체
sort_go_versions정렬 최신으로 넣음(크롤러 last-processed-event 방식 보정 = 기존 KNOWN GAP 실질 해소). - DB write 버그 3종(수정): ① mysql.connector
executemany/execute클라이언트측 치환이 README((/)/')에서 SQL 1064 깨짐 →cursor(prepared=True)서버측 prepared statement 로 해결(384+32 에러 전량 롤백→재실행 수습, 손상 0). ②DESCRIPTION64KB(text) 초과 1406 → UTF-8 65,000B 절단. ③ epoch pseudo(v0.0.0-19700101000000) commitTime1970-01-01 00:00:00< TIMESTAMP 최소값 1292 → None. - 재측정(
analyze_gpnf재실행): gpnf 617,525 중 listv2_pending 366,798→770, 이미 해소 39.9%→99.3%. (전역 pending 은 여전히 32M — gpnf 셋은 35M backlog 의 일부라 그 부분만 백필.) - 결과 2파일(사용자 요구 = 실제누락 + 제외목록):
golang_excluded.tsv(616,069,index_path\treason, 누락체크 제외용 — collected_exact 376,409/listv2_alias_resolved 153,990/case_only 50,762/subpackage 31,166/proxy_gone_404 2,871/…) +2026-06-19/golang_missing_real.tsv(1,369 수집대상, 대부분 not_indexed 의 proxy-existssame=LIST_V2 밖이라 별도 인덱싱 필요) + recheck(mod_unparsed) 121. - 미해결/후속: 실제누락 1,369(LIST_V2 밖 proxy-exists)은 pending 백필로 안 잡힘 → 직접수집/인덱스 추가 필요(별도 작업). 백필은 멱등·재개 가능(
--date명시 필수, 날짜 롤오버 주의). → 2026-06-22 해소(W26 참조):backfill_missing_real.py로 1,369 전량 직접수집(collected 1,348 + skip 21, unresolved 0/err 0).
GBrain MCP applied to Claude Code, Codex, and Hermes
- Date: 2026-06-18. Repo:
llm-wiki. - Installed Bun
1.3.14and GBrain0.42.51.0; initialized a local PGLite brain withgbrain init --pglite --no-embedding --yes. - Added
gbrainMCP server to all three local agent clients using/home/khw-bot/.bun/bin/gbrain serve:
- Claude Code: claude mcp add -s user gbrain -- /home/khw-bot/.bun/bin/gbrain serve. - Codex: codex mcp add gbrain -- /home/khw-bot/.bun/bin/gbrain serve. - Hermes: hermes mcp add gbrain --command /home/khw-bot/.bun/bin/gbrain --args serve with all 92 GBrain tools enabled.
- Verified client-side registration:
- claude mcp list reports gbrain ... ✔ Connected. - codex mcp list and codex mcp get gbrain show enabled stdio server with command /home/khw-bot/.bun/bin/gbrain and arg serve. - hermes mcp list shows gbrain enabled. Hermes needs a new session before the tools appear in the active toolset.
- Registered
llm-wikias a GBrain source and synced it with--no-embed: 169 pages / 814 chunks. Keyword search/query smoke tests forLLM Wikireturned expected wiki pages. - Fixed one corrupted Markdown byte in
docs/superpowers/plans/2026-06-10-study-blog.md: an actual NUL byte inside a code snippet was replaced with the literal text escape\\x00, allowing GBrain sync to complete. - Installed GBrain
retrieval-reflexintegration into the repo, addingskills/retrieval-reflex/SKILL.mdand the resolver row inAGENTS.md. - Durable guide added:
ai/wiki/concepts/gbrain-agent-memory.md, including setup, verification, agent usage, and how to install the retrieval-reflex plugin in repos that lack it. - Limitation: embeddings are not active because no
ZEROENTROPY_API_KEYis configured; GBrain keyword search works, while vector/hybrid quality should be improved later by setting the key and runninggbrain embed --stale.