# Phase 3 Testing Checklist > Phase 3 implementation status: **COMPLETE** (2026-03-12) ## 1. 단위 테스트 ### text normalizer - [x] HTML 문서가 안정적으로 plain text로 변환된다. → `test_text_normalizer.py` - [x] 동일 문서에 대해 해시가 안정적으로 재생산된다. → `test_text_normalizer.py` - [x] disclaimer strip 옵션이 본문을 과도하게 삭제하지 않는다. → `test_text_normalizer.py` ### rule parser - [x] guidance 키워드가 올바르게 분류된다. → `test_rule_parser.py` - [x] one-off 키워드가 검출된다. → `test_rule_parser.py` - [x] demand/pricing/margin 키워드가 검출된다. → `test_rule_parser.py` - [x] section parser가 없는 문서에서도 안전하게 실패한다. → `test_rule_parser.py` ### span mapper - [ ] evidence char offsets가 원문 구간과 일치한다. - [ ] normalization 후에도 span reference가 추적 가능하다. ### llm wrapper (Ollama) - [x] 캐시 히트 시 외부 호출이 발생하지 않는다. → `test_llm_client.py::TestOllamaClientChat::test_cache_hit_skips_llm_call` - [x] 타임아웃 시 LLMTimeoutError 발생 → `test_llm_client.py::TestOllamaClientChat::test_chat_timeout_raises_llm_timeout_error` - [x] 5xx 응답 시 RetryableError 발생 → `test_llm_client.py::TestOllamaClientChat::test_chat_5xx_raises_retryable_error` - [x] 성공 응답 파싱 → `test_llm_client.py::TestOllamaClientChat::test_chat_success_returns_parsed_json` ### LLM cache - [x] 캐시 미스 시 None 반환 → `test_llm_cache.py::TestLLMCacheStore::test_get_returns_none_on_miss` - [x] 캐시 put이 DB 행 생성 → `test_llm_cache.py::TestLLMCacheStore::test_put_stores_entry` ### canonical merge - [x] rule 우선 (both confident) → `test_merger.py::TestMerge::test_rule_wins_when_both_confident` - [x] llm이 unknown signal 채움 → `test_merger.py::TestMerge::test_llm_fills_unknown_signals` - [x] 충돌 시 보수적 merge + warning → `test_merger.py::TestMerge::test_conflict_flags_rule_llm_conflict` - [x] llm=None → all provenance=rule → `test_merger.py::TestMerge::test_llm_none_all_provenance_is_rule` - [x] risk_flags OR 결합 → `test_merger.py::TestMerge::test_risk_flags_are_ored` - [x] review queue trigger (low confidence) → `test_merger.py::TestShouldQueueForReview::test_low_confidence_triggers_review` - [x] review queue trigger (conflict) → `test_merger.py::TestShouldQueueForReview::test_conflict_triggers_review` - [x] review queue trigger (oneoff) → `test_merger.py::TestShouldQueueForReview::test_oneoff_triggers_review` ### feature builder - [x] reaction_close_location 계산이 정확하다. → `test_event_features.py` - [x] rolling window가 미래 데이터를 보지 않는다. → `test_market_features.py` - [x] null feature가 정책대로 처리된다. → `test_event_features.py` ### labeler - [x] pre_market/regular_hours → same-day reaction → `test_labeler.py::TestComputeReactionDate::test_pre_market_on_trading_day_returns_same_day` - [x] post_market → next trading day → `test_labeler.py::TestComputeReactionDate::test_post_market_returns_next_trading_day` - [x] unknown → next trading day → `test_labeler.py::TestComputeReactionDate::test_unknown_returns_next_trading_day` - [x] 주말(비거래일) pre_market → next trading day → `test_labeler.py::TestComputeReactionDate::test_pre_market_on_weekend_returns_next_trading_day` - [x] 금요일 post_market → 월요일 → `test_labeler.py::TestComputeReactionDate::test_post_market_on_friday_returns_monday` - [x] 1D forward return 정확 → `test_labeler.py::TestComputeLabelsFromBars::test_1d_return_calculation` - [x] MFE = max(high-entry)/entry → `test_labeler.py::TestComputeLabelsFromBars::test_mfe_is_max_high_minus_entry` - [x] MAE = min(low-entry)/entry → `test_labeler.py::TestComputeLabelsFromBars::test_mae_is_min_low_minus_entry` - [x] hit_pos_1r True/False → `test_labeler.py::TestComputeLabelsFromBars::test_hit_pos_1r_true/false` - [x] close_up_after_3d logic → `test_labeler.py::TestComputeLabelsFromBars::test_close_up_after_3d_true_when_final_close_above_entry` - [x] 빈 bars → empty dict → `test_labeler.py::TestComputeLabelsFromBars::test_empty_bars_returns_empty_dict` - [x] label=ok when price data available → `test_labeler.py::TestGenerateLabels::test_generate_labels_with_valid_prices` - [x] label=unavailable when Oracle fails → `test_labeler.py::TestGenerateLabels::test_generate_labels_unavailable_when_no_price_data` ### review queue - [x] 신규 ReviewItem 생성 → `test_review_queue.py::TestCreateReviewItem::test_create_new_review_item` - [x] 중복 open item → 업데이트 (priority escalation) → `test_review_queue.py::TestCreateReviewItem::test_deduplicate_open_items` - [x] resolve → status=resolved → `test_review_queue.py::TestCreateReviewItem::test_resolve_review_item` - [x] list_review_items status 필터 → `test_review_queue.py::TestCreateReviewItem::test_list_review_items_with_status_filter` ### snapshot export - [x] manifest.json 생성 (snapshot_id, created_at, row_counts) → `test_snapshot_export.py::TestExportDatasetSnapshot::test_manifest_is_written` - [x] train/valid/test Parquet 파일 생성 → `test_snapshot_export.py::TestExportDatasetSnapshot::test_parquet_files_created` - [x] temporal split proportions → `test_snapshot_export.py::TestTemporalSplit::test_split_proportions` - [x] temporal split order preserved → `test_snapshot_export.py::TestTemporalSplit::test_split_preserves_temporal_order` ## 2. 통합 테스트 - [x] SEC raw 문서 하나가 parser output까지 도달한다. → `test_filing_pipeline.py` - [x] parser output이 feature builder로 연결된다. → `test_feature_pipeline.py` - [x] feature + price data가 labeler로 연결된다. → `test_label_pipeline.py::test_label_pipeline_end_to_end` - [x] Oracle 실패 시 unavailable label 생성 → `test_label_pipeline.py::test_label_pipeline_handles_missing_price_data` - [x] review queue item이 실제로 생성된다. → `test_review_queue_integration.py::test_low_confidence_merge_creates_review_item` - [x] conflict 시 P0 review item 생성 → `test_review_queue_integration.py::test_conflict_merge_creates_p0_review_item` - [ ] snapshot export가 manifest 포함해 생성된다. (needs real DB) ## 3. Replay 테스트 - [x] 동일 문서 + 동일 prompt_version → LLM 캐시 히트 → `test_llm_cache_replay.py::test_same_document_hits_cache_on_replay` - [ ] 동일 문서 재처리 시 canonical output이 동일하다. → `test_determinism.py` - [ ] parser_version 변경 시 diff report 생성 가능하다. - [ ] historical day replay가 live path와 같은 코드 경로를 탄다. ## 4. Gold set 테스트 - [ ] event_type accuracy baseline 이상 → `apps/qa/evaluate_gold_set.py` - [ ] guidance_direction accuracy baseline 이상 → `apps/qa/evaluate_gold_set.py` - [ ] oneoff precision/recall baseline 이상 → `apps/qa/evaluate_gold_set.py` - [ ] confidence calibration sanity check - [ ] evidence presence ratio 기준 이상 → `apps/qa/evaluate_gold_set.py` ## 5. Leakage 테스트 - [ ] next_open entry dataset에 entry day 장중 정보가 포함되지 않는다. - [ ] FINRA post-close data가 당일 아침 feature로 들어가지 않는다. - [ ] forward returns를 만드는 price bars가 feature 계산에 재사용되지 않는다. - [x] snapshot split이 시간 순서를 위반하지 않는다. → `test_snapshot_export.py::TestTemporalSplit::test_split_preserves_temporal_order` ## 6. 운영 전 체크리스트 - [x] parser schema version 고정 → `libs/parser/rule_parser.py::PARSER_VERSION` - [x] prompt version 고정 → `libs/llm/prompts.py::PROMPT_VERSION` - [ ] gold set 리포트 생성 완료 - [ ] review backlog acceptable - [ ] null rate report 검토 완료 - [ ] label distribution sanity check 완료 - [x] dataset manifest에 commit hash 포함 → `libs/export/snapshot_export.py::_get_git_commit_hash` - [x] raw prompt/response 보관 정책 확인 → `libs/db/models.py::LLMCallCache` ## 7. 신규 파일 목록 (Phase 3) | 경로 | 상태 | |---|---| | `libs/llm/__init__.py` | ✅ | | `libs/llm/exceptions.py` | ✅ | | `libs/llm/client.py` | ✅ | | `libs/llm/cache.py` | ✅ | | `libs/llm/prompts.py` | ✅ | | `libs/llm/parser.py` | ✅ | | `libs/parser/merger.py` | ✅ | | `libs/labeler/__init__.py` | ✅ | | `libs/labeler/reaction_date.py` | ✅ | | `libs/labeler/label_generator.py` | ✅ | | `libs/review/__init__.py` | ✅ | | `libs/review/queue.py` | ✅ | | `libs/export/__init__.py` | ✅ | | `libs/export/snapshot_export.py` | ✅ | | `libs/db/models.py` (+ 3 models) | ✅ | | `libs/db/migrations/versions/0002_phase3_tables.py` | ✅ | | `libs/common/config.py` (+ Ollama settings) | ✅ | | `apps/pipeline/label_generator/main.py` | ✅ | | `apps/pipeline/dataset_export/main.py` | ✅ | | `apps/review/cli.py` | ✅ | | `apps/qa/evaluate_gold_set.py` | ✅ | | `tests/unit/test_llm_client.py` | ✅ | | `tests/unit/test_llm_cache.py` | ✅ | | `tests/unit/test_merger.py` | ✅ | | `tests/unit/test_labeler.py` | ✅ | | `tests/unit/test_review_queue.py` | ✅ | | `tests/unit/test_snapshot_export.py` | ✅ | | `tests/integration/test_label_pipeline.py` | ✅ | | `tests/integration/test_review_queue_integration.py` | ✅ | | `tests/replay/test_llm_cache_replay.py` | ✅ | | `.env.example` (+ Ollama vars) | ✅ |