Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions core/operator_health.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
18 changes: 16 additions & 2 deletions tests/test_operator_health.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
Loading