File size: 2,632 Bytes
4058302
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
"""Runtime configuration for the Incident Command Center environment.

All tunables are read from environment variables so the server is 12-factor
compatible and can be reconfigured per deployment without rebuilding the
image. Every field has a sensible default so local development "just works".
"""

from __future__ import annotations

import os
from dataclasses import dataclass

ENV_VERSION = "3.0.0"
ENV_NAME = "incident_command_center_env"


def _int_env(name: str, default: int) -> int:
    raw = os.getenv(name)
    if raw is None or raw == "":
        return default
    try:
        return int(raw)
    except ValueError:
        return default


def _bool_env(name: str, default: bool) -> bool:
    raw = os.getenv(name)
    if raw is None:
        return default
    return raw.strip().lower() in {"1", "true", "yes", "on"}


@dataclass(frozen=True)
class EnvConfig:
    name: str = ENV_NAME
    version: str = ENV_VERSION

    default_seed: int = 20260425
    easy_budget: int = 28
    medium_budget: int = 54
    hard_budget: int = 84
    easy_sla_minutes: int = 120
    medium_sla_minutes: int = 210
    hard_sla_minutes: int = 330

    sla_tick_minutes: int = 5
    max_reward_trace_len: int = 400
    structured_logging: bool = True
    log_level: str = "INFO"

    @classmethod
    def from_env(cls) -> "EnvConfig":
        return cls(
            name=os.getenv("ENV_NAME", ENV_NAME),
            version=os.getenv("ENV_VERSION", ENV_VERSION),
            default_seed=_int_env("ENV_SEED", 20260425),
            easy_budget=_int_env("ENV_EASY_BUDGET", 28),
            medium_budget=_int_env("ENV_MEDIUM_BUDGET", 54),
            hard_budget=_int_env("ENV_HARD_BUDGET", 84),
            easy_sla_minutes=_int_env("ENV_EASY_SLA", 120),
            medium_sla_minutes=_int_env("ENV_MEDIUM_SLA", 210),
            hard_sla_minutes=_int_env("ENV_HARD_SLA", 330),
            sla_tick_minutes=_int_env("ENV_SLA_TICK", 5),
            max_reward_trace_len=_int_env("ENV_MAX_REWARD_TRACE_LEN", 400),
            structured_logging=_bool_env("ENV_STRUCTURED_LOGGING", True),
            log_level=os.getenv("ENV_LOG_LEVEL", "INFO"),
        )

    def budget_for(self, task_name: str) -> int:
        return {
            "easy": self.easy_budget,
            "medium": self.medium_budget,
            "hard": self.hard_budget,
        }.get(task_name, self.medium_budget)

    def sla_for(self, task_name: str) -> int:
        return {
            "easy": self.easy_sla_minutes,
            "medium": self.medium_sla_minutes,
            "hard": self.hard_sla_minutes,
        }.get(task_name, self.medium_sla_minutes)