Files
QuantEngineByItz/spec/09_decision_flow.yaml
kjh2064 a4de0505a0 WBS-8.7 1단계: spec-코드 동기화 확장 (12.5%→22.22%)
3개 contract 파일 추가 태깅:
- spec/00_execution_contract.yaml (execution_slippage + snapshot_admin)
- spec/08_scoring_rules.yaml (score_thresholds + qualitative_sell)
- spec/09_decision_flow.yaml (execution_decision + routing_decision)

결과: 36/162 파일 (22.22% coverage)
목표: 50% 이상 (점진적 확장)

CI gate: PASS
2026-06-22 23:30:19 +09:00

397 lines
23 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
meta:
title: "은퇴자산포트폴리오 — 의사결정 상태 머신"
parent_file: "RetirementAssetPortfolio.yaml"
version: "2026-05-15-F3_decision_flow"
language: "ko-KR"
timezone: "Asia/Seoul"
has_code_implementation: true
code_path: ["formulas/execution_decision_v1.py", "formulas/routing_decision_v1.py"]
purpose: >
LLM이 투자 판단을 임의 순서로 수행하지 않도록 상태 머신으로 절차를 고정한다.
각 상태는 통과 조건, 실패 시 행동, 참조 파일을 가진다.
conflict_precedence:
- risk_exit
- cash_floor
- anti_late_entry
- smart_money
- momentum
decision_flow:
initial_state: "MODEL_GOVERNANCE_GATE"
terminal_states: ["FINAL_DECISION", "INSUFFICIENT_DATA", "BLOCKED"]
deterministic_execution_control:
purpose: "텍스트 해석 차이로 매번 다른 결론이 나오는 것을 줄이기 위한 결정 추적·동률 처리·first-match 규칙."
rule: "모든 상태는 ordered_checks를 위에서 아래로 평가하고, 첫 번째 BLOCK/PASS/SELECT 결과를 decision_trace에 기록한다."
no_freeform_override:
- "상태 머신 밖의 산문 판단으로 final_action, grade, quantity, sell_priority를 변경 금지"
- "동일 입력·동일 기준시각이면 동일 decision_trace와 동일 final_action이 나와야 한다."
- "규칙 충돌 시 자연어로 절충하지 말고 tie_breaker 또는 INSUFFICIENT_DATA/BLOCKED로 종료한다."
trace_required_fields:
- "state"
- "check_id"
- "rule_ref"
- "inputs_used"
- "result"
- "selected_action"
- "blocked_actions"
- "missing_inputs"
- "tie_breaker_applied"
tie_breaker_order:
1: "source_of_truth_order 상위 파일"
2: "risk hard stop 또는 master_prohibitions"
3: "데이터 완성도 OK > PARTIAL > DATA_MISSING"
4: "계산 가능한 공식 ID가 있는 규칙"
5: "보수적 행동: BLOCKED/INSUFFICIENT_DATA/WATCH"
null_propagation_rule: "필수 입력이 null이면 해당 계산은 null로 유지하고 prohibited_calculations에 사유를 남긴다. null을 0으로 대체 금지."
output_requirement: "OUTPUT_VALIDATION에서 decision_trace 누락 시 schema_validation_status=FAIL."
states:
MODEL_GOVERNANCE_GATE: # [governance/todo/v8_9_p1_adoption_plan.yaml P1-5]
purpose: >
매 의사결정 사이클 시작 전 kill switch(data_quarantine_rate, implementation_shortfall,
T5_hit_rate, calibration_error, drawdown)를 평가해 execution_mode를 확정한다.
이후 모든 단계는 이 execution_mode를 기준으로 동작한다.
required_refs:
- "spec/formulas/domains/governance.yaml:MODEL_GOVERNANCE_KILL_SWITCH_V1"
- "tools/build_model_governance_kill_switch_v1.py"
required_inputs: ["data_quarantine_rate_pct", "implementation_shortfall_ratio", "t5_hit_rate_pct", "t5_sample_count", "calibration_error", "account_mdd_pct"]
computed_outputs: ["execution_mode", "kill_switch_triggered", "kill_switch_reason_codes"]
pass_condition: "execution_mode 확정(kill switch 평가 완료 또는 DATA_MISSING)"
fail_state: "INSUFFICIENT_DATA"
INPUT_VALIDATION:
purpose: "요청, 기준일, 계좌, 보유수량, 가격/수급/ATR 입력 존재 여부 확인"
required_refs:
- "spec/01_objective_profile.yaml:input_required"
- "spec/12_field_dictionary.yaml:field_dictionary"
- "spec/02_data_contract.yaml:quant_feed_contract"
required_inputs: ["request_scope", "analysis_date", "account_scope"]
computed_outputs: ["normalized_request", "field_alias_resolution_log"]
pass_condition: "minimum request context exists"
fail_state: "INSUFFICIENT_DATA"
DATA_COMPLETENESS_CHECK:
purpose: "데이터 상태 OK/PARTIAL/DATA_MISSING/DATA_CONFLICT/DATA_STALE 판정"
required_refs:
- "spec/02_data_contract.yaml:data_rule"
- "spec/02_data_contract.yaml:quant_feed_contract.data_completeness_gate"
- "spec/12_field_dictionary.yaml:field_dictionary.policy"
required_inputs: ["normalized_request", "raw_data_sources"]
computed_outputs: ["data_completeness_matrix", "missing_fields", "field_unit_conflicts"]
pass_condition: "data_completeness_matrix produced"
fail_state: "INSUFFICIENT_DATA"
STATE_VECTOR_CONSTRUCTION: # [governance/todo/v8_9_p3_adoption_plan.yaml P3-F]
purpose: >
holdings, cash, tax_lots, sector_graph, factor_exposures, macro_regime_probabilities를
단일 state_vector로 통합한다. cash_ladder 구성 시 WEEKLY_LEGACY_TRANSFER_PLAN_V1을
통해 미확정 레거시 이전계획을 deployable_cash에서 제외한다.
required_refs:
- "spec/formulas/domains/portfolio.yaml:STATE_VECTOR_CONSTRUCTOR_V1"
- "spec/formulas/domains/cash.yaml:WEEKLY_LEGACY_TRANSFER_PLAN_V1"
- "tools/build_state_vector_constructor_v1.py"
- "tools/build_weekly_legacy_transfer_plan_v1.py"
required_inputs: ["data_completeness_matrix", "account_snapshot"]
computed_outputs: ["state_vector", "state_vector_completeness_pct", "missing_components", "deployable_cash_contribution_krw"]
pass_condition: "state_vector 산출(결측 component 포함 가능)"
fail_state: "INSUFFICIENT_DATA"
HARD_FILTER_CHECK:
purpose: "하드 필터를 점수보다 먼저 적용"
required_refs:
- "spec/08_scoring_rules.yaml:hard_filters"
- "spec/risk/aggregate_risk.yaml:risk_control.aggregate_risk_cap"
- "spec/risk/circuit_breakers.yaml:risk_control.weekly_circuit_breaker"
- "spec/13_formula_registry.yaml:formula_registry.formulas.TOTAL_HEAT_V1"
required_inputs: ["data_completeness_matrix", "account_snapshot", "total_asset"]
computed_outputs: ["hard_filter_results", "total_heat_pct", "blocked_actions"]
pass_condition: "no blocking hard filter for requested action"
fail_state: "BLOCKED"
MARKET_REGIME_CHECK:
purpose: "Risk-On/Neutral/Risk-Off 및 현금 목표 확인"
required_refs:
- "spec/risk/market_risk_cash.yaml:risk_control.market_risk_score_based_cash"
- "spec/strategy/entry_core.yaml:entry_timing_guardrails.regime_based_entry"
- "spec/13_formula_registry.yaml:formula_registry.formulas.MARKET_RISK_SCORE_V1"
- "spec/13_formula_registry.yaml:formula_registry.formulas.TARGET_CASH_PCT_V1"
required_inputs: ["vix_close", "kospi_close", "kospi_ma20", "usd_krw", "usd_jpy_2d_change_pct", "credit_stress_status"]
computed_outputs: ["market_risk_score", "target_cash_pct", "market_regime_state"]
pass_condition: "market regime classified or marked UNKNOWN"
fail_state: "INSUFFICIENT_DATA"
STRATEGY_SCORING:
purpose: >
섹터/종목/수급/유동성/실적/밸류 점수 산출. GOLDEN_CROSS_SIGNAL_V1, STRONG_CLOSE_SIGNAL_V1,
VOLATILITY_EXPANSION_BREAKOUT_V1, FIFTY_TWO_WEEK_HIGH_TRIGGER_V1, CONSECUTIVE_STREAK_V1,
TREND_FILTER_GATE_V1은 component_scores의 보조신호로만 포함되며, 단독으로 BUY를
허가하지 않는다(BREAKOUT_QUALITY_GATE_V2/FOLLOW_THROUGH_DAY_CONFIRM_V1/ANTI_LATE_ENTRY_GATE_V2
체인 우회 금지).
required_refs:
- "spec/08_scoring_rules.yaml:strategy_score"
- "spec/strategy/sector_model.yaml:sector_model"
- "spec/13_formula_registry.yaml:formula_registry.formulas.FLOW_CREDIT_V1"
- "spec/formulas/domains/entry.yaml:GOLDEN_CROSS_SIGNAL_V1"
- "spec/formulas/domains/entry.yaml:STRONG_CLOSE_SIGNAL_V1"
- "spec/formulas/domains/entry.yaml:VOLATILITY_EXPANSION_BREAKOUT_V1"
- "spec/formulas/domains/entry.yaml:FIFTY_TWO_WEEK_HIGH_TRIGGER_V1"
- "spec/formulas/domains/entry.yaml:CONSECUTIVE_STREAK_V1"
- "spec/formulas/domains/entry.yaml:TREND_FILTER_GATE_V1"
required_inputs: ["close_price", "ma20", "flow_ok", "flow_rows", "frg_5d_sh", "inst_5d_sh", "avg_trade_value_5d"]
computed_outputs: ["flow_credit", "strategy_score", "component_scores", "grade_candidate", "golden_cross_today", "strong_close", "volatility_expansion_breakout", "fifty_two_week_high_breakout", "up_streak", "down_streak", "trend_filter_pass"]
pass_condition: "strategy_score calculated or missing fields listed"
fail_state: "INSUFFICIENT_DATA"
PORTFOLIO_CONSTRAINT_CHECK:
purpose: "계좌·비중·중복노출·현금·납입한도 확인"
required_refs:
- "spec/10_portfolio_rules.yaml"
- "spec/risk/portfolio_exposure.yaml:portfolio_exposure_framework"
required_inputs: ["target_cash_pct", "available_cash", "total_asset", "current_exposures", "account_scope"]
computed_outputs: ["portfolio_fit_score", "cash_floor_status", "exposure_limit_amounts"]
pass_condition: "portfolio constraints pass or downgrade action selected"
fail_state: "BLOCKED"
cash_shortfall_resolution: # [2026-05-19_HARNESS_AUDIT_V1] H2
rule_id: "CSR001"
purpose: >
현금 < target_cash_pct 확인 시 BUY를 결정론적으로 차단하고
SELL_PRIORITY 엔진으로 TRIM 수량을 자동 배정한다. LLM 임의 배정 금지.
trigger_condition: "CASH_RATIOS_V1.current_cash_pct < TARGET_CASH_PCT_V1.target_cash_pct"
steps:
step_1_block_buy:
action: "모든 BUY 신호 → IGNORE 전환. 이유 불문, LLM 재해석 금지."
output_key: "buy_gate_status = CASH_BLOCKED"
step_2_calc_shortfall:
formula: "cash_shortfall_krw = max(0, (target_cash_pct/100 - current_cash_pct/100) × total_asset)"
source: "CASH_RATIOS_V1 결과 기반 — LLM 직접 계산 금지"
output_key: "cash_shortfall_krw"
step_3_assign_trim:
source: "sell_priority_engine (spec/risk/portfolio_exposure.yaml)"
algorithm: >
SELL_PRIORITY 1순위 종목부터 계단식 TRIM 수량 배정.
잔여 부족액이 남으면 2순위로 이동하며 반복.
formula: "trim_qty = min(floor(remaining_shortfall_krw / current_price), holding_quantity)"
cascade: "remaining_shortfall_krw -= trim_qty × current_price → 다음 순위"
output_tag: "[CASH_RAISE_AUTO: {종목} {qty}주 TRIM → 예상확보 {proceeds}원]"
step_4_output_required:
fields:
- "cash_shortfall_krw (부족액)"
- "trim_assignments: [{종목, qty, expected_proceeds}] (배정 목록)"
- "post_trim_cash_pct (TRIM 후 예상 현금비중)"
enforcement:
- "수동 배정·서사적 배정 금지 — 공식 결과만 기재"
- "trim_assignments 없이 현금 부족 해소 주장 금지"
- "QEH_AUDIT_BLOCK.SELL_PRIORITY_V1 행에 배정 결과 요약 필수"
- "1순위 소진 전 2순위 배정 금지 (sell_priority_engine 순서 준수)"
SECTOR_EXPOSURE_REVIEW: # [governance/todo/v8_9_p1_adoption_plan.yaml P1-5]
purpose: >
섹터를 canonical ID로 분류하고 ETF lookthrough·factor beta residualization을 적용해
실질노출을 산출하며, 리더 생명주기(CAPTAIN~DISTRIBUTION_RISK)를 평가한다.
required_refs:
- "spec/formulas/domains/sector.yaml:SECTOR_EXPOSURE_GRAPH_V1"
- "spec/formulas/domains/sector.yaml:LEADER_LIFECYCLE_GATE_V1"
- "tools/build_sector_exposure_graph_v1.py"
required_inputs: ["exposure_limit_amounts", "current_exposures", "etf_constituents_json"]
computed_outputs: ["sector_family_total_pct", "lookthrough_etf_weight_pct", "leader_role"]
pass_condition: "섹터 노출 산출 또는 ETF_BUY_BLOCKED/DATA_MISSING 명시"
fail_state: "INSUFFICIENT_DATA"
POSITION_SIZING:
purpose: "ATR20·현금·목표비중·유동성으로 정수 수량 산출"
required_refs:
- "spec/05_position_sizing.yaml:position_sizing"
- "spec/13_formula_registry.yaml:formula_registry.formulas.RISK_BUDGET_CASCADE_V1"
- "spec/13_formula_registry.yaml:formula_registry.formulas.POSITION_SIZE_V1"
required_inputs: ["total_asset", "atr20", "entry_price", "available_cash", "exposure_limit_amounts", "bayesian_confidence_multiplier"]
computed_outputs: ["final_risk_budget", "atr_quantity", "cash_limit_quantity", "target_weight_limit_quantity", "sector_limit_quantity", "liquidity_limit_quantity", "final_quantity"]
pass_condition: "integer quantity calculated, or NO_QUANTITY reason emitted"
fail_state: "INSUFFICIENT_DATA"
EXIT_POLICY_CHECK:
purpose: >
손절/익절/trailing/보유주 점검 규칙 적용. 돌파 매수로 진입한 포지션에는
BREAKOUT_FAILURE_STOP_V1을 적용해 전고점 재이탈을 ANTI_WHIPSAW_GATE_V1과 별도로 포착한다.
required_refs:
- "spec/exit/stop_loss.yaml:stop_loss"
- "spec/exit/take_profit.yaml:take_profit"
- "spec/exit/position_review.yaml:position_review_cycle"
- "spec/13_formula_registry.yaml:formula_registry.formulas.EXPECTED_EDGE_V1"
- "spec/formulas/domains/exit.yaml:BREAKOUT_FAILURE_STOP_V1"
required_inputs: ["entry_price", "stop_price", "target_price", "final_quantity"]
computed_outputs: ["expected_edge", "stop_order", "take_profit_order", "invalidation_conditions", "breakout_failure"]
pass_condition: "exit or hold policy evaluated"
fail_state: "INSUFFICIENT_DATA"
proactive_exit_radar_check: # [2026-05-19_PROACTIVE_RADAR_V1]
purpose: >
보유 포지션 분석 시 항상 실행. 가격이 멀쩡할 때도 수급·유동성·섹터
신호로 선제 매도 적기를 감지한다. '매도가 예술이다' 원칙 구현.
required_refs:
- "spec/exit/proactive_exit_radar.yaml"
- "spec/13_formula_registry.yaml:DIVERGENCE_SCORE_V1"
- "spec/13_formula_registry.yaml:OVERHANG_PRESSURE_V1"
- "spec/13_formula_registry.yaml:SECTOR_ROTATION_RADAR_V1"
required_inputs:
- "frg_5d_sh, inst_5d_sh, flow_credit (W1)"
- "frg_5d_sh, frg_20d_sh, volume, avg_volume_5d (W2)"
- "sector_flow.SmartMoney_5D_Norm_Score, sector_flow.Rank (W3)"
computed_outputs:
- "divergence_score + W1_status"
- "overhang_score + W2_status"
- "W3_status"
- "radar_composite_status (PASS/CAUTION/ALERT/CRITICAL_ALERT)"
- "PROACTIVE_RADAR_BLOCK (보고서 출력용)"
hard_rules:
- "ALERT 이상 발화 시 sell_priority_engine 실행 필수"
- "CRITICAL_ALERT 시 코어 포지션 포함 전면 재검토 강제"
- "LLM이 레이더 결과를 완화하는 서사 출력 금지 (Section B 해설만 허용)"
- "RADAR_MISSING(데이터 부족) 시 soft-block: 보유 포지션 수동 점검 권고 문구 출력"
PORTFOLIO_TRANSITION_REVIEW: # [governance/todo/v8_9_p0_adoption_plan.yaml P0-1.6, v8_9_p2_adoption_plan.yaml P2-E]
purpose: >
개별 종목 단위 결정을 포트폴리오 전체 전환 효용으로 재평가한다.
EXIT_POLICY_CHECK에서 나온 sell 후보들을 단일 전환 패킷으로 비교해
selected_transition_set 또는 NO_TRADE를 결정론적으로 확정한다. CE70/CVaR95 분포는
WALK_FORWARD_BOOTSTRAP_V1으로 생성하고 SCENARIO_SHOCK_MATRIX_V1의 5개 스트레스
시나리오를 반영하며, candidate 1건이 아니라 TRANSITION_SET_ENUMERATOR_V1으로 조합 단위
hard_constraint(MRC/CVaR95 포함)를 재검증한다. 실제 실행은 REBALANCE_CADENCE_GATE_V1의
rebalance_execution_allowed=true일 때만 허용된다.
required_refs:
- "spec/formulas/domains/portfolio.yaml:PORTFOLIO_TRANSITION_UTILITY_V1"
- "spec/formulas/domains/portfolio.yaml:TRANSITION_SET_ENUMERATOR_V1"
- "spec/formulas/domains/portfolio.yaml:REBALANCE_CADENCE_GATE_V1"
- "spec/formulas/domains/simulation.yaml:SCENARIO_SHOCK_MATRIX_V1"
- "spec/formulas/domains/simulation.yaml:WALK_FORWARD_BOOTSTRAP_V1"
- "tools/build_portfolio_transition_optimizer_v1.py"
- "tools/build_transition_set_enumerator_v1.py"
- "tools/build_scenario_shock_matrix_v1.py"
- "tools/build_walk_forward_bootstrap_v1.py"
- "tools/build_rebalance_cadence_gate_v1.py"
required_inputs: ["stop_order", "take_profit_order", "sell_waterfall_rows", "cash_repair_benefit_krw", "rebalance_execution_allowed"]
computed_outputs: ["transition_utility_krw", "acceptance_margin_krw", "selected_transition", "portfolio_transition_final_action", "selected_transition_set", "scenario_results", "post_trade_mrc", "post_trade_cvar95_krw"]
pass_condition: "selected_transition_set 결정(rebalance_execution_allowed=true 필요) 또는 default_action=NO_TRADE 명시"
fail_state: "INSUFFICIENT_DATA"
EXECUTION_CAPACITY_CHECK: # [governance/todo/v8_9_p1_adoption_plan.yaml P1-5, v8_9_p2_adoption_plan.yaml P2-E]
purpose: >
selected_transition_set의 주문금액이 실제 체결 가능 용량(20일 평균거래대금, 당일 거래대금,
호가창 깊이)을 초과하지 않는지 확인하고, broker_microstructure_packet 결측 시 차단한다.
용량이 확인되면 EXECUTION_PLAN_COMPILER_V1으로 30/30/40 LIMIT_SPLIT 슬라이스를 컴파일한다.
required_refs:
- "spec/formulas/domains/execution.yaml:EXECUTION_CAPACITY_LADDER_V1"
- "spec/formulas/domains/execution.yaml:EXECUTION_PLAN_COMPILER_V1"
- "tools/build_execution_capacity_ladder_v1.py"
- "tools/build_execution_plan_compiler_v1.py"
required_inputs: ["selected_transition_set", "avg_trade_value_20d_krw", "intraday_trade_value_krw", "orderbook_top3_depth_krw", "spread_bps"]
computed_outputs: ["order_capacity_krw", "execution_plan_status", "compiled_slices"]
pass_condition: "order_capacity_krw 산출 또는 EXECUTION_PLAN_BLOCKED 명시"
fail_state: "INSUFFICIENT_DATA"
OUTPUT_VALIDATION:
purpose: "JSON Schema와 HTS 표 필드 검증"
required_refs:
- "schemas/output_schema.json"
- "spec/07_output_schema.yaml"
required_inputs: ["final_action", "orders", "scores", "position_sizing", "triggered_rules", "missing_data"]
computed_outputs: ["schema_validation_status", "prohibited_calculations"]
pass_condition: "all required output fields populated or prohibited_calculations filled"
fail_state: "INSUFFICIENT_DATA"
FINAL_DECISION:
purpose: "BUY/HOLD/SELL/TRIM/ROTATE/AVOID/WATCH/INSUFFICIENT_DATA 중 하나로 결론"
required_refs:
- "spec/07_output_schema.yaml:recommendation_grade"
- "spec/formulas/domains/governance.yaml:IMMUTABLE_DECISION_LEDGER_V1"
output_required:
- "final_action"
- "grade"
- "orders or prohibited_calculations"
- "rules_used"
- "ledger_append_status"
post_state_action: "tools/build_immutable_decision_ledger_v1.py 호출 — decision_id 재기록 시도는 DUPLICATE_DECISION_ID로 거부."
INSUFFICIENT_DATA:
purpose: "데이터 부족으로 산출 불가. 다음 확인 출처를 제시."
output_required:
- "missing_fields"
- "prohibited_calculations"
- "next_source_to_check"
- "ledger_append_status"
post_state_action: "INSUFFICIENT_DATA로 종료해도 IMMUTABLE_DECISION_LEDGER_V1에 기록한다(결정 없음도 기록 대상)."
BLOCKED:
purpose: "하드 필터 또는 리스크 정책으로 행동 차단."
output_required:
- "triggered_rules"
- "blocked_action"
- "allowed_alternative"
- "ledger_append_status"
post_state_action: "BLOCKED로 종료해도 IMMUTABLE_DECISION_LEDGER_V1에 기록한다."
transitions:
- from: "MODEL_GOVERNANCE_GATE"
to: "INPUT_VALIDATION"
condition: "execution_mode 확정(kill switch 평가 완료 또는 DATA_MISSING)"
- from: "MODEL_GOVERNANCE_GATE"
to: "INSUFFICIENT_DATA"
condition: "kill switch 평가에 필요한 모든 지표가 결측"
- from: "INPUT_VALIDATION"
to: "DATA_COMPLETENESS_CHECK"
condition: "minimum request context exists"
- from: "INPUT_VALIDATION"
to: "INSUFFICIENT_DATA"
condition: "account/request context missing and cannot be inferred"
- from: "DATA_COMPLETENESS_CHECK"
to: "STATE_VECTOR_CONSTRUCTION"
condition: "data_completeness_matrix produced"
- from: "DATA_COMPLETENESS_CHECK"
to: "INSUFFICIENT_DATA"
condition: "matrix cannot be produced"
- from: "STATE_VECTOR_CONSTRUCTION"
to: "HARD_FILTER_CHECK"
condition: "state_vector 산출(결측 component 포함 가능)"
- from: "HARD_FILTER_CHECK"
to: "BLOCKED"
condition: "blocking hard_filter failed"
- from: "HARD_FILTER_CHECK"
to: "MARKET_REGIME_CHECK"
condition: "no blocking hard_filter failed"
- from: "MARKET_REGIME_CHECK"
to: "STRATEGY_SCORING"
condition: "regime classified or UNKNOWN with caution"
- from: "STRATEGY_SCORING"
to: "PORTFOLIO_CONSTRAINT_CHECK"
condition: "strategy score calculated or downgrade reason emitted"
- from: "PORTFOLIO_CONSTRAINT_CHECK"
to: "BLOCKED"
condition: "cash_floor, duplicate exposure, account limit, or Total_Heat blocks requested action"
- from: "PORTFOLIO_CONSTRAINT_CHECK"
to: "SECTOR_EXPOSURE_REVIEW"
condition: "requested action requires quantity or affects sector exposure"
- from: "PORTFOLIO_CONSTRAINT_CHECK"
to: "EXIT_POLICY_CHECK"
condition: "requested action is hold/trim/sell review"
- from: "SECTOR_EXPOSURE_REVIEW"
to: "POSITION_SIZING"
condition: "섹터 노출 산출 또는 ETF_BUY_BLOCKED/DATA_MISSING 명시"
- from: "SECTOR_EXPOSURE_REVIEW"
to: "INSUFFICIENT_DATA"
condition: "sector exposure 계산에 필요한 입력 누락"
- from: "POSITION_SIZING"
to: "EXIT_POLICY_CHECK"
condition: "quantity calculated or NO_QUANTITY reason emitted"
- from: "EXIT_POLICY_CHECK"
to: "PORTFOLIO_TRANSITION_REVIEW"
condition: "order/hold/watch decision prepared"
- from: "PORTFOLIO_TRANSITION_REVIEW"
to: "EXECUTION_CAPACITY_CHECK"
condition: "selected_transition 결정 또는 NO_TRADE 명시"
- from: "PORTFOLIO_TRANSITION_REVIEW"
to: "INSUFFICIENT_DATA"
condition: "transition utility 계산에 필요한 입력 누락"
- from: "EXECUTION_CAPACITY_CHECK"
to: "OUTPUT_VALIDATION"
condition: "order_capacity_krw 산출 또는 EXECUTION_PLAN_BLOCKED 명시 (NO_TRADE인 경우 즉시 통과)"
- from: "EXECUTION_CAPACITY_CHECK"
to: "INSUFFICIENT_DATA"
condition: "broker_microstructure_packet 필드 누락"
- from: "OUTPUT_VALIDATION"
to: "FINAL_DECISION"
condition: "schema and required output fields valid"
- from: "OUTPUT_VALIDATION"
to: "INSUFFICIENT_DATA"
condition: "required output fields missing without prohibited_calculations reason"
global_prohibitions:
- "HARD_FILTER_CHECK 이전에 BUY 결론 출력 금지"
- "POSITION_SIZING 이전에 정수 주문수량 출력 금지"
- "OUTPUT_VALIDATION 실패 상태에서 즉시 실행 플레이북 출력 금지"
- "BLOCKED 상태를 WATCH로 미화 금지. 차단 사유를 명시한다."
- "anti_late_entry gate 평가 이전에 BUY 또는 STAGED_BUY 결론 출력 금지"
- "anti_late_entry gate가 FAIL인 경우 BUY/STAGED_BUY의 매수 수량은 0으로 강제하며 action은 WATCH 또는 BLOCKED로 강등한다."