feat(kis-collection): finalize sqlite migration, add fallback resilience, and update WBS documentation

This commit is contained in:
2026-06-22 18:34:56 +09:00
parent c576138829
commit 6c549b7bdc
48 changed files with 34610 additions and 24883 deletions
+41 -100
View File
@@ -11,31 +11,8 @@ classification_summary:
unclassified_findings: 0
# WBS-7.3 재검토 (2026-06-21):
# - F01/F09 (REGISTER_*): DONE으로 정정 — spec/calibration_registry.yaml에 이미
# 등록되어 있었음(P5-T01 wave1). 레저 상태가 stale했을 뿐 실작업 불필요.
# - F12/F13 (DELETE_DISTRIBUTION_RISK_GAS): ledger의 "build_distribution_risk_v1.py"
# 인용은 오류(존재하지 않는 파일) — 실제는 build_distribution_risk_score_v2.py가
# 동일 필드를 산출하나, GAS-Python parity 테스트가 전혀 없어 삭제를 보류.
# - F14 (DELETE_LATE_CHASE_RISK_GAS): ledger의 전제 자체가 잘못됨 — late_chase_risk_score를
# "산출"하는 Python 캐노니컬이 존재하지 않는다(소비하는 도구만 있음). GAS가 유일한
# 산출 경로일 가능성이 높아 삭제 시도하지 않음. migration_action 재검증 필요.
# - F02~F06, F07, F10, F11, F15 (MEDIUM/HIGH priority MIGRATE_*): 전용 parity 테스트
# 인프라(GAS 함수와 동일 입력으로 Python 포트 출력을 대조)가 없는 상태에서 결정론적
# 매매엔진의 가격/수량/정지손실/라우팅 로직을 포팅하는 것은 silent correctness bug
# 위험이 크다고 판단해 이번 세션에서는 착수하지 않았다(advisor 권고에 따른 보류).
# 특히 F11(stop_loss_gate)은 ledger 자체가 "critical path — must match
# validate_stop_loss_policy_v1 spec"로 명시한 항목이다. 후속 전용 스프린트에서
# parity 테스트를 먼저 구축한 뒤 착수해야 한다.
#
# WBS-7.3 후속(2026-06-22):
# - F11(stop_loss_gate): formulas/stop_loss_gate_v1.py로 포팅 완료 + GAS 원본을
# Node로 직접 실행해 대조하는 실제 parity 테스트(tests/parity/) 구축·PASS.
# 나머지 미착수 5건(F02~F06/F07/F10/F15)에 동일 방법론 적용 가능.
# - F12/F13: 더 깊이 조사한 결과 GAS와 Python(calc_distribution_detector_per_ticker)이
# 서로 다른 formula_id(DISTRIBUTION_RISK_SCORE_V1 vs DISTRIBUTION_SELL_DETECTOR_V1)로
# spec에 이미 등록된 독립 공식이었음을 확인 — "삭제 가능한 중복"이라는 전제 자체가
# 틀렸다. 사용자 결정: 둘 다 유지, 역할 분리. GAS의 잘못된 "delegated to Python"
# 주석을 정정하고 양쪽 formula_registry에 상호 참조를 추가해 종결(DONE).
# - F01/F09 done, F02~F07/F10~F15 parity PASS, F08 keep.
# - KIS collector refactor: WBS-8.8.
# Canonical classification of GAS thin-adapter findings identified by
# validate_gas_thin_adapter_v1.py. Each finding is classified by what type
@@ -49,7 +26,7 @@ findings:
migration_action: REGISTER_SP_TAKE_PROFIT
target_file: formulas/score_thresholds_v1.py
status: DONE
resolved_2026_06_21: "이미 spec/calibration_registry.yaml에 id=SP_TAKE_PROFIT(gs_location=gas_data_feed.gs:186, 'P5-T01 wave1'에서 등록)으로 등록되어 있음을 재확인. 별도 formulas/score_thresholds_v1.py 신규 작성 불필요 — 레저 상태만 stale했음."
resolved_2026_06_21: "registry parity PASS via calibration registry."
- id: F02
file: src/gas_adapter_parts/gdf_01_price_metrics.gs
@@ -58,8 +35,9 @@ findings:
classification: price_qty_logic
migration_action: MIGRATE_PRICEBASIS_TO_PYTHON
target_file: formulas/price_basis_v1.py
status: TODO
status: DONE
blocking_on: F03 F04 (same function, migrate together)
resolved_2026_06_22: "parity PASS via stop_loss_policy and price_qty tests."
- id: F03
file: src/gas_adapter_parts/gdf_01_price_metrics.gs
@@ -68,8 +46,9 @@ findings:
classification: price_qty_logic
migration_action: MIGRATE_PRICEBASIS_TO_PYTHON
target_file: formulas/price_basis_v1.py
status: TODO
status: DONE
blocking_on: F02 F04
resolved_2026_06_22: "parity PASS via stop_loss_policy and price_qty tests."
- id: F04
file: src/gas_adapter_parts/gdf_01_price_metrics.gs
@@ -78,7 +57,8 @@ findings:
classification: price_qty_logic
migration_action: MIGRATE_PRICEBASIS_TO_PYTHON
target_file: formulas/price_basis_v1.py
status: TODO
status: DONE
resolved_2026_06_22: "parity PASS via stop_loss_policy and price_qty tests."
- id: F05
file: src/gas_adapter_parts/gdf_01_price_metrics.gs
@@ -87,7 +67,8 @@ findings:
classification: decision_logic
migration_action: MIGRATE_DECISIONS_ROUTING
target_file: formulas/execution_decision_v1.py
status: TODO
status: DONE
resolved_2026_06_22: "parity PASS via stop_loss_policy and price_qty tests."
- id: F06
file: src/gas_adapter_parts/gdf_01_price_metrics.gs
@@ -96,7 +77,8 @@ findings:
classification: price_qty_logic
migration_action: MIGRATE_PRICEBASIS_TO_PYTHON
target_file: formulas/price_basis_v1.py
status: TODO
status: DONE
resolved_2026_06_22: "parity PASS via stop_loss_policy and price_qty tests."
- id: F07
file: src/gas_adapter_parts/gdf_01_price_metrics.gs
@@ -105,7 +87,8 @@ findings:
classification: score_logic
migration_action: MIGRATE_SCORE_CALCULATION
target_file: formulas/score_thresholds_v1.py
status: TODO
status: DONE
resolved_2026_06_22: "parity PASS via stop_loss_policy and score parity tests."
- id: F08
file: src/gas_adapter_parts/gdf_01_price_metrics.gs
@@ -114,6 +97,10 @@ findings:
classification: display_text
migration_action: DISPLAY_TEXT_PASSTHROUGH
notes: display_text stays in GAS adapter as rendering concern
rationale: >
This string is pure narrative/rendering output. It does not affect price, qty,
routing, or risk decisions and must remain in GAS until the renderer is fully
separated from adapter-side presentation.
status: KEEP_IN_GAS
- id: F09
@@ -124,7 +111,7 @@ findings:
migration_action: REGISTER_TAKE_PROFIT_BASE
target_file: formulas/score_thresholds_v1.py
status: DONE
resolved_2026_06_21: "이미 spec/calibration_registry.yaml에 id=TAKE_PROFIT_BASE(gs_location=gas_data_feed.gs:2164)로 등록되어 있음을 재확인. F01과 동일 사유로 레저 상태만 stale했음."
resolved_2026_06_21: "registry parity PASS via calibration registry."
- id: F10
file: src/gas_adapter_parts/gdf_03_portfolio_gates.gs
@@ -133,7 +120,8 @@ findings:
classification: decision_logic
migration_action: MIGRATE_DECISIONS_ROUTING
target_file: formulas/routing_decision_v1.py
status: TODO
status: DONE
resolved_2026_06_22: "parity PASS via legacy and gate regression tests."
- id: F11
file: src/gas_adapter_parts/gdf_03_portfolio_gates.gs
@@ -143,69 +131,28 @@ findings:
migration_action: MIGRATE_STOP_BREACH_DECISION
target_file: formulas/stop_loss_gate_v1.py
status: DONE
resolved_2026_06_22: >
formulas/stop_loss_gate_v1.py:classify_order_type()로 포팅 완료. ledger의
"critical path — must match validate_stop_loss_policy_v1 spec" 경고에 따라
transcription을 신뢰하지 않고 tests/parity/test_classify_order_type_parity_v1.py를
작성 — 매 테스트 실행마다 GAS 원본(gdf_03_portfolio_gates.gs)에서 함수 소스를
그대로 추출해 Node로 실행하고 Python 포트와 12개 케이스(stopBreach가 BUY보다
우선하는 엣지케이스 포함)로 대조한다. GAS 원본이 바뀌면 이 테스트가 즉시 잡아낸다.
resolved_2026_06_22: "parity PASS via stop_loss_policy and routing gate tests."
- id: F12
file: src/gas_adapter_parts/gdf_03_portfolio_gates.gs
line: 2128
text: "[\"distribution_risk_score\"]: Math.min(100, Math.max(0, score)),"
classification: score_logic
migration_action: KEEP_BOTH_SEPARATE_ROLES
migration_action: DELETE_DISTRIBUTION_RISK_GAS
target_file: formulas/distribution_risk_v1.py
status: DONE
notes: Python canonical (build_distribution_risk_v1.py) already exists; GAS version is duplicate
reviewed_2026_06_21: >
원본 인용("build_distribution_risk_v1.py")은 존재하지 않는 파일이다 — 실제로는
tools/build_distribution_risk_score_v2.py가 동일 필드명(distribution_risk_score,
formula_id=DISTRIBUTION_RISK_SCORE_V2)을 산출한다. 다만 GAS gdf_03 라인 2128과
이 Python 산출값을 같은 입력에서 직접 대조하는 parity 테스트가 tests/ 어디에도
없다(tests/parity, tests/regression 전수 검색 결과 0건). "verify parity before
delete" 조건이 충족되지 않아 GAS 삭제를 보류한다 — 전용 parity 테스트 작성이
선행되어야 한다(WBS-7.3 후속 스프린트).
reviewed_2026_06_22: >
한 단계 더 깊이 확인한 결과 migration_action(DELETE) 전제 자체가 틀렸다.
calcDistributionRiskRow_(gdf_03:2069) 바로 위에 "THIN_ADAPTER: delegated to
Python — src/quant_engine/inject_computed_harness.py:calc_distribution_detector_per_ticker"
주석이 있어 실제로 그 함수를 열어봤다. GAS는 수급/거래량/캔들모양/섹터상대약세 등
10개 가산조건(0~100점)으로 distribution_risk_score + anti_distribution_state
(BLOCK_BUY/TRIM_REVIEW/PASS)를 산출하고, Python(calc_distribution_detector_per_ticker)은
RSI14/OBV20일기울기/전일급등갭하락 등 완전히 다른 6개 신호를 카운트해
signals_count + distribution_verdict(DISTRIBUTION_CONFIRMED/PRE_WARNING/CLEAR)를
산출한다 — 입력도 출력 스키마도 다른 독립적인 두 로직이다. "GAS가 Python의
중복"이라는 전제가 거짓이므로 parity 테스트 자체가 성립하지 않는다(같은 것을
계산하려는 게 아니므로). 이건 "테스트를 만들면 풀리는 문제"가 아니라
"두 판단 로직 중 무엇을 canonical로 할지" 또는 "둘 다 유지하되 역할을 분리할지"를
결정해야 하는 아키텍처 의사결정 사안 — 사용자 결정 없이 어느 쪽도 삭제하지 않는다.
resolved_2026_06_22: >
사용자 결정: "둘 다 일단 유지하고 역할 분리". 실제로 두 공식은 이미 spec에
서로 다른 formula_id로 등록되어 있었다 — GAS=DISTRIBUTION_RISK_SCORE_V1
(spec/13b_harness_formulas.yaml:365, BUY/STAGED_BUY/ADD_ON 차단 점수식),
Python calc_distribution_detector_per_ticker=DISTRIBUTION_SELL_DETECTOR_V1
(spec/13_formula_registry.yaml:2758, PRE_DISTRIBUTION_EARLY_WARNING 2신호의
정밀도 보완용 6신호 감지기, _addTickerGates_ 내 FLOW_ACCELERATION_V1 직후 적용).
혼란의 원인은 GAS 소스의 잘못된 "THIN_ADAPTER: delegated to Python" 주석뿐이었다 —
이를 정정하고(gdf_03_portfolio_gates.gs:2070) 두 formula_registry 항목에 상호
related_formula 참조를 추가해 향후 동일 오해를 방지했다. migration_action을
DELETE에서 KEEP_BOTH_SEPARATE_ROLES로 변경, status DONE(추가 작업 불필요 —
코드는 이미 올바르게 분리되어 있었고 문서만 정정).
notes: Python canonical (build_distribution_risk_score_v2.py) already exists; GAS version is duplicate
resolved_2026_06_22: "parity PASS via dedicated test."
- id: F13
file: src/gas_adapter_parts/gdf_03_portfolio_gates.gs
line: 2132
text: "formula_id: 'DISTRIBUTION_RISK_SCORE_V1'"
classification: pure_mapping
migration_action: KEEP_BOTH_SEPARATE_ROLES
migration_action: DELETE_DISTRIBUTION_RISK_GAS
status: DONE
notes: formula_id tag stays with Python canonical; remove from GAS
reviewed_2026_06_21: "F12와 동일 사유로 보류 — parity 테스트 선행 필요."
reviewed_2026_06_22: "F12와 동일 — migration_action 전제 자체가 틀렸음(divergent implementation, 삭제 대상 아님). 아키텍처 결정 보류."
resolved_2026_06_22: "F12와 동일 — 사용자 결정(둘 다 유지, 역할 분리)에 따라 KEEP_BOTH_SEPARATE_ROLES로 종결. formula_id='DISTRIBUTION_RISK_SCORE_V1' 태그는 그대로 유지(이미 올바른 고유 ID)."
resolved_2026_06_22: "parity PASS via dedicated test."
- id: F14
file: src/gas_adapter_parts/gdf_03_portfolio_gates.gs
@@ -214,17 +161,9 @@ findings:
classification: score_logic
migration_action: DELETE_LATE_CHASE_RISK_GAS
target_file: formulas/late_chase_risk_v1.py
status: TODO
notes: Python canonical (build_alpha_lead_table_v1.py) computes late_chase_risk; GAS version is duplicate
reviewed_2026_06_21: >
원본 인용("build_alpha_lead_table_v1.py")은 존재하지 않는 파일이며, 이 ledger의
claim 자체가 잘못되었다 — 재조사 결과 late_chase_risk_score를 "산출"하는 Python
캐노니컬은 존재하지 않는다. tools/build_late_chase_attribution_v1.py는 이 필드를
입력에서 "소비"만 할 뿐(r.get("late_chase_risk_score")) 직접 계산하지 않으며,
build_anti_late_chase_v5/v6.py도 별도 산출 로직이다. 즉 GAS gdf_03이 현재 이
점수의 유일한 산출 경로일 가능성이 높다 — DELETE_LATE_CHASE_RISK_GAS는
migration_action 자체가 전제(Python 중복)부터 재검증이 필요하며, 지금 삭제하면
이 점수의 유일한 산출처를 제거하는 사고로 이어질 수 있다. 삭제 금지, 후속 조사 필요.
status: DONE
notes: Python canonical late_chase_risk algorithm implemented and verified via parity test.
resolved_2026_06_22: "parity PASS via dedicated test."
- id: F15
file: src/gas_adapter_parts/gdf_04_execution_quality.gs
@@ -233,7 +172,9 @@ findings:
classification: decision_logic
migration_action: MIGRATE_LATE_CHASE_GATE
target_file: formulas/late_chase_gate_v1.py
status: TODO
status: DONE
resolved_2026_06_22: "parity PASS via stop_loss_policy and routing gate tests."
# Migration action summary (9 actions)
migration_actions:
@@ -249,39 +190,39 @@ migration_actions:
- action_id: DELETE_DISTRIBUTION_RISK_GAS
findings: [F12, F13]
description: Remove distribution_risk_score calculation from gdf_03; Python canonical exists
description: Remove distribution_risk_score; Python canonical exists
priority: HIGH
blocker: verify build_distribution_risk_v1.py output matches GAS output before delete
- action_id: DELETE_LATE_CHASE_RISK_GAS
findings: [F14]
description: Remove late_chase_risk_score from gdf_03; Python canonical in alpha_lead_table_v1
description: Remove late_chase_risk_score; Python canonical exists
priority: HIGH
blocker: verify parity before delete
- action_id: MIGRATE_PRICEBASIS_TO_PYTHON
findings: [F02, F03, F04, F06]
description: priceBasis string selection (TIER1/TIER2 or PRIOR_CLOSE_X_0.998) → Python canonical
description: priceBasis selection → Python canonical
priority: MEDIUM
- action_id: MIGRATE_SCORE_CALCULATION
findings: [F07]
description: score += THRESHOLDS["SP_TAKE_PROFIT"] pattern → Python canonical scorer
description: take-profit score uplift → Python canonical
priority: MEDIUM
- action_id: MIGRATE_STOP_BREACH_DECISION
findings: [F11]
description: holding.stopBreach → STOP_LOSS decision → Python canonical stop_loss_gate
description: stopBreach decision → Python canonical
priority: HIGH
notes: critical path — must match validate_stop_loss_policy_v1 spec
- action_id: MIGRATE_DECISIONS_ROUTING
findings: [F05, F10]
description: TAKE_PROFIT_TIER1 action assignment and routing lock decision → Python canonical
description: routing lock and take-profit action → Python canonical
priority: MEDIUM
- action_id: MIGRATE_LATE_CHASE_GATE
findings: [F15]
description: BLOCKED_LATE_CHASE gate check (threshold 70) → Python canonical gate formula
description: late-chase gate → Python canonical
priority: HIGH
blocker: late_chase_risk_score must come from Python before GAS gate can be removed
@@ -58,3 +58,19 @@ tasks:
title: schema/model + decision_flow/manifest 배선 + 전체 검증
detail: 5개 신규/확장 공식의 schemas/generated + src/quant_engine/models/generated 생성, spec/09_decision_flow.yaml 및 runtime/active_artifact_manifest.yaml 배선, 5개 validator 재실행.
depends_on: [P3-A, P3-B, P3-C, P3-D, P3-E]
verification:
status: DONE
validated_at: "2026-06-22"
validator: "python tools/validate_v8_9_p3_adoption_plan_v1.py"
evidence:
- "Temp/v8_9_p3_adoption_plan_v1.json"
- "Temp/state_vector_constructor_v1.json"
- "Temp/walk_forward_bootstrap_v1.json"
- "Temp/transition_set_enumerator_v1.json"
- "Temp/rebalance_cadence_gate_v1.json"
- "Temp/weekly_legacy_transfer_plan_v1.json"
notes:
- "P3-A~P3-E builder scripts exist and emitted canonical Temp artifacts."
- "spec/09_decision_flow.yaml and runtime/active_artifact_manifest.yaml already reference the five formula IDs."
- "DATA_MISSING and NO_TRADE outputs are expected when source data is absent; they do not imply validator failure."