요약 풀의 머신별 완료 실적(맥미니 vs 맥북)을 /api/queue/overview 응답에
summarize_by_machine 로 노출. rows_to_summarize_split 이 이미 계산하던 값의
additive 투영 — 신규 수집 SQL/마이그 0. 통합 보드 레인의 오프로드 가시화
(맥북이 요약 86% 처리) 재료. + FE 타입 동기 + store 신선도 timestamp(B-4).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- 흐름 뷰 메인: 좌→우 노드(머신·엔진 태그, 유입 우세 amber, 실패 뱃지) + 머신 스트립(모델 표기) + trend_24h 스파크라인 첫 렌더
- 노드 클릭 상세 패널: KV 4칸 + 다중 stage 행 + 지금 처리 중
- 실패 처리 드로어: 에러 패턴 그룹 + 재시도/건너뛰기 (영구 실패의 첫 사용자 조치 경로)
- API: stages[].done_1h/created_1h 노출 + GET /api/queue/failed + POST /api/queue/retry|/skip (uq_queue_active 충돌 skip, 건너뛰기는 enqueue_next_stage 미호출)
- 엔진/모델 표기 = queueDisplay.ts 정적 맵 단일 지점 (모델 교체 시 1곳)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
'대기만 보이고 성공은 안 보인다' 피드백 반영:
- overview 에 stages[] 노출 (stage 별 done_today + oldest_pending_age, SQL 1필드 추가)
- 게이지 의미 전환: 단계 간 대기량 비교(amber) → 단계 내 오늘 진척(완료=green 비율,
가득 찬 초록 = 다 끝남) + 처리 중 pulse dot
- 움직임 없는 단계는 행 제거, 하단 '비어 있음: ...' 한 줄로
- 라벨 누수 fix: details 가 구 STAGE_LABEL 을 쓰던 것 → queueStageLabel 통일
(deep_summary/markdown/summarize/chunk/fulltext 한글화)
- 헤더: 오늘 N 완료(성공 가시화) · 실패(error) · 대기. 데이터 소스 = overview 단일화
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
plan ds-processing-ui-6an (시안 choice 채택: 안2 1차 + 안5/6 지원):
- GET /api/queue/overview — 머신(GPU/맥미니/맥북) 귀속 라이브 집계 5쿼리, 마이그레이션 0.
summarize 풀 완료 실적은 documents.ai_model_version 조인으로 맥북/맥미니 분리,
보류(deferred_until)=맥북 카드 귀속, state=active/deferred/idle. raw 모델명 비노출
- 홈: 처리 머신 보드(3열 카드 + 지금 처리 중 제목) + ETA 라인(유입 우세 시 null 명시),
기존 stage 테이블은 details 접힘으로 강등 (구조 개편)
- 전 페이지: 상태 스트립(처리중·대기·실패·맥북 칩) + 우측 드로어(QueueDrawer,
dialog a11y) — 공유 60s 폴링 store, 경량 fetch(401 강제 logout 부수효과 회피)
- tests: 판정부 30건 (귀속/풀 분리/state 9케이스/ETA 경계/trend 버킷/계약 shape)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
[id] 전체보기에만 있던 개요 rail/점프를 메인 /documents 3-pane 중앙 리더로 확장
(사용자 주 사용 표면). 경로 A anchor 인프라 그대로 재사용.
- /documents/{id}/sections fetch(loadSections, doc.id 가드) → 좌측 SectionOutline rail
(showRail = 표시가능 절 有 + markdown-ish 본문). window 빈제목 31% 노이즈는 outlineSections
필터로 표시 제외(클린업, 코퍼스 무터치).
- anchorMap = buildAnchorMap(mdRenderText, sections) — 각 분기가 실제 렌더하는 텍스트 기준.
MarkdownDoc(markdown/pdf/hwp/article)에 anchorMap 전달 → <span id=sec-N> splice.
- jumpTo = scrollEl 내 #sec-{id} scrollIntoView. scroll-spy = scrollEl scroll 리스너로
상단 통과 마지막 .md-anchor → activeKey(SectionOutline 강조). $effect cleanup.
- 본문을 [rail | scrollEl] flex 로 래핑(비-섹션 문서는 rail 미표시=기존 그대로). pdf 분기는
자체 overflow 제거하고 scrollEl 단일 스크롤로 정리(iframe h-[80vh]).
id↔id 점프라 중복제목·비-ATX 정확, anchor 없는 절=비활성(폴백). FE only, BE 무변.
vite build + node test 10/10 + lint:tokens(신규0) PASS.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
불만② 개요→본문 점프의 deterministic anchor 좌표 산출(경로 A, FE-only).
게이트 측정상 textContent 매칭은 중복 63%·비-ATX 로 5% + silent 오점프 → md_content
에서 각 절 heading 라인 offset 을 찾아 <a id="sec-{chunk_id}"> 주입 좌표를 만든다.
★ false-early-match 방어 3중 (적대 리뷰 반영):
- 라인-시작(전체-라인) 매칭 → 본문 중간 상호참조("see Part UW")는 라인 전체가 제목과
같지 않아 제외(forward-cursor 가 못 막던 핵심 구멍).
- 전체 매칭 + truncation(builder [:200]) 처리 → '제1조'가 '제1조의2' 오매칭 차단.
- 단조 커서 + 코드펜스 회피 → 역행/펜스 매칭 거부 = anchor 없음(점프 비활성, 오점프 금지).
window/section_split 조각·빈 제목은 skip. node test 10/10 PASS(상호참조 선행·중복 단조·
prefix·평문 제N조·펜스·window·miss·heading_path fallback). 순수 함수, vite build PASS.
다음 commit = MarkdownDoc splice + SectionOutline 점프 + DocumentViewer rail/scroll-spy.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
메인 /documents 3-pane 의 중앙 리더(DocumentViewer)가 md_content 를 안 쓰고
PDF=raw iframe·md/txt=plain marked(extracted_text)만 렌더하던 이원화 제거.
"전부 MD화" 한 canonical markdown 이 전체보기 없이 메인에서 바로 보이게 함(불만①).
- viewerType.ts 신설: 분류 단일 source(상세페이지와 공유 예정, drift 차단).
csv/json/xml/html→text(<pre>, 콤마 뭉침 회피), office→preview-pdf, hwp→hwp-markdown.
- DocumentViewer: 자체 getViewerType/renderMd(본문) 제거 → viewerType.ts + MarkdownDoc.
- pdf: canShowMarkdown(isMdSuccess+md_content) 시 MarkdownDoc 기본 + [Markdown|PDF원본]
토글 + MarkdownStatusBadge, 아니면 PDF iframe. lastDocId 가드는 fullDoc.id(prop) 키잉.
- markdown(md/txt): MarkdownDoc(extracted_text=표시·편집 단일 필드), 편집 유지.
- hwp-markdown/article: MarkdownDoc(앵커/KaTeX/이미지). 편집 미리보기만 plain marked 유지.
- article/preview-pdf/image/text/cad/synology/unsupported 분기 보존(회귀 금지) + synology 신설.
API md_status='completed'(S1 validator live) 대응 = isMdSuccess. FE only, BE/스키마 무변.
vite build + lint:tokens(신규 위반 0) PASS. 후속: 개요 rail·안전점프(commit 2), [id] 정합(commit 3).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
S1 backend(이미 main 머지, app/api/documents.py field_validator
_db_success_to_completed)가 직렬화 시 DB 'success'를 API 'completed'로 remap한다.
그런데 프론트 3곳이 raw 'success' 만 검사 → S1 backend 배포 시 침묵 회귀:
- documents/[id]/+page.svelte canShowMarkdown: completed PDF가 markdown-first
대신 raw PDF로 표시
- documents/+page.svelte 인스펙터 칩 게이트: success 문서 칩 사라짐
- MarkdownStatusBadge: 'completed'→default→null (성공 칩 사라짐)
DB↔API enum divergence guard: 두 어휘를 모두 성공으로 취급해야 S1 배포
전(API='success')·후(API='completed') 모두 안전. 단일 source 헬퍼로 수렴.
- lib/utils/mdStatus.ts 신설: isMdSuccess / isMdStatusVisible (raw 비교 산재 금지)
- [id] canShowMarkdown → isMdSuccess()
- documents 인스펙터 게이트 → isMdStatusVisible()
- MarkdownStatusBadge: case 'completed' 를 'success' 동의어로 추가
FE only, 백엔드/스키마/마이그레이션 무변. vite build + lint:tokens(신규 위반 0) PASS.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
documents/+page.svelte 인스펙터의 md상태 칩이 doc.md_status==='completed'
비교였는데 실제 enum은 success/partial/skipped/failed/pending 이라 'completed'가
존재하지 않음 → success 여도 항상 text-warning(노랑)으로 표시되던 라이브 버그.
- documents/+page.svelte: 깨진 삼항을 MarkdownStatusBadge 재사용으로 교체.
success→success(초록) 자동, pending/null→null 이라 article(news) 칩 자동 suppress.
표시 조건을 badge 가 렌더하는 5상태로 명시(빈 라벨 행 방지).
- MarkdownStatusBadge: partial case 추가(tone warning 'Markdown 일부') →
대형 split 일부 실패 문서도 칩 노출 + md_status 표시 어휘를 단일 컴포넌트에 완결.
FE only, 백엔드/스키마 무변. vite build + lint:tokens(신규 위반 0) PASS.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
diagnosis는 cross-topic(사용자 단위) 코칭 표면인데 기존엔 /study/topics 상단에만
노출돼 발견성이 낮았다. 허브(/study)에 '학습 진단' 카드 추가 + 전용 라우트
/study/diagnosis 신설(향후 weekly_recap·review_set_draft 코치 표면의 정식 홈).
패널은 StudyDiagnosisPanel 공유 컴포넌트로 추출 — topics·diagnosis 양쪽이 단일
청크 참조(복붙 drift 0). 백엔드 무변경(기존 POST /diagnosis/generate 재사용).
검증: vite build OK, lint:tokens 내 파일 위반 0, 새 라우트·허브 링크·공유 청크
번들 반영 확인.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
확정 컨셉=노트 피드(d1, 5안 권장 1순위). 현재 페이지가 이미 단일 컬럼 카드
피드 패러다임이라 focused 업데이트:
- 빠른 캡처 컴포저 상단 고정(sticky) — d1 핵심
- 비-세이지 팔레트(indigo/blue/emerald/rose/amber) → 디자인 토큰 하모나이즈
(AI 분류 배지·음성 배지·승급 버튼·promoted 링크). 기능 회귀 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
확정 시안 morning-briefing-final 의 '편집 신문 1면'으로 재구조화.
- 마스트헤드(제호·날짜선택·에디션메타·오늘의 한 줄 deck·통계·상태 가드 배너)
- 리드 토픽 전체너비(관점 2열) + 나머지 2열 그리드, folio/serif 헤드라인
- 국가별 관점(색칩+기사ID 링크+요약)·차이/공통 ednote·인용(serif)·지난 흐름
- 이모지 국기 → 국가 색칩(no-emoji 규칙). 읽음/별표/날짜 등 전 기능 보존.
데이터·API(/briefing)는 기존 그대로. 기존 news lint:tokens 51 위반도 해소.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
확정 시안 dashboard-sage-3 의 권장 합성(안1 데일리 홈 골격 + 안2 검토/파이프라인
위젯 + 안3 도메인 분포 한 줄)으로 콘텐츠 재구조화. F1 세이지 테마 위 레이아웃 개편.
- 인사 헤더 + 오늘 요약 띠(검토 대기 + 디제스트 톱 + 스탯 띠)
- 2열: 좌(빠른 캡처·활동 타임라인) / 우(학습·도메인 분포+파이프라인 칩·고정)
- digest/도메인 분포는 기존 엔드포인트 wiring(백엔드 변경 0), 학습 streak는 링크형 degrade
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
검토 지적: 탭 바꿔도 selected 잔존 → 탭별 독립 선택으로 setTab 에서 selected={} 리셋. (선택 복습은 이미 현재 탭 shown 기준이라 데이터 오염은 없었고 UX 정합 개선.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
/study/review-box: GET /study-cards/due(review_stage) 를 2탭 분리(오늘 할 일=review_stage 보유 / 미확인=review_stage null 신규). 카드 멀티셀렉트 → pendingReviewCards store 로 cards-study 복습 세션에 선택분 전달(백엔드 세션 X = eid contention 중 fastapi 무재빌드). '이 탭 전체 복습'도. 완료 탭은 졸업카드 엔드포인트 필요라 비활성('추후'). 허브에 복습함 진입 카드.
- 신규 store /stores/studySession.ts(pendingReviewCards). cards-study startReview 가 consume. 전부 frontend-only.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
cards-review view 모드가 cue/cloze/fact/근거를 평문으로 뿌려 표·**굵게**·수식이 raw 노출. cards-study와 동일하게 renderMathMarkdown(근거 블록)·renderMathMarkdownInline(앞면·정답) 적용. 편집모드 textarea는 raw 유지.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
manual 카드 그룹은 source_question_id=null 이라 자료가 2개+ 면 {#each ... (g.source_question_id)} 키 중복 → Svelte each_key_duplicate 크래시. 키를 (source_question_id ?? question_text) 고유값으로 변경. 추가로 자료 그룹은 approve-batch 가 source_question_id:int 필수라 422 → 일괄승인 버튼을 question 그룹에만 노출. 개별 승인/수정/삭제는 cardId 기반이라 자료도 정상.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
데스크탑서 좁은 카드 하나만 휑하던 문제 해결. 모바일 단일 카드는 그대로, md+ 에서 3밴드 그리드.
- 좌: 진행 n/total + 카드별 결과 점(marks: correct/unsure/wrong/seen/flagged) + 집계
- 중앙: 무대 카드(max-w-600·확대 타이포·shadow), 평가 버튼
- 우: reveal 시 근거 fade-in(자리 예약=레이아웃 점프 0), 미reveal 시 빈 칸
시안 A(Focus Stage) 채택. 컨테이너 md:max-w-5xl, 랜딩 md:max-w-xl 제약.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
사용자 의도 정정: 신고 버튼은 퀴즈가 아니라 암기카드 학습(cards-study) 안에 필요했음.
- 복습·그냥공부 카드 우상단에 '이 카드 이상해요' 버튼. PATCH /study-cards/{id} {needs_review:true} → flagged_by='user' → 학습 큐에서 빠지고 검수함(/study/cards-review)으로 복귀. 신고 후 advance()로 다음 카드.
- 카드 backend(update_card needs_review set)는 기존 — 프론트 1파일만.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
백엔드(needs_review/flagged_by 컬럼·PATCH·needs-review 큐 API)는 P1 때 깔렸으나 이를 쓰는 화면이 없어 사실상 미구현 상태였음. 프론트 UI 보강(백엔드 무변경).
- 퀴즈 세션·문제 상세에 '이 문제 이상해요' 플래그 버튼(PATCH needs_review toggle, flagged_by='user'). 신고/해제 토스트.
- 신규 /study/questions-review 신고함: 전 토픽 횡단 목록 + 사유칩(직접신고/문제수정됨/문제삭제됨) + 문제보기·수정 링크 + 검토완료(해제)·폐기(soft-delete).
- 허브에 '문제 신고함' 카드 + count 배지(GET needs-review/count).
- 퀴즈 세션 신고 상태는 세션 내 optimistic(결과 payload 에 needs_review 없음, 영속 source=신고함 큐). flagQuestion 은 PATCH 응답 needs_review 반영.
검증: 적대검토(runes·API계약·UX) 통과 — blocker(payload 미포함)는 프론트 init 제거로 해소(study_topics.py 미편집=타 세션 작업 보호). 기존 이모지(repeatBadge/근거)는 본 변경 무관.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
B2 /due 가 due_at<=now(progress 보유) 카드만 반환 → progress 는 rate_card(=/rate)로만 생기고 /rate 는 /due 카드만 평가 → 신규 승인 카드가 SR 큐에 영영 못 들어가는 순환 갭. 복습 트랙이 절대 안 채워짐.
- /due 를 outerjoin 으로 재작성: 신규(progress 없음=첫 회상 전) OR 예정 due(due_at<=now, stage<4). 예정 due 먼저, 신규(due NULL) 뒤로. '첫 회상 후 due' 규칙·시안('오늘 복습'에 stage0 신규 포함)과 일치.
- 신규 카드 '암'은 백엔드가 due 안 박음(외움→큐 제외, 큐 폭발 방지)이라 correctLabel(null)='안 나옴'으로 정합(기존 '+3일'은 거짓 라벨). 큐 stage0 '암'은 그대로 '+3일'.
검증: py_compile OK. 신규 암→progress(due null, 재출제 X) / 애매·모름→due 내일 입고 / 큐 stage 전진 불변.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
직접 추가 자료 카드(source_kind='manual', 출처 문제 없음)가 검수 UI에서 null 한 덩어리로
뭉치지 않도록 extra.material 별 그룹("[자료] ...") + CardItem.source_kind 노출(프론트 '직접 추가 자료' 라벨).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
PR-3 of DS AI routing policy (2026-05-23, see plan
~/.claude/plans/document-server-ai-cheeky-reddy.md +
memory project_document_server_ai_routing_policy).
기존 BackendSelector (PR-DocSrv-Web-Ask-Selector-1, 2 옵션 default
qwen-macbook) 확장 — 4 옵션 + DeviceToggle inline.
UI 변경 (frontend/src/routes/ask/+page.svelte):
- BackendChoice = auto | mac-mini-default | qwen-macbook | claude-cloud
(기존 default 는 legacy alias, auto 또는 mac-mini-default 로 자동 매핑).
- select 4 옵션 (Auto router / Mac mini default / This device /
Claude Cloud) + tooltip.
- DeviceToggle (checkbox 'This is M5 Max') inline — localStorage
ds_device_self_label = macbook-m5-max | null. mount 시 복원.
- This device 옵션 disabled state = !isMacBookM5Max (토글 off 시
grey-out). 토글 off 시 qwen-macbook 선택돼 있었으면 auto 복귀.
- Claude Cloud 옵션 disabled state = !CLOUD_DEV_ENABLED (build-time
flag VITE_ENABLE_CLOUD_BACKEND_DEV, default false). 운영 토글
불가 — 후속 PR DS runtime feature flag API 로 migrate 예정.
- friendlyErrorMessage(reason) — 503 error_reason 매핑
(macbook_unavailable / provider_not_configured / router_* / upstream_*).
- retryWithDefault → retryWithMacMiniDefault 명명 정정.
- parseBackend backward-compat: default / gemma-macmini →
mac-mini-default.
source IP 의존 0 (PR-0 round 2 발견: caddy 2-hop + X-Forwarded-For
미설정 → DS 가 보는 source IP = LAN gateway, 신뢰 불가).
사용자 명시 토글 + localStorage 방식 채택 (Q3=C).
Closure (build + bundle string + lint):
- frontend build PASS (SvelteKit/TS syntax + svelte compile 모두 OK).
- 컴파일된 bundle 에 9 핵심 string 박혀있음 (mac-mini-default /
qwen-macbook / claude-cloud / Auto router / This is M5 Max /
ds_device_self_label / provider_not_configured / This device /
Cloud backend not configured).
- lint:tokens 본 PR 변경 위반 0 (기존 62 stale debt 는 별 chore
PR-DocSrv-Frontend-Token-Cleanup-1).
Backup: ~/.local/share/ds-routing-pr2-backups/20260523/
ask-page.svelte.pre-pr3.
선행: PR-1 (llm-router alias scaffold) + PR-2 (RouterBackend
dispatcher, refactor commit bcf644f) closed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>