From 064d928505ea856c45b3f3e71043077b081790ad Mon Sep 17 00:00:00 2001 From: DONGRYEOLLEE1 Date: Fri, 22 May 2026 12:45:26 +0900 Subject: [PATCH] test(routing-eval): add 6 data_science cases (PR #10/#11 regression line) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit routing_eval golden dataset를 12 → 18 cases로 확장. data_science 카테고리에 신규 6 cases 추가하여 본 세션의 시각화/분기 회귀를 정량 측정으로 차단. 신규 cases: - data-002 trend line CSV → data_science_team - data-003 JSON category bar chart - data-004 xlsx multi-sheet 비교 - data-005 multi-file 비교 - data-006 CJK 라벨 차트 - data-007 corrupt PDF 우아한 실패 plan §4.0 P5 (회귀는 evaluation harness로) 강화. CODEBASE_WIDE_REFACTORING_PLAN §2.8 항목에 18 cases + 카테고리 10종 + data_science 확장 메모 반영. 검증: pytest 316/316 + routing_eval 6/6 PASS, 회귀 0. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../tests/routing_eval/golden_dataset.json | 54 +++++++++++++++++++ plans/CODEBASE_WIDE_REFACTORING_PLAN.md | 2 +- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/apps/backend/tests/routing_eval/golden_dataset.json b/apps/backend/tests/routing_eval/golden_dataset.json index 2b8c3b6..8b3b158 100644 --- a/apps/backend/tests/routing_eval/golden_dataset.json +++ b/apps/backend/tests/routing_eval/golden_dataset.json @@ -47,6 +47,60 @@ "expected_request_review": false, "rationale": "데이터 파일 분석 + 차트 요청." }, + { + "id": "data-002-trend-line", + "category": "data_science", + "user_message": "첨부 trend.csv의 월별 매출 추세를 라인 차트 이미지로 시각화해서 PNG로 저장 후 보여줘. 인사이트 3줄.", + "repo_bound": false, + "expected_next": "data_science_team", + "expected_request_review": false, + "rationale": "S-A: CSV 시계열 + 라인 차트 PNG 요청. data_engineer → data_analyst 한 사이클로 끝나야 함." + }, + { + "id": "data-003-json-bar", + "category": "data_science", + "user_message": "첨부 products.json의 category별 평균 price를 막대 차트 PNG로 시각화. 한국어 인사이트 3줄.", + "repo_bound": false, + "expected_next": "data_science_team", + "expected_request_review": false, + "rationale": "S-B: JSON 첨부 + 집계 + 막대 차트. coding_team으로 잘못 위임하면 안 됨 (PR #10 회귀)." + }, + { + "id": "data-004-xlsx-multi-sheet", + "category": "data_science", + "user_message": "첨부 xlsx의 sales 시트 revenue 합계와 costs 시트 cost 합계를 비교 막대 차트 PNG로 만들어 보여줘.", + "repo_bound": false, + "expected_next": "data_science_team", + "expected_request_review": false, + "rationale": "S-C: 다중 시트 xlsx → preview_tabular_file로 sheet 결정 + 비교 차트. request_review는 false (python sandbox 안전)." + }, + { + "id": "data-005-multi-file-compare", + "category": "data_science", + "user_message": "첨부한 두 CSV(sales.csv, metrics.csv)를 하나의 PNG에 두 서브플롯으로 시각화해줘.", + "repo_bound": false, + "expected_next": "data_science_team", + "expected_request_review": false, + "rationale": "S-D: 다중 파일 비교 분석. data_engineer가 두 파일 모두 inspect 후 data_analyst가 단일 PNG로 종합." + }, + { + "id": "data-006-korean-labels", + "category": "data_science", + "user_message": "첨부 korean_sales.csv의 지역별 매출 합계를 한국어 라벨 막대 차트 PNG로 시각화해서 보여줘.", + "repo_bound": false, + "expected_next": "data_science_team", + "expected_request_review": false, + "rationale": "S-E: CJK 라벨 차트. CJK 폰트 fallback + bbox_inches='tight' (PR #11)이 적용되어야 PNG가 silent fail하지 않음." + }, + { + "id": "data-007-corrupt-pdf", + "category": "data_science", + "user_message": "첨부한 corrupt.pdf의 텍스트를 추출해서 핵심 키워드 3개만 알려줘.", + "repo_bound": false, + "expected_next": "data_science_team", + "expected_request_review": false, + "rationale": "S-F2: 깨진 PDF. data_science_team으로 분기 후 extract_document_text가 실패하면 사용자에게 명확히 고지(plan §검증 기준 4)." + }, { "id": "vision-001", "category": "vision", diff --git a/plans/CODEBASE_WIDE_REFACTORING_PLAN.md b/plans/CODEBASE_WIDE_REFACTORING_PLAN.md index dfb90b2..8a0435c 100644 --- a/plans/CODEBASE_WIDE_REFACTORING_PLAN.md +++ b/plans/CODEBASE_WIDE_REFACTORING_PLAN.md @@ -344,7 +344,7 @@ revert 후 _workspace의 audit/baseline 파일을 그대로 두고 원인 분석 - [x] 2.5 `agent_core/router_schema.py` 신설 — `RouterDecision`(next/reason/request_review/team_finished) + `RouterDecisionRecord`(상태 영속). LLM `with_structured_output` 사용 준비. - [x] 2.6 `agent_core/safeguards.py` 신설 — `reject_invalid_goto`, `enforce_team_redirect_limit`, `enforce_dispatch_limit`, `fallback_decision_on_parse_failure` 순수 함수. `SafeguardOutcome` 결과 타입(status: accepted/rejected_invalid_goto/parse_failed/fallback_finish). **plan §4.0 P3 강제 — 결정 자체를 바꾸지 않고 차단·재요청만**. 단위 테스트 11 cases(`test_router_safeguards.py`). - [x] 2.7 supervisor / team-supervisor 프롬프트 강화 — `SYSTEM_SUPERVISOR_PROMPT`(v2.5 → v2.6)에 `ROUTER_DECISION_GUIDANCE` 통합 + `TEAM SELECTION HINTS` 블록(이미지→vision_team / 데이터 attachment→data_science_team / repo binding+코드 의도→coding_team) + 가이드 필드명을 RouterDecision 스키마(`reason`/`request_review`)에 맞춤. `TEAM_SUPERVISOR_PROMPT`(v1.2 → v1.3)에 `ROUTER_DECISION_GUIDANCE` + `WORKER REUSE POLICY` 블록(route_history 검토 + 중복 dispatch 금지 + `team_finished` 시그널 사용) 추가. fragments는 f-string으로 임베드, JSON 예시의 `{}`는 `{{}}`로 escape하여 `str.format(members=…)` 호환. -- [x] 2.8 라우팅 evaluation harness 골격 — `apps/backend/tests/routing_eval/` 신설: `golden_dataset.json`(12 cases 시작, 카테고리 8종 균등 분포: coding/coding-no-repo/research/data_science/vision/writing/FINISH/approval_request + ambiguous/multi-intent), `scorer.py`(`EvalCase`/`EvalReport`/`load_dataset`/`score_decisions` pure 함수), `test_scorer.py`(6 cases — dataset 로딩, top-1 hit/miss, request_review 별도 추적, category accuracy). 실 LLM 호출 + 50→100 case 확장 + nightly 실행은 Phase 2.4 LLMRouter 적용과 함께 진행. pytest 325 → **331 PASS**(+6, 회귀 0). +- [x] 2.8 라우팅 evaluation harness 골격 — `apps/backend/tests/routing_eval/` 신설: `golden_dataset.json`(12 cases 시작 → 2026-05-22 시점 **18 cases**로 확장, 카테고리 10종: coding/coding-no-repo/research/data_science/vision/writing/FINISH/approval_request + ambiguous/multi-intent). data_science 카테고리는 PR #10/#11 후속으로 6 cases 신규 추가(data-002 trend line / data-003 json bar / data-004 xlsx multi-sheet / data-005 multi-file compare / data-006 CJK labels / data-007 corrupt PDF) — 본 세션의 회귀가 다시 일어나면 scorer가 즉시 잡도록 정량 측정선 구축. `scorer.py`(`EvalCase`/`EvalReport`/`load_dataset`/`score_decisions` pure 함수), `test_scorer.py`(6 cases — dataset 로딩, top-1 hit/miss, request_review 별도 추적, category accuracy). 실 LLM 호출 + 50→100 case 확장 + nightly 실행은 Phase 2.4 LLMRouter 적용과 함께 진행. pytest 325 → **331 PASS**(+6, 회귀 0). - [x] 2.9 finalizer/validator 에러 폴백 통일 — `agent_core/fallback_messages.py` 신설. `finalizer_absolute_fallback()`, `validator_recursion_warning()`, `validator_review_error()`, `validator_review_passed()`, `supervisor_safeguard_finish(reason)` 5개 helper. finalizer + validator 양쪽이 동일 출처에서 메시지 로드 — 사용자 가시 톤 일관성 확보. Phase 2.4 safeguard 발동 시 `supervisor_safeguard_finish(decision.reason)` 사용 준비 완료. - [x] 2.10 `load_memories.py` 독립 테스트 — `apps/backend/tests/test_load_memories_node.py`가 이미 3 cases(skip-when-missing, populates-personalization, instruction-only-payload)로 커버 중. 인벤토리 확인 후 그대로 보존. - [x] 2.11 finalizer messages 길이 상한 도입 — `SAFEGUARDS.finalizer_recent_messages_limit=200`. `make_finalizer_node` 내부에서 deduped 후 `[-N:]` 슬라이싱. 장기 대화 OOM 회귀 방지.