# spec/27_bch_calibration_runbook.yaml # BCH-V1 + CALIB-V1 실행 런북 (저성능 LLM 완전 재현 가이드) # ──────────────────────────────────────────────────────────────────────────── # 이 파일을 처음부터 끝까지 순서대로 따라 실행하면 # 저성능 LLM도 동일한 결과(behavioral_coverage_pct=100%, divergence=0, # llm_freedom_pct=0.0%)를 얻을 수 있다. # # 진정한 작업완료 기준: # - BEHAVIORAL_COVERAGE_V1_OK (behavioral_coverage_pct=100%, divergence=0) # - CALIBRATION_REGISTRY_WARN/OK (overclaimed=0, unregistered=0) # - LFM_V1_OK (llm_freedom_pct=0.0%) # - LLM_NARRATIVE_LOCK gate=PASS (softening_violations=0) # - HONEST_PERFORMANCE_V1_WARN/OK (design_score_as_proof ≤1건) # - full-gate EXIT=0 (53단계 파이프라인 전부 통과) # ──────────────────────────────────────────────────────────────────────────── runbook_id: BCH_CALIBRATION_RUNBOOK_V1 version: "2026-05-30" objective: | yaml 지침(spec/13_formula_registry.yaml)의 공식이 GAS(.gs) 및 Python 구현과 행위 수준에서 100% 일치하는지 검증하고, 하드코딩 임계값을 정직하게 관리하며, LLM의 가격·수량 자유계산 여지를 0으로 측정·폐쇄한다. "거짓 100%"를 제거하고 수치로 증빙 가능한 진짜 100%를 달성한다. # ════════════════════════════════════════════════════════════════════════════ # PHASE 0 — 전제조건 확인 # ════════════════════════════════════════════════════════════════════════════ phase_0_prerequisites: description: "이 단계를 모두 만족해야 Phase 1을 시작할 수 있다." checks: - id: P0_1 command: "python --version" expect: "Python 3.10+" note: "yaml, json, math, re, pathlib 사용. 외부 패키지: pyyaml(pip install pyyaml)" - id: P0_2 command: "node --version" expect: "v18+" note: "GAS 패리티 러너(run_gas_golden_parity.js)에 필요" - id: P0_3 command: "python -c \"import yaml; print('yaml OK')\"" expect: "yaml OK" fail_action: "pip install pyyaml" - id: P0_4 command: "ls spec/13_formula_registry.yaml spec/13b_harness_formulas.yaml" expect: "두 파일 모두 존재" note: "170개 공식 정의 파일" - id: P0_5 command: "ls gas_data_feed.gs gas_lib.gs gas_apex_alpha_watch.gs" expect: "세 파일 모두 존재" note: "GAS 구현 파일" # ════════════════════════════════════════════════════════════════════════════ # PHASE 1 — 행위기반 커버리지 하네스 (BCH-V1) # ════════════════════════════════════════════════════════════════════════════ phase_1_behavioral_coverage: description: | "formula_id 문자열이 .gs에 등장한다" → "golden == Python미러 == GAS미러" 로 전환. 발견된 분기(divergence)는 spec/13 기준으로 근본 정정. ordered_steps: - id: S1_1_VERIFY_CONTRACT name: "계약 파일 확인" command: "cat spec/26_behavioral_coverage_contract.yaml | head -20" expect: "behavioral_coverage_pct_min: 100.0" note: "없으면 계약 파일 작성 필요 (spec/26_behavioral_coverage_contract.yaml)" - id: S1_2_VERIFY_GOLDEN_CASES name: "골든케이스 파일 확인" command: | python -c " import yaml with open('spec/formula_golden_cases_v2.yaml', encoding='utf-8') as f: d = yaml.safe_load(f) formulas = d.get('golden_cases_v2', []) print(f'등록 공식 수: {len(formulas)}') for f in formulas: cases = f.get('cases', []) n = sum(1 for c in cases if 'inputs' in c) print(f' {f[\"formula_id\"]}: {n}개 케이스') " expect: "등록 공식 수 ≥ 22" fail_action: | spec/formula_golden_cases_v2.yaml 에 golden case 추가. 각 case 형식: - id: 케이스ID inputs: {필드명: 값} expected: {출력필드: 기대값} tolerance: {수치필드: 허용오차} provenance: HAND_COMPUTED # 반드시 spec에서 손계산. .gs 역복사 금지. 주의: expected 값을 .gs 출력에서 역복사하면 순환논리(REJECT). - id: S1_3_RUN_PY_MIRROR name: "Python 미러 검증" command: "python tools/run_formula_golden_cases_v2.py" expect: status_token: BEHAVIORAL_COVERAGE_PY_OK behavioral_coverage_pct: 100.0 python_fail: 0 fail_code: BCH_PY_MIRROR_FAIL fail_action: | 출력에서 [FAIL] 공식을 찾아 python_function 로직을 spec/13 expression과 비교. spec/13 expression이 맞고 Python이 틀린 경우 → Python 수정. Python이 맞고 golden expected가 틀린 경우 → golden case 수정(다시 손계산). 절대 "Python 출력 = expected" 방식의 역복사 금지. - id: S1_4_RUN_GAS_PARITY name: "GAS 패리티 검증" command: "node tools/run_gas_golden_parity.js" expect: status_token: GAS_PARITY_OK gas_fail: 0 fail_code: BCH_GAS_PARITY_FAIL fail_action: | 출력에서 [GAS_FAIL] 또는 [GAS_CORRECT_PYTHON_WRONG] 확인. GAS_CORRECT_PYTHON_WRONG: GAS가 spec_correct → Python 수정 필요. GAS_FAIL: GAS가 틀림 → gas_data_feed.gs / gas_lib.gs / gas_apex_alpha_watch.gs 수정. 수정 기준: 항상 spec/13_formula_registry.yaml의 expression. - id: S1_5_3WAY_VALIDATE name: "3-way 동등성 게이트" command: "python tools/validate_behavioral_coverage_v1.py --strict" expect: status_token: BEHAVIORAL_COVERAGE_V1_OK behavioral_coverage_pct: 100.0 implementation_divergence_count: 0 fail_code: BEHAVIORAL_COVERAGE_V1_FAIL fail_action: | implementation_divergence_count > 0 이면: - PYTHON_DIVERGES_FROM_SPEC: Python normalize_tick 등 → math.floor로 수정 - GAS_DIVERGES_FROM_GOLDEN: GAS 함수 → spec/13 expression 적용 divergence가 0이어도 coverage < 100%이면 golden case 부족 → S1_2로 돌아감. - id: S1_6_WIRE_PIPELINE name: "파이프라인 연결 확인" command: "npm run validate-behavioral-coverage" expect: exit_code: 0 status_token: BEHAVIORAL_COVERAGE_V1_OK fail_code: BCH_WIRING_FAIL note: "package.json의 validate-behavioral-coverage 스크립트가 S1_3+S1_4+S1_5를 순서대로 실행" completion_gate: command: "python tools/validate_behavioral_coverage_v1.py --strict" required_output: behavioral_coverage_pct: "== 100.0" implementation_divergence_count: "== 0" evidence_artifact: "Temp/formula_behavioral_coverage_summary_v1.json" # ════════════════════════════════════════════════════════════════════════════ # PHASE 2 — 임계값 보정 레지스트리 (CALIB-V1) # ════════════════════════════════════════════════════════════════════════════ phase_2_calibration_registry: description: | 모든 하드코딩 임계값을 spec/calibration_registry.yaml 에 등록하고 overclaimed(검증 안 된 값을 CALIBRATED로 위장) = 0 을 달성한다. ordered_steps: - id: S2_1_VERIFY_REGISTRY name: "레지스트리 파일 확인" command: | python -c " import yaml with open('spec/calibration_registry.yaml', encoding='utf-8') as f: d = yaml.safe_load(f) t = d.get('thresholds', []) print(f'총 임계값: {len(t)}') by_src = {} for e in t: s = e.get('source', 'EXPERT_PRIOR') by_src[s] = by_src.get(s, 0) + 1 for s, n in sorted(by_src.items()): print(f' {s}: {n}') " expect: "총 임계값 ≥ 60" - id: S2_2_RUN_REGISTRY_VALIDATE name: "레지스트리 검증" command: "python tools/validate_calibration_registry_v1.py" expect: overclaimed_count: 0 unregistered_threshold_count: 0 status_token: "CALIBRATION_REGISTRY_WARN or CALIBRATION_REGISTRY_OK" fail_code: CALIBRATION_REGISTRY_FAIL fail_action: | OVERCLAIMED: source=CALIBRATED 이면서 sample_n<30 → source를 PROVISIONAL 로 변경. 절대 sample_n을 30으로 올려서 해결 금지 (실제 표본 없이 수치 조작). UNREGISTERED: .gs/.py 핫존에서 발견된 미등록 상수 → calibration_registry.yaml에 추가. 추가 형식: - id: 고유ID value: 상수값 unit: pct/ratio/count/etc source: EXPERT_PRIOR # 실측 없으면 반드시 EXPERT_PRIOR sample_n: 0 owner_formula: 관련_FORMULA_ID gs_location: "파일명:줄번호" - id: S2_3_BUILD_PRIORITY name: "보정 우선순위 연결" command: "python tools/build_calibration_priority_v1.py" expect: status_token: CALIBRATION_PRIORITY_OK priority_count_min: 5 fail_code: CALIBRATION_PRIORITY_FAIL note: "alpha_feedback_loop_v2.json의 miss5_count 신호를 임계값 보정 우선순위에 연결" calibration_policy_enforcement: - rule: "source=CALIBRATED 이려면 sample_n ≥ 30 AND backtest_doc이 있어야 한다" - rule: "실측 없는 임계값은 반드시 EXPERT_PRIOR 또는 PROVISIONAL" - rule: "overclaimed_count > 0 이면 CALIBRATION_REGISTRY_FAIL → 배포 차단" calibration_path: EXPERT_PRIOR: description: "30년 현장경험 기반 초기값. 검증 없음." next_step: "표본 수집 → 30건 이상이면 PROVISIONAL 승격 심사" PROVISIONAL: description: "예비 검증(1-29건). 방향성 확인됨." next_step: "30건 이상 + 실제 P&L 검증 → CALIBRATED" CALIBRATED: description: "실측 표본 ≥30건 backtest 완료." maintenance: "분기별 재검증. 시장 국면 변화 시 재보정" completion_gate: command: "python tools/validate_calibration_registry_v1.py" required_output: overclaimed_count: "== 0" unregistered_threshold_count: "== 0" evidence_artifact: "Temp/calibration_registry_v1.json" # ════════════════════════════════════════════════════════════════════════════ # PHASE 3 — LLM 자유도 측정·폐쇄 (LFM-V1) # ════════════════════════════════════════════════════════════════════════════ phase_3_llm_freedom: description: | 가격·수량을 LLM이 자유계산하는 여지를 0으로 측정하고, narrative 완화어휘(INVALID_SOFTENING)를 차단한다. ordered_steps: - id: S3_1_FREEDOM_VALIDATE name: "LLM 자유도 측정" command: "python tools/validate_number_provenance_v1.py" expect: status_token: LFM_V1_OK llm_freedom_pct: 0.0 freedom_signals_count: 0 fail_code: LFM_V1_FAIL fail_action: | prompts/analysis_prompt.md 에서 '직접 계산한다' 문구를 찾아 'DATA_MISSING — 하네스 업데이트 필요' 로 교체. harness 결측 시 LLM 직접계산 허용 문구 전면 삭제 (HS011). - id: S3_2_NARRATIVE_LOCK name: "LLM 내러티브 잠금" command: "python tools/build_llm_narrative_template_lock_v1.py" expect: gate: PASS total_violations: 0 narrative_violations: 0 softening_violations: 0 fail_code: LLM_NARRATIVE_LOCK_FAIL fail_action: | [INVALID_NARRATIVE]: 금지어휘(같다/약간/괜찮다/곧 등) 섹션에서 제거. [INVALID_SOFTENING]: BLOCK/SELL verdict 근방에서 완화어휘 제거. 완화어휘 패턴: 그래도/유연하게/장기관점재진입/고려가능/상황에따라/아직괜찮/지켜볼만 규칙: BLOCK verdict가 있으면 완화 해석 문장을 완전히 삭제. completion_gate: command: "python tools/validate_number_provenance_v1.py && python tools/build_llm_narrative_template_lock_v1.py" required_output: llm_freedom_pct: "== 0.0" softening_violations: "== 0" evidence_artifact: "Temp/llm_freedom_v1.json" # ════════════════════════════════════════════════════════════════════════════ # PHASE 4 — 정직 성과증빙 (HONEST-V1) # ════════════════════════════════════════════════════════════════════════════ phase_4_honest_performance: description: | 설계점수(design_score)와 실측점수(actual_score)를 물리적으로 분리. sample_n < 30 이면 반드시 UNVALIDATED_DESIGN_SCORE 라벨. ordered_steps: - id: S4_1_HONEST_GUARD name: "정직 성과증빙 하네스" command: "python tools/build_honest_performance_guard_v1.py" expect: status_token: "HONEST_PERFORMANCE_V1_OK or HONEST_PERFORMANCE_V1_WARN" note: "WARN은 표본 부족(sample<30)을 정직하게 공시하는 정상 상태" fail_code: HONEST_PERFORMANCE_V1_FAIL fail_action: | design_score_as_proof 위반이 있으면: 해당 score를 보고서에 표시할 때 '[UNVALIDATED_DESIGN_SCORE: n=N]' 주석 필수. 'score=97.12(검증됨)' 형식 절대 금지. T+1/T+5 KPI가 목표 미달이면: 보정루프 로드맵(build_calibration_priority_v1.py 결과) 참조. '목표 달성' 선언 금지 — 수치 그대로 공시. - id: S4_2_KPI_TRACKING name: "T+1/T+5 KPI 추적" command: | python -c " import json with open('Temp/honest_performance_guard_v1.json', encoding='utf-8') as f: d = json.load(f) for k in d.get('kpi_tracker', []): status = 'OK' if k['status'] != 'BELOW_TARGET' else 'BELOW_TARGET' print(f\"{k['metric']}: {k['current']}% (target={k['target_min']}%) [{status}]\") " expect: "출력 확인" note: | T+5 35.86% → 50% 목표: 보정루프 4단계 Step1: 표본 누적(30건) Step2: ALEG_V2_GATE1_BLOCK_PCT 3% → 실측 최적값 PROVISIONAL 승격 Step3: DSD_V1 가중치 logistic regression 최적화 Step4: K2 분할비율 backtest → CALIBRATED completion_gate: command: "python tools/build_honest_performance_guard_v1.py" required_output: violation_count: "== 0 (UNVALIDATED 라벨 추가로 해소)" evidence_artifact: "Temp/honest_performance_guard_v1.json" # ════════════════════════════════════════════════════════════════════════════ # PHASE 5 — 통합 게이트 + 파이프라인 확인 # ════════════════════════════════════════════════════════════════════════════ phase_5_integration: description: "4-기둥 통합 실행 후 full-gate / daily-feedback-report 최종 통과 확인" ordered_steps: - id: S5_1_ENGINE_INTEGRITY name: "통합 엔진 무결성" command: "npm run validate-engine-integrity" expect: exit_code: 0 behavioral_coverage_pct: 100.0 overclaimed_count: 0 llm_freedom_pct: 0.0 softening_violations: 0 fail_code: ENGINE_INTEGRITY_FAIL note: | validate-behavioral-coverage && validate-calibration-registry && validate-llm-freedom && validate-narrative-lock && build-honest-performance-guard && build-calibration-priority - id: S5_2_FULL_GATE name: "전체 파이프라인 확인" command: "npm run full-gate" expect: exit_code: 0 note: "53단계 전부 통과. WARN_ONLY 항목(펀더멘털 미수집)은 허용." fail_code: FULL_GATE_FAIL fail_action: | 실패 단계를 단독 실행해 원인 파악: npm run <실패_단계명> HARNESS CONTEXT FAIL → validate_harness_context.py의 허용 enum 확인 validate-specs FAIL → RetirementAssetPortfolio.yaml spec_files에 신규 파일 등록 - id: S5_3_DAILY_FEEDBACK name: "일일 피드백 리포트 확인" command: "npm run daily-feedback-report" expect: exit_code: 0 fail_code: DAILY_FEEDBACK_FAIL completion_gate: command: "npm run full-gate && npm run daily-feedback-report" required_output: exit_code: "== 0 (both)" evidence_artifact: "Temp/formula_behavioral_coverage_summary_v1.json" # ════════════════════════════════════════════════════════════════════════════ # PHASE 6 — 보정루프 (표본 누적 후 반복 실행) # ════════════════════════════════════════════════════════════════════════════ phase_6_calibration_loop: description: | 매 거래일 T+5 결과 수집 후 실행. 표본이 누적될수록 임계값을 EXPERT_PRIOR → PROVISIONAL → CALIBRATED 로 승격한다. trigger: "매 거래일 장마감 후 (15:30 이후)" ordered_steps: - id: L1_UPDATE_HISTORY name: "평가 이력 업데이트" command: "npm run update-evaluation-history" note: "proposal_evaluation_history.json 에 T+5 결과 추가" - id: L2_CHECK_SAMPLE_COUNT name: "표본 수 확인" command: | python -c " import json with open('Temp/calibration_priority_v1.json', encoding='utf-8') as f: d = json.load(f) print('cases_analyzed:', d.get('cases_analyzed', 0)) print('miss5_count:', d.get('miss5_count', 0)) top3 = d.get('priority_list', [])[:3] for p in top3: print(f' [{p[\"urgency_score\"]}] {p[\"calibration_id\"]}: value={p[\"current_value\"]} n={p[\"sample_n\"]}') " note: "cases_analyzed ≥ 30이면 최우선 임계값 PROVISIONAL 승격 심사" - id: L3_CALIBRATION_CANDIDATE_REVIEW name: "보정 후보 심사 (cases ≥ 30 시)" trigger_condition: "cases_analyzed >= 30" manual_action: | 1. ALEG_V2_GATE1_BLOCK_PCT(3%) 검증: - late_chase_attribution_v1.json 의 chase_entry_rate 확인 - velocity_1d ≥ 3%에서 진입한 케이스의 T+5 승률 계산 - 현재 3%보다 낮은 임계값이 더 효과적이면 새 값 제안 2. 새 값 제안 후: - calibration_registry.yaml의 source를 PROVISIONAL로 변경 - sample_n에 실제 표본 수 기재 - last_calibrated: 오늘 날짜 3. 변경 후 반드시 npm run validate-engine-integrity 재실행 - id: L4_RUN_FULL_GATE name: "변경 후 전체 검증" command: "npm run full-gate" expect: {exit_code: 0} calibration_escalation_criteria: PROVISIONAL: condition: "sample_n >= 10 AND 방향성 확인" CALIBRATED: condition: "sample_n >= 30 AND 실제 P&L backtest 완료 AND 이전 임계값 대비 명확한 개선" required_doc: "backtest 결과 노트 (날짜, 표본 수, 이전값, 신규값, 성과 비교)" # ════════════════════════════════════════════════════════════════════════════ # 거부 조건 (Reject Conditions) — 어떤 상황에서도 적용 # ════════════════════════════════════════════════════════════════════════════ reject_conditions: - "behavioral_coverage_pct < 100% 인데 '커버리지 100% 달성' 선언" - "golden expected 값을 .gs 출력에서 역복사 (순환논리)" - "임계값을 실측 없이 source=CALIBRATED로 기재 (overclaimed)" - "LLM이 가격/수량을 spec 등록 공식 없이 즉석 계산" - "rebound_efficiency_score 등 설계점수를 '검증된 성과'로 서술 (UNVALIDATED 라벨 없이)" - "T+1/T+5 목표 미달 상태에서 '예측 정확도 100%' 선언" - "divergence_count > 0 상태에서 '구현 일치' 선언" - "sample_n < 30인 임계값을 '보정완료'로 처리" # ════════════════════════════════════════════════════════════════════════════ # 현재 달성 현황 (2026-05-30) # ════════════════════════════════════════════════════════════════════════════ current_status_2026_05_30: phase_1_bch: COMPLETE behavioral_coverage_pct: 100.0 gas_parity_cases: 63 implementation_divergence_count: 0 bugs_fixed: - "normalize_tick: round() → math.floor() (Python-GAS divergence 제거)" - "PROFIT_LOCK_STAGE 단계명 7개 spec 일치 정정 (GAS calcPrices_)" - "validate_harness_context.py VALID_PROFIT_LOCK_STAGES 신규 명칭 추가" - "RetirementAssetPortfolio.yaml spec_files 신규 3파일 등록" phase_2_calib: COMPLETE total_thresholds: 70 overclaimed_count: 0 unregistered_count: 0 expert_prior_count: 61 # 정직하게 공시됨 phase_3_lfm: COMPLETE llm_freedom_pct: 0.0 softening_violations: 0 prompt_freedom_risks_removed: 4 phase_4_honest: COMPLETE design_score_labeled_unvalidated: true t1_match_rate_pct: 47.28 t5_match_rate_pct: 35.86 target_t5: 55.0 phase_5_integration: COMPLETE full_gate_exit: 0 daily_feedback_exit: 0 phase_6_calibration_loop: IN_PROGRESS cases_analyzed: 141 miss5_count: 51 next_milestone: "cases_analyzed=30 달성 후 ALEG_V2_GATE1_BLOCK_PCT 보정 심사"