From 23c92403e6752effbd60400253bfc62f789cb572 Mon Sep 17 00:00:00 2001 From: hyeokjun32 Date: Fri, 19 Jun 2026 22:51:50 +0900 Subject: [PATCH] Show operation risk in sustained CLI --- docs/agent_orchestration_summary_contract.ko.md | 4 ++++ docs/agent_orchestration_summary_contract.md | 4 ++++ src/inferedge_orchestrator/cli.py | 14 ++++++++++++++ tests/test_multi_workload_sustained.py | 5 +++++ 4 files changed, 27 insertions(+) diff --git a/docs/agent_orchestration_summary_contract.ko.md b/docs/agent_orchestration_summary_contract.ko.md index e65fbbe..c503ed3 100644 --- a/docs/agent_orchestration_summary_contract.ko.md +++ b/docs/agent_orchestration_summary_contract.ko.md @@ -312,6 +312,10 @@ deployment judgement를 수행하지 않습니다. checker 출력은 compact `operation_timeline` review hint와 stale-drop count/task도 함께 보여주므로, reviewer가 전체 JSON을 열기 전에 queue delay/fallback/deadline/stale drop pressure를 확인할 수 있습니다. +`run-multi-workload-sustained` CLI도 `operation_risk_rollup`에서 가져온 +`operation-risk` first-read line을 출력해 risk level, primary reason, affected +task를 바로 보여줍니다. 이는 reviewer navigation aid일 뿐이며 JSON rollup이 +source evidence이고, deployment decision owner는 계속 Lab입니다. ## Compatibility Rules diff --git a/docs/agent_orchestration_summary_contract.md b/docs/agent_orchestration_summary_contract.md index ba8933b..e4acc28 100644 --- a/docs/agent_orchestration_summary_contract.md +++ b/docs/agent_orchestration_summary_contract.md @@ -310,6 +310,10 @@ markers only; it does not perform regression analysis or deployment judgement. The checker output also prints the compact `operation_timeline` review hints and stale-drop count/tasks so reviewers can see queue delay/fallback/deadline/stale drop pressure without opening the full JSON first. +The `run-multi-workload-sustained` CLI also prints an `operation-risk` first-read +line from `operation_risk_rollup` with risk level, primary reasons, and affected +tasks. This is a reviewer navigation aid only; the JSON rollup remains the +source evidence, and Lab remains the deployment decision owner. ## Compatibility Rules diff --git a/src/inferedge_orchestrator/cli.py b/src/inferedge_orchestrator/cli.py index 6ea19a8..6fc3177 100644 --- a/src/inferedge_orchestrator/cli.py +++ b/src/inferedge_orchestrator/cli.py @@ -217,6 +217,7 @@ def _run_multi_workload_sustained(args: argparse.Namespace) -> int: policy_pressure = ( timeline.get("policy_pressure", {}) if isinstance(timeline, dict) else {} ) + risk_rollup = report.get("operation_risk_rollup", {}) review_hints = timeline.get("review_hints", []) if isinstance(timeline, dict) else [] print(f"wrote sustained telemetry: {args.output}") if args.edgeenv_feed_output: @@ -250,6 +251,19 @@ def _run_multi_workload_sustained(args: argparse.Namespace) -> int: f"fallback={_format_cli_list(policy_pressure.get('fallback_tasks'))} " f"markers={_format_cli_list(policy_pressure.get('pressure_markers'))}" ) + if isinstance(risk_rollup, dict) and risk_rollup: + affected = risk_rollup.get("affected_tasks", {}) + if not isinstance(affected, dict): + affected = {} + print( + "operation-risk: " + f"level={risk_rollup.get('risk_level', 'unknown')} " + f"first_read={risk_rollup.get('first_read', 'unknown')} " + f"reasons={_format_cli_list(risk_rollup.get('primary_reasons'))} " + f"scheduler_delay={_format_cli_list(affected.get('scheduler_delay'))} " + f"fallback={_format_cli_list(affected.get('fallback'))} " + f"degraded={_format_cli_list(affected.get('degraded'))}" + ) return 0 diff --git a/tests/test_multi_workload_sustained.py b/tests/test_multi_workload_sustained.py index 3ba2fbe..93b9ae5 100644 --- a/tests/test_multi_workload_sustained.py +++ b/tests/test_multi_workload_sustained.py @@ -815,6 +815,9 @@ def test_cli_run_multi_workload_sustained_writes_edgeenv_feed_output( assert "limited=" in captured.out assert "protected=" in captured.out assert "markers=" in captured.out + assert "operation-risk: level=review" in captured.out + assert "first_read=review_operation_risk_context" in captured.out + assert "reasons=queue_pressure_overloaded" in captured.out report = json.loads(output.read_text(encoding="utf-8")) feed = json.loads(feed_output.read_text(encoding="utf-8")) assert feed == report["edgeenv_runtime_telemetry_feed"] @@ -1303,6 +1306,8 @@ def test_cli_device_local_overrides_write_edgeenv_feed_output( assert "stale_drop=" in captured.out assert "stale_drop_tasks=" in captured.out assert "max_queue_wait_ms=" in captured.out + assert "operation-risk: level=review" in captured.out + assert "first_read=review_operation_risk_context" in captured.out report = json.loads(output.read_text(encoding="utf-8")) feed = json.loads(feed_output.read_text(encoding="utf-8")) assert feed == report["edgeenv_runtime_telemetry_feed"]