"""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()