hyungi
e1da984e08
refactor(study): SR 산술 sr_schedule.py 공용추출 (B1 — 카드 SR 토대)
...
문제 SR과 카드 SR이 같은 간격 상수·산술을 참조하도록 순수함수 추출. 운영 동작 무변경.
- app/services/study/sr_schedule.py: REVIEW_INTERVAL_DAYS{1:3,2:7,3:14}/MASTERED=4/FIRST_DUE=1
+ advance(stage,outcome,now)→(new_stage,new_due) | None(skipped) + first_due(now).
진입 게이트(due_at IS NOT NULL/최초 due/skipped 불변)는 호출부 잔류(finalize vs review-complete 정책 차이).
- session_finalize.py: 상수·advance 분기 → sr_schedule import + sr_advance() (re-export 유지).
- study_question_progress.py: DEFAULT_FIRST_DUE_DAYS → sr_schedule import.
- 회귀 테스트 7/7: 전진 1·3·7·14·졸업·리셋·skipped불변·상수 + 전 stage×outcome 구 로직 바이트 동등.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-07 10:11:38 +09:00
hyungi
e9a95934ef
feat(study): 카드 검수 그룹핑 — manual(직접 추가) 카드를 자료(material)별 묶음 + source_kind 노출
...
직접 추가 자료 카드(source_kind='manual', 출처 문제 없음)가 검수 UI에서 null 한 덩어리로
뭉치지 않도록 extra.material 별 그룹("[자료] ...") + CardItem.source_kind 노출(프론트 '직접 추가 자료' 라벨).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-07 09:41:13 +09:00
hyungi
b9f2ade55e
feat(study): 암기카드 검수 UI — 백엔드 카드 review API + SvelteKit /study/cards-review
...
577 카드(needs_review=true)를 보고 채택/수정/폐기하는 첫 검수 화면(학습 흐름 '마지막 한 칸' 1번).
- 백엔드 app/api/study_cards.py(prefix /api/study-cards): GET(출처 문제별 그룹, evidence 동반)·needs-review/count·PATCH(승인 needs_review=false / 수정 시 dedup_hash 재계산+검수완료)·DELETE(soft)·approve-batch(문제 단위, 전체 일괄승인 없음).
- 프론트 /study/cards-review: 반응형 그룹 목록(문제+카드) · 카드별 승인/수정(인라인)/삭제 · 문제 단위 일괄승인 · format 필터 · 세이지 토큰. study 허브에 진입 링크+대기 카운트 배지.
- 카피 drift 정정: 허브 '예정(Phase 2~)'이 가동 중인 퀴즈/SRS/통계를 잘못 표기 → 예정은 카드 SRS·모바일·알람으로 수정.
검증: 백엔드 부팅+라우트 등록 OK(4 route). 프론트 빌드는 배포 시 vite.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-07 08:49:11 +09:00
hyungi
19f544fb5e
feat(study): 공부 암기노트 Phase 1 — 정정/삭제 훅 + needs_review 큐 + 알람 재료 (HR/A)
...
추출 파이프라인(287~298, 별 커밋) 위 HR/A. 신규 마이그레이션 0 (DDL은 295~298 재사용).
- HR 정정/삭제 훅: PATCH 본문 수정 → 파생 study_memo_cards needs_review=auto(source_changed),
soft-DELETE → source_deleted. flag_cards_for_source 헬퍼(임시 플래그, 최종정리는 워커 supersede).
- HR needs_review: PATCH set/clear(flagged_by='user' 서버강제) + GET /study-questions/needs-review
목록·count(부분인덱스 술어 일치, 동적 {id} 라우트보다 먼저 등록해 int 파싱 충돌 회피).
- A 알람 재료: study_topics.focused_at 공부중 토글 + study_reminder cron(09/13/19 KST, due 술어
quiz_selection SQL 재현·시간슬롯 truncate 멱등·LLM 0) + GET /api/study-reminders/latest(없으면 204).
- 테스트: 가드/정규화 18/18 (정량=evidence 원문·cue/cloze 누출·dedup·배치).
검증: 앱 부팅 import+mapper OK · 가드 18/18 PASS.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-07 08:08:55 +09:00
hyungi
0a7402b327
feat(study): 공부 암기노트 Phase 1 — card_extract 추출 파이프라인 (순수 additive)
...
study_memo_cards 추출 파이프라인 + 버전키 폴러 + needs_review 컬럼. 운영 SR 코드(session_finalize/quiz_selection) 무수정.
- migrations 287~298: study_memo_cards/_evidence/_jobs/_progress(P1 휴면)·study_reminders·study_topics.focused_at·study_questions needs_review 3컬럼. dedup PARTIAL UNIQUE(deleted_at IS NULL).
- 워커: in-process RAG gather → MLX {cards} → 카드 가드(정량=evidence 원문 등장·cue/cloze 누출·dedup) → supersede 구버전 retire → append. 별 consumer 로 기존 study_queue 격리.
- 폴러 study_card_enqueue: 버전키 NOT EXISTS(source_version) 멱등 + ai_explanation_generated_at NOT NULL 가드 + per-poll LIMIT(thundering-herd).
- 검증: 실 prod 스키마 덤프 위 12 마이그 적용 OK + dedup/supersede/active-unique 기능 7/7 PASS + 정규화 util 15/15.
plan: PKM plans/2026-06-05-study-memo-card-p1-plan.html
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-06 21:33:12 +09:00
hyungi
f512d94c74
feat(app): ds-app 네이티브 클라이언트(S2 AIFabric + S3 macOS 앱)를 clients/ds-app 로 통합 — monorepo, 원종=Document Server. 계약(contract/)을 백엔드와 동일 repo 에서 co-evolve, 배포는 build context 분리(./services·./app·./frontend)로 무영향
...
git-subtree-dir: clients/ds-app
git-subtree-mainline: a24e3e6f22
git-subtree-split: 5206cf3b0c
2026-06-05 09:52:50 +09:00
hyungi
a24e3e6f22
ops(deploy): .dockerignore 에 clients/ 추가 — 서버 이미지 빌드 컨텍스트에서 네이티브 앱 제외 (build context 는 ./services·./app·./frontend 분리라 무영향, 방어적)
2026-06-05 09:52:37 +09:00
hyungi
5206cf3b0c
feat(s3): A-6 Xcode .app 타깃 (xcodegen) — 실행 가능한 macOS 앱
...
bare SPM 실행타깃은 .app 번들/Info.plist 없어 macOS 액세서리로 취급 → Cmd+R
윈도우 미표시. xcodegen project.yml 로 진짜 application 타깃 생성.
- @main 셸을 Sources/DSApp → App/DSApp.swift 이동 (SPM 간섭 제거, SPM 은
라이브러리+테스트만 소유 → swift build/test 백엔드-free 유지).
- Package.swift: executableTarget DSApp 제거, AppFeature library product 추가
(App 타깃이 로컬 SPM product 로 의존).
- project.yml: application 타깃 DSApp(.macOS 26, Swift6 mode), Info.plist(APPL,
LSUIElement 없음=일반 윈도우 앱) + entitlements(app-sandbox·network.client·
files.user-selected) → Support/ 생성, xcodeproj/Support 는 gitignore.
검증: swift build + swift test 72 green / xcodebuild BUILD SUCCEEDED (서명 off
스모크 + ad-hoc 서명 빌드 둘 다) / DS.app 실행 확인(pid 생존·sandbox 크래시 0).
사용자 경로: `xcodegen generate` → DSApp.xcodeproj 열기 → My Mac → Cmd+R.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-05 07:39:47 +09:00
hyungi
c44c4fae83
merge: consolidate S3 app (feat/s3-app) into main
...
S2 라이브캡처(main +2) + S3 스캐폴드~FU-B seam(feat/s3-app +5) 단일 mainline 수렴.
merge-base=5383a93, 파일 겹침 0 (AI/contract vs DSKit) → 자동 병합.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-05 07:33:58 +09:00
hyungi
c8c7fa22fc
feat(s3): RootView #Preview 추가 (Xcode 캔버스용)
...
DEBUG-gated #Preview(AppModel.preview + loadInitial). bare SPM 에서는
프리뷰 불안정하나 A-6 .app 타깃에서 캔버스 렌더용으로 보존.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-05 07:33:58 +09:00
hyungi
3ba4e7e777
feat(ai-fabric): S2-Ff 라이브↔fixture 드리프트 감지 (비차단 runbook)
...
contract/contract-check.sh + contract/shape_diff.py — 라이브 엔드포인트 재호출 →
동결 fixture 와 키/타입 *모양* diff(LLM 스칼라 값 무시). 드리프트 = 비0 exit + 재캡처 안내.
PR 게이트 아님(수동/Tailscale-CI 트리거). 가시적 스킵(silent green 금지).
- llm-router /v1/chat/completions ↔ llm-router-chat.response.json (라이브 실행 PASS)
- DS /search/ask ↔ ask.json (best-effort, 인증 필요시 가시 SKIP)
- exit 0=드리프트없음 · 1=breaking 드리프트 · 2=전부 도달불가(green 아님)
- 음성 테스트 검증: 타입변경/키삭제 드리프트 감지 + exit 1 확인(no-op 아님)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-05 07:15:34 +09:00
hyungi
f6bb830c8e
fix(ai-fabric): LocalMLX 라이브 fixture 캡처 + 모델명 정정 (mac-mini-default)
...
맥미니 GUI 로그인 복구(GPU 점프 경유 Screen Sharing) 후 llm-router :8890 라이브 캡처 → S2-2a 완료.
- llm-router-chat.{request,response}.json: PROVISIONAL_SYNTHETIC → CAPTURED_LIVE (2026-06-05)
- 모델명 'gemma-macmini'(= DS backend 이름, llm-router 모델 ID 아님) → 'mac-mini-default'
(/v1/models 실측 확인, 별칭 → mlx-community/gemma-4-26b-a4b-it-8bit resolve)
- LocalMLXProvider/AIProviderConfiguration 기본 모델 + 관련 테스트 갱신
- testLiveLocalMLXIfReachable 추가(실 :8890 e2e, offline 시 skip). 47 tests PASS.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-05 07:01:29 +09:00
Hyungi
b9b5188265
feat(s3): DSAskClient HTTP bridge + realRouter seam (FU-B)
...
- LiveDSAskClient: S3-owned concrete DSAskClient (GET /search/ask -> decode AIFabric.AskResponse),
the piece S2's plan assigned to S3 for the real RemoteDSProvider
- AppAIComposition.realRouter(): makeDefaultRouter(client: LiveDSAskClient) — the one-call swap from
mock to the real S2 fabric; app default stays mockRouter (offline scaffold)
- DSError.from made public (used cross-module by the bridge)
swift build + swift test green (71). Sources/AI untouched.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-05 06:44:18 +09:00
Hyungi
52aa99ec8e
merge: integrate AIFabric (S2) into S3 app — unified package
...
- Resolve Package.swift add/add: one manifest, single AIFabric target (Sources/AI compiled once;
no duplicate-symbol risk) + DSKit/AppFeature/DSApp + AITests + DSKitTests, AIFabric library product kept.
- import AI -> import AIFabric across AppFeature + RouterFallbackTests (S2 renamed module).
- AppModel.askMeta qualified DSKit.AskResponse (AIFabric also defines an AskResponse for RemoteDS).
swift build + swift test green (71 tests: S2 AITests + S3 DSKitTests). Frozen AIProvider interface intact.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-05 06:41:30 +09:00
Hyungi
3520c8f82a
feat(s3): LiveDSClient + Endpoint + Keychain/TokenProvider (FU-A plumbing)
...
- DSEndpoint: method/path/query/body single source (trailing slashes preserved, nil query skipped)
- KeychainStore + InMemoryTokenStore (TokenPersistence); TokenProvider actor with single-flight refresh (Task handle, cleared on completion)
- LiveDSClient: URLSession + shared cookie storage, Bearer injection, 401 -> single-flight refresh -> one retry (never on login/refresh/logout); same DTOs/decoder as fixtures
- Tests: endpoint path/method/query/body + single-flight (fires once) + token cache/persist
swift build + swift test green (25). Live HTTP path itself is FU-A (needs real backend). Sources/AI untouched.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-05 06:38:07 +09:00
Hyungi
560efb9554
feat(s3): SwiftUI sage 3-pane shell + 6 pages + AI seam
...
- AppFeature: SageTheme tokens, AppModel (@MainActor @Observable store), RootView (DEVONthink NavigationSplitView), Dashboard/Documents(MD-first+pending fallback+?token= download)/Search/Ask/Memos/Digest pages
- AI seam: AIService actor + AIResult, AppAIComposition (MockAIProvider x4 tiers), AICompletionView (numbered citations + always-visible routing badge), backend picker with visible explicit-unavailable error
- MarkdownView: block-aware renderer (GFM table separator-row skip, AttributedString inline-only)
- DSApp: thin @main, injects FixtureDSClient + mock AIRouter (zero backend / zero LLM)
swift build (full app) + swift test (19) green under Swift 6 strict concurrency. Sources/AI untouched (isolation vs freeze 17f8830 = clean).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-04 17:26:02 +09:00
hyungi
5383a93f98
feat(ai-fabric): S2 LLM 패브릭 4 provider 결선 + 컴포지션 루트
...
risk-first 채움(RemoteDS→LocalMLX→OnDevice→Specialized) + makeDefaultRouter 컴포지션 루트.
동결 인터페이스(AIProvider/AIRouter/MockAIProvider) 무변경. SPM AIFabric 단독 빌드·테스트(46 PASS).
- RemoteDS: DSAskClient seam + AskResponse(ask.json) 매핑 + backend exhaustive switch(qwen/cloud TODO)
- LocalMLX: GET /v1/models probe + OpenAI /v1/chat/completions system/user call-shape + non-200 backendError
- OnDevice: FoundationModels 라이브(M5 Max) availability + respond() + GenerationError 9-case 매핑 + stateless/prewarm
- Specialized: scaffold-only(명시 unavailable, vision 폴백 가시화), cloud='claude-cloud' 503
- config 단일소스(env override) + 타임아웃/취소(URLSession 자동 honor, OnDevice 협조적)
실측 동결(S2-3a, M5 Max): availability=available · 취소=COOPERATIVE(~33ms) · 오버플로=exceededContextWindowSize
· GenerationError 9-case(refusal·concurrentRequests 추가 발견, plan 정정).
한계: LocalMLX fixture=PROVISIONAL_SYNTHETIC(맥미니 offline → 라이브 재캡처 S2-Ff 대기).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-04 17:20:10 +09:00
Hyungi
0becf7829e
feat(s3): SwiftPM scaffold + DSKit data layer + 14-fixture acceptance
...
- Package.swift: AI (S2-owned) + DSKit (models/client/fixtures) + DSKitTests, tools 6.2, .swiftLanguageMode(.v6), .macOS(.v26)
- JSONValue (Sendable AnyCodable), DSDate (value-type ISO8601FormatStyle cascade, date-only UTC), explicit-CodingKeys decoder
- Models: Auth/Document(+Detail flat-compose, MD-first)/Catalog/Search+Ask/Memo/Digest; non-optional limited to id/file_type/created+updated_at/total
- DSClient protocol + FixtureDSClient (Bundle.module, zero backend) + DSError + DSConfig + DownloadURL (?token= query)
- Tests: 14-fixture contract acceptance (value asserts) + JSONValue number trap + Ask round-trip + AI router fallback/explicit-unavailable
swift build + swift test green (19 tests). Sources/AI untouched.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-04 17:16:55 +09:00
Hyungi
17f8830d37
feat(ds-app): freeze S1 contract + S2 AIProvider interface baseline
...
S1 = contract/CONTRACT.md + 14 fixtures + README + AI-ROUTING.
S2 = Sources/AI/{AIProvider,AIRouter,MockAIProvider} + Providers skeletons.
Baseline before S3 (device app) scaffold work begins.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-04 15:27:24 +09:00
hyungi
701113738f
merge: 편집형 /digest( 57de6a1) + UI 세이지 셸 통합
2026-06-04 05:02:11 +00:00
hyungi
cc8bdee6c1
feat(ui): 셸 재구성 — nav 4그룹·데스크탑 상시 사이드바·모바일 하단탭바 (F2)
...
+layout.svelte: 상단 nav 11개 flat → 4그룹(홈·문서▾·뉴스▾·질문, 드롭다운) +
브랜드(DS)·받은편지함·⋮(설정/로그아웃). 데스크탑(lg+)=상시 좌측 사이드바,
모바일(<lg)=하단 탭바(문서·뉴스·질문·메모·더보기) + 사이드바 드로어.
세이지 토큰 Tailwind. /news=풀스크린(상시 사이드바 없음). frontend docker build PASS.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-04 05:02:11 +00:00
hyungi
e968236796
feat(ui): app.css 테마 다크블루 → 세이지 그린 라이트 (F1)
...
UI 전면 개선 파운데이션. @theme + :root 토큰 값을 세이지 라이트로 교체
(bg #e7ebe4·surface #f4f7f1·text #23291f·accent #4f8a6b·도메인색 세이지 조화).
토큰 규율(lint:tokens) 덕에 값 교체만으로 전 페이지 전환. markdown zebra
rgba(255,255,255,.02)→rgba(35,41,31,.03) 1곳 라이트 보정. frontend docker build PASS.
검토 대상 = text-white 14 + bg-white 2 (대부분 강조색 버튼 위, 시각확인 시 점검).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-04 04:53:39 +00:00
hyungi
57de6a1072
feat(digest): 편집형 1면 레이아웃 (안1 채택)
...
/digest 단순 카드 → 신문 1면형 편집 뷰. 웜톤(크림+clay) self-contained — 앱 다크토큰 충돌 방지 위해 .digest-page 래퍼에 웜 팔레트 로컬 재정의.
- 슬롯 매핑: ALL=전국가 imp 내림차순 / country=rank 오름차순 → lead·featured 2·sidebar 3·심층 grid, graceful 생략
- 국가 nav(ALL+국가별 주제수)·edition line·중요도 막대. date picker URL sync·기사 /documents/{id} 라우팅·국가사전 재사용
- 검정·이모지·외부폰트 0. 구현+적대적 리뷰 2(ok). docker build PASS
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-04 02:55:19 +00:00
hyungi
696d8b71b0
Merge pull request 'Feat/digest ui followup' ( #26 ) from feat/digest-ui-followup into main
...
Reviewed-on: #26
2026-06-04 08:44:16 +09:00
hyungi
f269e0df27
ops(news): chunk_worker news_source 매핑 실패 가시성 가드
...
_lookup_news_source prefix 미일치 시 silent (None) 반환 → warn 로그 추가.
loader 의 drop 로그와 대칭, 신규 source / RSS category 오염 재발 즉시 가시. 동작 변경 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-03 23:39:14 +00:00
hyungi
aa2d7814e3
feat(digest): date picker URL sync + article→문서 라우팅 + country 국기·한국어
...
- GET /api/digest/dates 신설 (브리핑 /briefing/dates 패턴 미러, read-only)
- topic article 제목 enrich (documents 배치 1쿼리 + dedupe(set) + map-miss=null → 프론트 '(제목 없음)')
- /digest 재작성: ?date=&country= URL sync(공유·뒤로가기), 국가 탭=인라인 SVG 국기+한국어, 기사=/documents/{id} 링크(상위5+펼치기)
- Phase 4.5(PR #22 ) 후속. 검증: py_compile·dates/enrich 쿼리(275 resolve·miss 0)·frontend docker build PASS. 시각 렌더 검증=preview 게이트 대기
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com >
2026-06-03 23:39:07 +00:00
hyungi
cd33ded7a8
docs(search): passage-RAG go/no-go = NO-GO (hier evidence 동등, diagnose c4+c5)
...
PR-DocSrv-Hier-PassageRAG-Diagnose-1 c4+c5. 조건부 N=12(retrieval 통제) blind pairwise
(hypothesis-blind subagent, 익명 3-file split). 결과 4-way 수렴 = 동등:
pairwise prehier4/hier3/tie5(no edge) + axis ±0.08 + objective 동일(halluc36/36) +
variance~0(byte-identical 재생성). verbosity artifact 없음(prehier 더 길었으나 승+1).
=> NO-GO: hier-leaf evidence 무이득. hier leaf = section-outline UI 전용 완전 확정
(UI yes / doc-search NO-GO / passage-RAG NO-GO 3영역 종결). 2026-06-21 freeze input only.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-25 07:02:46 +00:00
hyungi
9c039139ef
feat(search): passage-RAG capture runner + raw JSONL (diagnose c3)
...
PR-DocSrv-Hier-PassageRAG-Diagnose-1 c3. 22Q x {prehier,hier_sim_clean} /ask?debug=true
exact_knn capture (44 rec). ai_answer/evidence/target_doc_present/target_span_used/
objective signals(hallucination/grounding/completeness/refused) 박제.
관찰: hier 일부 타깃 retrieval 실패(exam_005/006,cl_007=doc-search NO-GO 일관) + 일부 gain
(cl_001/002). empty-answer 케이스(cl_005/cl_007 prehier, cl_006/exam_004 skipped) 존재.
JWT 15min 만료로 1차 부분실패 → cache-warm 재실행 완주.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-25 06:53:11 +00:00
hyungi
698510bc0e
feat(search): passage-RAG answer-seeking question subset (diagnose c2)
...
PR-DocSrv-Hier-PassageRAG-Diagnose-1 c2. queries.yaml v0.2 의 answer-seeking 22문항
(exam 7 + korean_only 7 + mixed 8, decomposed-target 필터). targets_g2/g3 = 조건부 subset
산출용. broad seed (조건부 ~65-70% → N≥12 확보). 신규 authoring 0 (기존 graded 재사용).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-25 06:20:20 +00:00
hyungi
2f152911f7
feat(search): /ask corpus_variant + exact_knn (EVAL-ONLY) for passage-RAG diagnose
...
PR-DocSrv-Hier-PassageRAG-Diagnose-1 c1. /ask evidence retrieval 의 chunk leg 를
측정 뷰(prehier/hier_sim_*)로 교체 + exact_knn — passage evidence 단위(hier 절 vs
legacy 윈도우) 비교용. /search 와 동일 패턴, run_search 전달. EVAL-ONLY 박제,
default(미지정) 시 기존 /ask byte/behavior 동일(회귀 0). pattern 검증 → 잘못된 값 422.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-25 06:14:59 +00:00
hyungi
6e9d73278f
docs(search): pin hier measurement views as EVAL-ONLY (replace-diagnose)
...
COMMENT ON VIEW + header — corpus_chunks_{prehier,hier_sim_raw,hier_sim_clean} 은
?corpus_variant= eval dispatch 전용. production retrieval default-path 는 corpus_chunks
(partial ivfflat) 만. 재측정/passage-RAG 재평가 자산으로 보존, 오용 방지 박제.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-25 05:53:04 +00:00
hyungi
6a9142a2e5
docs(search): hier vs legacy go/no-go = NO-GO (replace-diagnose c6)
...
PR-DocSrv-Hier-Replace-Diagnose-1 c6 측정+결정. prehier exact vs hier_sim exact, dedup 0/51.
결정權(분해-subset n=41): prehier 0.748 -> hier_sim_clean 0.675 (-0.074 회귀). raw 0.673 (robust).
카테고리: standards(법령, hier 최적가설) flat -0.002 / exam -0.183 / korean -0.109 / english -0.088.
법령 제N조조차 개선 없음 + 대체로 회귀 → 짧은 절 leaf 가 맥락 손실. dedup clean = 실제값.
=> NO-GO: 검색 코퍼스 hier 교체 안 함. Apply PR 미진입. hier leaf 는 in_corpus=false 잔존
(section-outline UI 재료, doc-level 검색 무관). 측정은 doc-level NDCG 한정.
산출물: decision md + 4 eval csv(sanity/prehier/clean/raw exact) + subset analysis script.
in_corpus 634 전 구간 불변. default 검색 path 회귀 0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-25 05:46:14 +00:00
hyungi
100aaa3b0c
feat(search): corpus_variant + exact_knn measurement dispatch (replace-diagnose c4+c5)
...
PR-DocSrv-Hier-Replace-Diagnose-1 c4+c5. hier vs prehier(legacy) go/no-go 비파괴 측정 hook.
- 측정 뷰 3종 (hier_measure_views.sql, additive/droppable): corpus_chunks_prehier
(legacy+null-source 375 포함) / hier_sim_raw / hier_sim_clean (childless-tiny<30 제외,
all-tiny doc 은 legacy fallback 정합).
- retrieval_service: _resolve_corpus_variant + CORPUS_VARIANT_MAP + _VALID_CHUNKS_TABLE
3 뷰 추가 + exact_knn(SET LOCAL enable_indexscan/bitmapscan=off, eval 전용).
chunk leg 만 영향 (doc-level + fts/trgm = documents 무관). baseline/None path 회귀 0.
- search_pipeline.run_search + search.py: corpus_variant/exact_knn 전달, unknown→400,
embedding_backend cand 와 동시 사용 금지(400).
- run_eval: --corpus-variant + --exact-knn flag.
- tests/test_corpus_variant.py 22 PASS (resolver/map/allowlist + SQL injection 거부).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-25 05:37:15 +00:00
hyungi
e860baa179
ops(hier): Phase A law/library decompose + snapshot freeze (replace-diagnose c3)
...
47 eval-target undecomposed non-news docs (law21+library24+document2) 분해+임베딩
(--skip-analysis, additive). 1005 leaf 생성 fail0, in_corpus 634 무손상 검증.
snapshot doc_id_max=25912 chunk_id_max=71164 docs_decomposed 301->348. 측정 drift 0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-25 05:23:38 +00:00
hyungi
fc9e0f1d8f
feat(search): hier backfill --skip-analysis + --doc gate-bypass flags
...
PR-DocSrv-Hier-Replace-Diagnose-1 c2. 구조화 소형 문서(법령 등) eval coverage
보정용 — --doc 명시 리스트로 DOC_MIN_CHARS=4000 게이트 우회, --skip-analysis 로
절분석(Mac mini) 생략하고 분해+임베딩만. retrieval go/no-go 측정 준비. additive,
in_corpus 무영향. NOT EXISTS hier 멱등 가드 유지.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-25 05:21:00 +00:00
hyungi
f7198d9d68
feat(search): expose hier section outline & summaries in document detail
...
PR-DocSrv-Hier-Section-UI-1 Phase 1 (코드+커밋만, 배포는 Phase 2 backfill 완주 후).
- backend: GET /documents/{id}/sections — hier leaf 목차 + chunk_section_analysis
요약. document_chunks 직접 조회(retrieval 아닌 목차 표시라 corpus_chunks 뷰
의도적 우회 — docstring 명시). DISTINCT ON 으로 최신 분석 1행.
- frontend: SectionOutline.svelte(좌측 목차, per-doc 동적 그룹/flat, window
dedupe, 클릭 시 요약/breadcrumb 인라인), headingPath.ts 순수 유틸(+node:test
단위테스트 8케이스). [id]/+page.svelte 3-zone 레이아웃 + 우측 메타 Tabs
[정보|AI|관리] 로 카드 스프롤 해소.
- 절 없는 문서/404 는 목차 숨김(graceful). 본문 점프는 follow-up.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-25 00:22:34 +00:00
hyungi
ec174fc1e7
ops(hier): default backfill scope to all-except-news
...
기본 범위 = 뉴스 도메인만 제외, 나머지 전부(>4000자 미분해). --domains 로 allowlist override.
신규 후보 50건(general 29 + programming 13 + engineering 8). additive(in_corpus=false) 유지.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-24 22:51:13 +00:00
hyungi
c2f9dca62d
ops(hier): add section analysis backfill runner
...
hier 분해(additive, in_corpus=false) + 절 분석(Mac mini gemma-26B BACKGROUND gate)
오버나이트 backfill 러너. time-box deadline + per-doc commit + 멱등 선별(NOT EXISTS).
section_summary_pilot 상수 재사용(PROMPT_VERSION 단일화). no silent fallback.
검증: Engineering+Industrial_Safety 245 doc / 6066 절 요약 / fail 0 (2026-05-24~25).
컨테이너 TZ=UTC → deadline KST 환산 주의. 종료는 컨테이너 내부 PID kill 필수.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-24 22:47:06 +00:00
hyungi
cfadaaffd9
feat(search): hier section per-leaf analysis scaffold (Section-Summary-1 c1)
...
chunk_section_analysis 테이블(migration 286) + ORM model + pilot script.
document_chunks(retrieval-hot)와 분리된 절-레벨 분석 축. domain 상속,
section_type 절-전용 역할 enum, status로 skip 박제, source_content_hash로 stale 탐지.
script-only(scripts mount, rebuild 불필요). LLM 0 dry-run 검증 = 5225 147 analyze + 17 skip.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-24 13:45:30 +00:00
hyungi
a7b16b63db
feat(search): doc-level atomic corpus replace + isolation test (Hier-Decomp-1 c5)
...
replace_doc_corpus(dry_run): G5 precond(doc-local embed 100% + parent 무결성 + leaf>0) 검증 후
단일 트랜잭션 atomic 교체(legacy in_corpus=false / hier leaf in_corpus=true,
predicate=is_leaf AND embedding NOT NULL, node_type 미사용). 물리삭제 없음. rollback_doc_corpus 역토글.
precond 미충족 시 변경 0(legacy 유지).
tests/hier_decomp/test_corpus_isolation.py: in_corpus=false leaf 가 corpus_chunks 누출 0 단언
(부분 ivfflat + 뷰 이중 choke point 회귀 가드).
c5: dry-run 3 pilot precond_ok(5140 158L→271leaf / 5186 381→199 / 5225 18→164), 격리 테스트 PASS.
실제 replace 는 c6(1-doc-first).
plan: hierarchical-decomposition-tiered-nesting-marmot.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-24 13:14:36 +00:00
hyungi
fa82bd495b
feat(search): hier persist + partial ivfflat index on in_corpus (Hier-Decomp-1 c4)
...
persist_hier_tree(): build_hier_tree → document_chunks insert. source_type=hier_section,
in_corpus=false, is_leaf 노드만 bge-m3 embedding. idempotent(기존 hier 행 삭제 후 재삽입).
chunk_index = doc 별 (max+1) offset → 기존 (doc_id,chunk_index) unique 충돌 회피.
embedding NULL 파라미터 asyncpg 타입추론 → cast(cast(:emb AS text) AS vector) 이중캐스트.
migration 284/285: ivfflat 오염 fix. full 인덱스는 in_corpus=false hier 벡터까지 색인 →
근사 검색이 비활성 벡터에 오염(corpus_chunks 필터해도 근사 이웃 셋 흔들림). partial index
(WHERE in_corpus=true)로 교체 → in_corpus=false 는 검색 인덱스에 부재 = 무영향 인덱스 레벨 보장.
c4 pilot(5140/5186/5225) G3: 트리 insert, embed_coverage 1.0(doc-local 100%), in_corpus_true=0,
dangling_parent=0, dup 0. **부분인덱스 후 검색 baseline IDENTICAL to 원래(pre-hier)** = 691 hier
행 영향 0 검증(오염 fix 효과). replace 는 c5/c6.
plan: hierarchical-decomposition-tiered-nesting-marmot.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-24 13:12:42 +00:00
hyungi
d982dce7d1
feat(search): rule hierarchy builder (Hier-Decomp-1 c3)
...
순수 함수 build_hier_tree(text) → heading 경계 segment 트리 (DB 미접근, c4 에서 insert).
- 경계 규칙: ATX 마크다운(#{1,6}) > 한국 제N장/절/조 > 영문 Chapter/Section/Article.
- segment = heading + 다음 heading 전까지 본문 (disjoint, 100% 커버). parent/level = heading 깊이 정규화 트리.
- 과대 own-text(>HARD_MAX 5000) = 무overlap window 분해(자식 유무 무관), 부모 is_leaf=false(heading 마커, 코퍼스 제외).
- 구조 전용 heading(자식 보유 + own body<30자) = is_leaf=false. is_leaf = replace 코퍼스 편입 대상.
dry-run G2 (insert 없음, 5 pilot + headingless):
- 5140/5186/5225/5151/5124 md_content: coverage 0.9993~1.0, dup_hash 0, empty 0, dangling 0, bad_level 0, leaf_max<=4973(<5000).
- 5152 headingless extracted_text(238k): window 89 leaf, coverage 1.0, dup 0, leaf_max 3000.
관찰: tiny heading-only leaf(7~19자) 잔존(무해, tuning 후보).
plan: hierarchical-decomposition-tiered-nesting-marmot.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-24 13:05:06 +00:00
hyungi
f940f50c60
feat(search): route retrieval through corpus_chunks view (Hier-Decomp-1 c2)
...
baseline chunk 벡터검색을 document_chunks → corpus_chunks 뷰(in_corpus=true)로 rewire.
in_corpus=false(비활성 hier leaf 등) 자동 제외 = 검색 오염 구조적 차단(B choke point).
- retrieval_service: baseline chunks_table=corpus_chunks, _VALID_CHUNKS_TABLE 에 corpus_chunks 허용,
snapshot_clause 조건 corpus_chunks 포함(eval snapshot 보존). candidate(cand_*) 경로 불변.
documents 측(FTS+doc embedding) 무변경 — doc row 는 교체 무관.
- models/chunk: 5 신규 컬럼 매핑(parent_id/level/node_type/is_leaf/in_corpus). server_default 로
기존 chunk_worker INSERT 무영향(legacy=in_corpus true/is_leaf false).
- subject_note_rag/explanation_rag: RAG chunk 로드에 in_corpus=true 필터(교체 doc legacy 중복 방지).
게이트: G4b(rewire 불변) before/after IDENTICAL(현재 view==table no-op) / G4a(누출) synthetic
in_corpus=false leaf 가 corpus_chunks 0건·document_chunks raw top(dist 0.0) 양방향 증명. /health 200.
plan: hierarchical-decomposition-tiered-nesting-marmot.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-24 12:58:28 +00:00
hyungi
7971e69e3e
feat(search): hier decomposition schema + corpus_chunks view (Hier-Decomp-1 c1)
...
PR-DocSrv-Hierarchical-Decomposition-1 c1 (G1).
- migration 282: document_chunks ADD parent_id/level/node_type/is_leaf/in_corpus
(단일 statement ALTER, additive, IF NOT EXISTS). legacy 행 = in_corpus=true/is_leaf=false 기본값.
- migration 283: corpus_chunks 뷰 (WHERE in_corpus=true) = 검색 코퍼스 단일 choke point.
c2 에서 retrieval 을 이 뷰로 rewire. node_type 은 hint, replace 는 is_leaf 사용.
검증: schema_migrations 282/283, 30952 행 in_corpus=true 보존, corpus_chunks 30952,
/health 200, restarts=0. dry-run(BEGIN/ROLLBACK) 선검증 후 적용.
plan: hierarchical-decomposition-tiered-nesting-marmot.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-24 12:47:41 +00:00
hyungi
0854c72c70
fix(search): sync doc md_status to failed on permanent markdown queue failure
...
marker_worker 는 변환 시작 시 doc.md_status=processing 으로 표시하는데, 변환이
_fail()/_set_skipped() 를 거치지 않고 예외(예: 대형 batch ReadTimeout)로 죽으면
queue_consumer 가 큐 행만 failed 처리하고 doc.md_status 는 processing 에 영구 고착
= orphan (큐 failed, 문서 processing). markdown consumer 분리 후 이 orphan 이
tail 재처리에서 재발(5149/5201)하여 근본 원인 차단.
_process_stage except 블록에서 큐 항목이 영구 실패(attempts>=max)할 때 stage가
markdown 이고 doc.md_status=processing 이면 failed 로 동기화. 재시도 중
(attempts<max)엔 pending 큐 행이 남아 orphan 아니므로 미터치.
검증: synthetic 영구 실패 경로 → md_status processing→failed 동기화 PASS.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-24 12:06:32 +00:00
hyungi
2edc80d4bb
fix(search): split markdown into dedicated queue consumer to prevent pipeline stall
...
대형 PDF split 변환(5210 ≈ 40분 실측)이 단일 consume_queue 코루틴을 점유해
extract/classify/embed/chunk 등 전 파이프라인을 stall 시키던 문제 제거.
- consume_markdown_queue 신규 — markdown 전용 scheduler job (id=markdown_consumer)
- consume_queue 는 MAIN_QUEUE_STAGES (markdown 제외) 만 처리
- _process_stage / _load_workers 헬퍼로 per-stage 로직 공유
- reset_stale_items(stages, threshold_minutes) 파라미터화: main=10min(markdown 제외),
markdown=MARKDOWN_STALE_MINUTES(기본 120). marker_worker 는 heartbeat 미기록이라
40분 변환을 10분 stale 로 오인하던 함정 차단
- enqueue flow (classify -> embed,chunk,markdown) 불변
STT/deep_summary 분리 + GPU 동시성 튜닝은 out of scope (follow-up).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-24 10:33:45 +00:00
hyungi
826f66f8f5
fix(search): correct large-doc manifest wording after commit 4 drop
...
PR-DocSrv-LargeDoc-Split-Markdown-1 follow-up (plan brisk-paging-quokka.md).
commit 4(marker_section→document_chunks) 드롭으로, split md_content/manifest 의
「권위 검색본 = document_chunks (source_type=marker_section)」 문구가 실제와 불일치.
실제 = 검색 인덱스는 기존 document_chunks(extracted_text long_pdf window chunks),
marker_section chunk 부재, md_content 는 Markdown 렌더링 preview.
- _build_large_md_content 헤더: 「검색 인덱스 = 기존 document_chunks long_pdf/
extracted_text window chunks. 아래는 Markdown 렌더링 preview.」
- _split_manifest: canonical_storage(marker_section) → search_index(legacy/extracted_text)
- 상수 주석 + _process_split docstring: commit 4 드롭/이중적재 회피 반영
뷰어에 없는 source_type 으로 디버깅 오도 방지. 이미 처리된 5 docs 의 md_content 는
즉시 재처리 X — 자연 reprocess 시 갱신(사용자 결정).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-24 09:48:03 +00:00
hyungi
cf0d75fe84
fix(search): handle markdown/fileless docs without marker conversion
...
PR-DocSrv-LargeDoc-Split-Markdown-1 commit 5 (plan brisk-paging-quokka.md).
이미 마크다운인 문서는 marker 변환 불필요 → _process_markdown_passthrough 로
파일 내용(없으면 extracted_text)을 md_content 에 직접 적재(success), 비면 skipped.
- _is_markdown_doc: file_format=md/markdown 또는 .md/.markdown 확장자
- 분기 위치 = file_path validation 이전 (fileless md = file_path NULL 처리 위함)
- engine=passthrough 로 marker 변환본과 구분
기존 버그 해소: fileless md 43건=「no file_path」 fail / .md 파일=unsupported extension
skip → 둘 다 md_content 미생성이었음.
검증(docker cp 격리): 13948(.md+file_path)→success md_len=1805(파일) /
23409(fileless 931자)→success(extracted_text) / 20237(fileless 6자)→success.
PDF 경로 무영향(_is_markdown_doc=False).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-24 08:02:30 +00:00
hyungi
7aaabe2c75
feat(search): split markdown processing for large PDFs (>threshold)
...
PR-DocSrv-LargeDoc-Split-Markdown-1 commit 3 (plan brisk-paging-quokka.md).
- page_count gauge 분기: 소형(<=120p)=_process_single 통째 1-shot / 대형(>120p)=_process_split
- MAX_PAGES=200 hard skip 제거 → 대형은 BATCH_PAGES=40 page-range 윈도우 순차 변환
- 각 batch /convert start_page/end_page(1-based) 호출 + slug 충돌 회피 batch별 ref rewrite + stitch
- _persist_images_to_nas seq_offset → batch 간 image_key(img_NNN) 연속
- md_status success/partial/failed (전부/일부/전무) + failed batch manifest JSON
- 대형 md_content = head+manifest (LARGE_DOC_MD_CONTENT_HEAD_CHARS=50000), canonical=document_chunks(commit 4)
- MARKER_MAX_SPLIT_PAGES=5000 초과 = skipped_too_large 안전상태
검증: G1 소형회귀 doc6675 동일(success,6292,14)/single경로 / G2 doc5180 453p→12batch success
manifest+207img(img_001~207 연속) / G4 stuck0 restart0 각batch<300s. 섹션 chunk적재(G3)=commit 4.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-24 07:39:49 +00:00
hyungi
2528996dee
feat(marker): support page-range conversion in /convert
...
ConvertRequest.start_page/end_page (1-based inclusive); per-request PdfConverter with config page_range, reuses loaded models. 1-based->0-based contained in marker adapter. PR-DocSrv-LargeDoc-Split-Markdown-1 commit 2.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-24 07:01:34 +00:00