chaosops / dashboard /transcript.py
helloAK96's picture
Initializing space
83136ac
"""Dump a human-readable transcript of one episode.
Used for the HF blog post and pitch materials. Unlike the live Rich
dashboard, this writes a plain text file so it can be embedded in
markdown, pasted into slides, or diff'd across training checkpoints.
Usage:
python -m chaosops.dashboard.transcript \\
--scenario autoscaler_cost_cut \\
--policy oracle \\
--difficulty hard \\
--out artifacts/transcripts/hard_autoscaler_oracle.txt
"""
from __future__ import annotations
import argparse
from pathlib import Path
from chaosops.agents.policies import (
Policy,
heuristic_policy,
oracle_policy,
random_policy,
)
from chaosops.agents.runner import EpisodeResult, run_episode
from chaosops.env.environment import ChaosOpsEnvironment
from chaosops.env.models import AgentRole, DifficultyTier, FailureType
from chaosops.env.world_sim import Scenario
ROLE_TAG = {
AgentRole.SRE: "SRE",
AgentRole.DEV: "DEV",
AgentRole.MANAGER: "MGR",
AgentRole.OVERSIGHT: "OVS",
}
def _build_policy(name: str, scenario: Scenario) -> Policy:
if name == "random":
return random_policy(seed=scenario.seed)
if name == "heuristic":
return heuristic_policy(seed=scenario.seed)
if name == "oracle":
return oracle_policy(scenario.failure_type)
raise ValueError(name)
def render_transcript(result: EpisodeResult) -> str:
lines: list[str] = []
s = result.scenario
lines.append("=" * 72)
lines.append("ChaosOps AI — episode transcript")
lines.append("=" * 72)
lines.append(f"scenario : {s.failure_type.value} ({s.difficulty.value})")
lines.append(f"seed : {s.seed}")
lines.append(f"rogue_agent : {s.rogue_fleet_agent or 'none (infra fault)'}")
lines.append("")
for step in result.steps:
tag = ROLE_TAG[step.role]
args = step.action.args or {}
args_str = " ".join(f"{k}={v}" for k, v in args.items())
lines.append(
f"t{step.turn:02d} [{tag}] action={step.action.action_type.value} "
f"target={step.action.target or '-'}{(' ' + args_str) if args_str else ''} "
f"reward={step.reward:+.1f}"
)
br = step.breakdown
subs = []
if br.resolved_bonus: subs.append(f"resolved{br.resolved_bonus:+.0f}")
if br.mttr_penalty: subs.append(f"mttr{br.mttr_penalty:+.0f}")
if br.early_root_cause_bonus: subs.append(f"early_rca{br.early_root_cause_bonus:+.0f}")
if br.rogue_caught_bonus: subs.append(f"rogue_caught{br.rogue_caught_bonus:+.0f}")
if br.rogue_false_positive_penalty: subs.append(f"false_flag{br.rogue_false_positive_penalty:+.0f}")
if br.wrong_fix_penalty: subs.append(f"wrong_fix{br.wrong_fix_penalty:+.0f}")
if br.miscommunication_penalty: subs.append(f"miscom{br.miscommunication_penalty:+.0f}")
if br.cascade_penalty: subs.append(f"cascade{br.cascade_penalty:+.0f}")
if br.under_budget_bonus: subs.append(f"under_budget{br.under_budget_bonus:+.0f}")
if subs:
lines.append(f" breakdown: {', '.join(subs)}")
lines.append("")
lines.append("-" * 72)
lines.append(
f"RESULT resolved={result.resolved} "
f"steps={result.final_step} "
f"cum_reward={result.cumulative_reward:+.1f} "
f"wrong_fixes={result.wrong_fixes} "
f"oversight_flags={result.oversight_flags}"
)
lines.append("-" * 72)
return "\n".join(lines) + "\n"
def _parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser()
parser.add_argument(
"--scenario",
type=str,
default="autoscaler_cost_cut",
choices=[f.value for f in FailureType],
)
parser.add_argument(
"--policy",
type=str,
default="oracle",
choices=["random", "heuristic", "oracle"],
)
parser.add_argument(
"--difficulty",
type=str,
default="hard",
choices=[d.value for d in DifficultyTier],
)
parser.add_argument("--seed", type=int, default=42)
parser.add_argument(
"--out",
type=Path,
default=Path("artifacts/transcripts/hard_autoscaler_oracle.txt"),
)
return parser.parse_args()
def main() -> None:
args = _parse_args()
env = ChaosOpsEnvironment()
scen = Scenario.from_type(
FailureType(args.scenario),
seed=args.seed,
difficulty=DifficultyTier(args.difficulty),
)
policy = _build_policy(args.policy, scen)
result = run_episode(env, scen, {r: policy for r in AgentRole})
text = render_transcript(result)
args.out.parent.mkdir(parents=True, exist_ok=True)
args.out.write_text(text)
print(text)
print(f"wrote {args.out}")
if __name__ == "__main__":
main()