PPS 모노레포 · 조달청 기술평가 지원 플랫폼

로컬 전수테스트 검증 · 코드 개선 · QA 평가 리포트

메일 리포트 주장 → 실제 코드 대조 → 오프라인·실HTTP 검증 → 결함 개선 → QA셋 평가까지 전 과정 정리

브랜치 feat/unified-deploy LLM=Kanana-2-30b OCR=Datalab(shim) 임베딩=KURE-v1 작성 2026-07-09 개인용 · noindex

0요약 (TL;DR)

메일의 "전 항목 Pass"는 상당수가 커밋된 코드가 아닌 로컬 우회로 달성됨. 실코드 대조 결과 failover·busy-poll은 실제 갭이었고, 이를 개선·검증(오프라인 18테스트 + 실HTTP failover)했다. QA 프록시 평가 결과 정형 문서엔 우수, 실 비정형 문서·기본메타·지연은 목표 미달.

18/18
신규 유닛테스트 통과
3+3
개선 + 자기검토 이슈 수정
6
코드 갭 식별 (G1–G6)
3
QA 목표 미달 축

1분석 대상

자료내용
PPS_로컬_전수테스트_결과.emlself-report 메일 (C1–C16 전수 Pass 주장, 2026-07-09)
pps-test-bundle.zip (243KB)QA_RESULTS.md · env(.env·override) · scripts(datalab_shim.py·e2e·bench) · results(JSON 7종) · artifacts(pdf·hwpx·ocr)

번들은 tests/qa_datasets/local_e2e_20260709/ 에 배치. env·eml 시크릿은 .gitignore로 커밋 차단, QA 산출물만 추적.

2리포트 주장 vs 실제 코드 (갭 분석)

#리포트 주장실제 코드판정
G1Kanana 다운 시 OpenRouter failover 자동전환자동 전환 로직 전무 (예외 raise). env 토글+재기동 수동절차
G2busy-poll 병목 → dual restart로 해결wait_for_task_completion 2s폴링 + Celery PENDING 무한반환 → 좀비루프실버그
G3OCR = Datalab async→OpenAI shimrepo에 datalab 0건. shim은 repo 밖 로컬 HTTP (Chandra 요청→Datalab /convert)외부
G4OCR 캐시 187배(5.6→0.03s)실재. write=_save_ocr_cache, hit=chandra_results_dir (단 opt-in)확인
G5포트 5440/6390 overridecompose는 5432/6379 하드코딩, override 미커밋외부
G6Infisical staging(179키)dev/prod 불완전 → staging 우회env

정상 확인: 배점표(정성65/정량35)·요구사항(5+기술12) 추출은 실코드로 정상. "0/5 fields"는 별개 경로(기본메타 키워드 파싱)임을 코드로 규명.

3검증 — 오프라인 + 실HTTP 런타임

실HTTP failover 런타임 증명 (mock 아님)

primary(Kanana) → 127.0.0.1:62581  HTTP 500 (다운)
fallback        → 127.0.0.1:62582  정상
──────────────────────────────────────────
[실코드 로그] LLM failover: primary kanana_llm(kakaocorp)
             실패(LLMError) → fallback or_llm(qwen) 재시도
실제 사용 provider: qwen
실제 응답: '[FAILOVER-OK] OpenRouter가 응답함'   ✅ PASS

실제 KananaEngine이 진짜 HTTP 500 → LLMError → 실제 QwenEngine(fallback)로 전환 → 실응답 수신. 엔진 생성→HTTP→실패감지→전환→수신 전 경로 동작.

HWPX 파서 오프라인 재현

샘플 HWPX → HTML 28,675자 → 마크다운 1,691자 = 기록값 정확일치(동일 입력 확증). 사업명·예산 850M·기술평가 90:10 정확 추출. 규칙기반 요구사항추출 0건 → 핵심추출은 LLM 의존 판명.

4개선 — 3 갭 수정 + 자기검토 3 이슈 수정

주요 개선

항목수정테스트
G2 busy-pollTaskLostError+활동기반 grace: worker 생존 감지로 좀비루프 종료, 큐 대기 오판 방지6/6
G1 failoverllm_failover.py: primary 실패 시 등록된 다른 provider로 자동 재시도6/6
G4 캐시_lookup_ocr_cache: file_uuid 자동히트(opt-in 불필요)6/6

자기검토("이슈없나")에서 발견·수정한 결함

이슈심각도수정
busy-poll이 큐 대기 정상 태스크를 유실 오판 (prefetch=1 배치)회귀활동 기반 판정으로 전환 + grace 120→180s
캐시 부분저장 히트 → 잘린 OCR 조용히 반환정확성metadata.json 완료마커 + page_count 정합 검증
online.py 미사용 import청소제거

변경: 소스 3파일(+154/−39) · 신규 llm_failover.py + 테스트 3종

5QA셋 기반 평가 결과

방식: 라이브 363문항은 모델+프로덕션 DB 부재로 실행 불가(질문이 self-contained 아님). 기록된 실 파이프라인 출력을 문서 ground truth+QA 루브릭으로 채점한 2문서 프록시 평가.

QA목표실측판정
C2 배점 (정형 RFP)90/95% exact·sum정성65+정량35=100/100, 7/7 항목PASS
C2 배점 (실 109p)90/95%0건 추출FAIL
C1 기본메타 (양 문서)90% exact0/5 = 0% (값은 문서에 실재)FAIL
C4 요구사항 (정형)req 5 / tech 12양호
C4 요구사항 (실 109p)req 1 / tech 10저조
C6 지연 단일 LLM3.5s / 2.2sKanana 4.7s (gemini-flash 3.7s)FAIL
C6 임베딩KURE 52msPASS
제안서 e2e2p→7섹션→7벡터, errors=0PASS
단계 성공률6/6 SUCCESS (양 문서)PASS

핵심 발견

6환경 차단 · 남은 일

항목상태
라이브 e2e (363 QA 전수)차단 — 모델노드(promaxgb10) 오프라인·Docker 미기동·프로덕션 DB 부재
C-C 기본메타 0/5 개선정규식 폴백으로 오프라인 개선·검증 가능 (값이 문서에 실재)
C-D 실문서 recallLLM 의존 → 라이브 검증 전제

내가 고친 3개(failover·poll·cache)는 인프라 복원력/속도 개선으로 QA 정확도엔 무회귀·중립. QA 점수를 올리는 다음 작업은 C-C·C-D 추출 로직.