From c4da8bf4604363a9c8d96fcdf06de70db6cef0a7 Mon Sep 17 00:00:00 2001 From: Quant Trader Date: Tue, 7 Jul 2026 16:57:19 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EC=8A=B9=EA=B2=A9=20=EB=8C=80=EA=B8=B0?= =?UTF-8?q?=20=EC=83=81=ED=83=9C=EB=A5=BC=20=ED=97=AC=EC=8A=A4=20=EA=B2=BD?= =?UTF-8?q?=EB=B3=B4=EC=97=90=EC=84=9C=20=EB=9D=BC=EB=B2=A8=EB=A1=9C=20?= =?UTF-8?q?=EA=B0=95=EB=93=B1=20=E2=80=94=20=EB=8F=84=EB=8B=AC=20=EB=B6=88?= =?UTF-8?q?=EA=B0=80=EB=8A=A5=ED=95=98=EB=8D=98=20OK=20=ED=8C=90=EC=A0=95?= =?UTF-8?q?=20=EB=B3=B5=EA=B5=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit blocked_insufficient_evidence는 장애가 아니라 증거 축적 전 단계 표시인데 ATTENTION으로 분류돼 있어 연구 전략 2개 때문에 --mode health가 매일 경보(exit 1)였다. OK가 도달 불가능하면 ATTENTION은 정보량이 없고 진짜 장애(degraded/frozen)가 와도 어제와 같은 색이라 구분이 안 된다. 게이트 NO-GO를 라벨로 강등했던 것과 같은 원칙 적용: - _EXPECTED_IDLE_STATES 분리, verdict는 OK 유지 + 노트에 승격 대기 표시 - degraded/frozen/수동 동결/이상 징후 경보는 그대로 (대기 상태여도 freeze나 anomaly가 붙으면 여전히 ATTENTION — 테스트로 고정) 실CLI 검증: python main.py --mode health → 운영 헬스 OK / exit 0 (최초) --- core/operator_health.py | 14 +++++++++++--- tests/test_operator_health.py | 18 ++++++++++++++++-- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/core/operator_health.py b/core/operator_health.py index 0e01581c..fc4465e6 100644 --- a/core/operator_health.py +++ b/core/operator_health.py @@ -14,9 +14,10 @@ 알파 없음이 정착 결론인 체제에서는 상시 NO-GO가 정상이므로 전체 verdict에 합산하지 않는다(헤드라인의 게이트 라벨로 보고; 매일 빨강이면 진짜 장애를 못 알아본다): - BLOCKED : frozen 전략 존재, 또는 바스켓 운영 차단 수준 이상. - - ATTENTION: degraded/blocked_insufficient_evidence 전략, manual freeze, 최근 anomaly, + - ATTENTION: degraded 전략, manual freeze, 최근 anomaly, 바스켓 스냅샷 끊김, 또는 게이트 artifact의 '장애성' 신호(부재/stale/표기 불일치). - - OK : 위 어느 것에도 안 걸림. (게이트 NO-GO 여부와 무관) + - OK : 위 어느 것에도 안 걸림. (게이트 NO-GO 여부와 무관. + blocked_insufficient_evidence도 같은 이유로 라벨만 남기고 합산하지 않는다) """ from __future__ import annotations @@ -28,7 +29,12 @@ # runtime state별 분류 _BLOCKING_STATES = {"frozen"} -_ATTENTION_STATES = {"degraded", "blocked_insufficient_evidence"} +_ATTENTION_STATES = {"degraded"} +# 승격 파이프라인 대기 상태 — 장애가 아니라 '증거 축적 전'이라는 단계 표시다. +# 알파 부재가 정착 결론인 현 체제에서 연구 전략들은 이 상태가 상시 정상이므로, +# verdict를 올리면 헬스가 영원히 ATTENTION이 되어 진짜 장애를 못 알아보게 된다 +# (게이트 NO-GO를 라벨로 강등한 것과 같은 원칙). 노트로는 계속 표시한다. +_EXPECTED_IDLE_STATES = {"blocked_insufficient_evidence"} def _worst(*verdicts: str) -> str: @@ -62,6 +68,8 @@ def summarize_runtime_state(state: Any) -> dict[str, Any]: notes.append(f"state={s}") elif s in _ATTENTION_STATES: notes.append(f"state={s}") + elif s in _EXPECTED_IDLE_STATES: + notes.append(f"state={s} (승격 대기 — 정상)") if manual_freeze: notes.append("manual_freeze") if anomalies: diff --git a/tests/test_operator_health.py b/tests/test_operator_health.py index 1d34b894..c3125e6e 100644 --- a/tests/test_operator_health.py +++ b/tests/test_operator_health.py @@ -34,9 +34,23 @@ def test_degraded_is_attention(self): out = summarize_runtime_state(_state("scoring", "degraded")) assert out["verdict"] == "ATTENTION" - def test_blocked_insufficient_evidence_is_attention(self): + def test_blocked_insufficient_evidence_is_expected_idle_ok(self): + # 승격 파이프라인 대기 = 단계 표시지 장애가 아니다 — verdict를 올리면 헬스가 + # 영원히 ATTENTION이 되어 진짜 장애를 못 알아본다(게이트 NO-GO 강등과 동일 원칙). out = summarize_runtime_state(_state("rotation", "blocked_insufficient_evidence")) - assert out["verdict"] == "ATTENTION" + assert out["verdict"] == "OK" + assert any("승격 대기" in n for n in out["notes"]) # 라벨로는 계속 표시 + + def test_idle_state_with_freeze_or_anomaly_still_alarms(self): + # 대기 상태여도 수동 동결·이상 징후는 실제 개입 신호 — 경보 유지 + frozen = summarize_runtime_state( + _state("rotation", "blocked_insufficient_evidence", manual_freeze=True) + ) + assert frozen["verdict"] == "ATTENTION" + anom = summarize_runtime_state( + _state("rotation", "blocked_insufficient_evidence", anomalies=["x"]) + ) + assert anom["verdict"] == "ATTENTION" def test_manual_freeze_on_normal_is_attention(self): out = summarize_runtime_state(_state("scoring", "normal", manual_freeze=True))