From 9d80b427a326407bc6996e09862423fcac9b1d1c Mon Sep 17 00:00:00 2001
From: szafranski
Date: Tue, 4 Aug 2026 13:11:12 +0200
Subject: [PATCH] fix(diagnose): read cron failures from nested state
---
.../aionui-app/src/commands/cmd_diagnose.rs | 12 ++++--
crates/aionui-app/tests/diagnose_cli_e2e.rs | 41 +++++++++++++++++--
2 files changed, 46 insertions(+), 7 deletions(-)
diff --git a/crates/aionui-app/src/commands/cmd_diagnose.rs b/crates/aionui-app/src/commands/cmd_diagnose.rs
index 8253e5d4d..1cc68d894 100644
--- a/crates/aionui-app/src/commands/cmd_diagnose.rs
+++ b/crates/aionui-app/src/commands/cmd_diagnose.rs
@@ -775,7 +775,9 @@ fn cron_summary(data: &Value) -> Value {
.iter()
.filter(|job| {
matches!(
- job.get("last_status").and_then(Value::as_str),
+ job.get("state")
+ .and_then(|state| state.get("last_status"))
+ .and_then(Value::as_str),
Some("error") | Some("missed")
)
})
@@ -794,7 +796,9 @@ fn cron_overview(data: &Value) -> Value {
.iter()
.filter(|job| {
matches!(
- job.get("last_status").and_then(Value::as_str),
+ job.get("state")
+ .and_then(|state| state.get("last_status"))
+ .and_then(Value::as_str),
Some("error") | Some("missed")
)
})
@@ -802,8 +806,8 @@ fn cron_overview(data: &Value) -> Value {
json!({
"id": job.get("id").cloned().unwrap_or(Value::Null),
"name": job.get("name").cloned().unwrap_or(Value::Null),
- "last_status": job.get("last_status").cloned().unwrap_or(Value::Null),
- "last_error": job.get("last_error").cloned().unwrap_or(Value::Null),
+ "last_status": job.pointer("/state/last_status").cloned().unwrap_or(Value::Null),
+ "last_error": job.pointer("/state/last_error").cloned().unwrap_or(Value::Null),
})
})
.collect();
diff --git a/crates/aionui-app/tests/diagnose_cli_e2e.rs b/crates/aionui-app/tests/diagnose_cli_e2e.rs
index 844c131ca..d20823d79 100644
--- a/crates/aionui-app/tests/diagnose_cli_e2e.rs
+++ b/crates/aionui-app/tests/diagnose_cli_e2e.rs
@@ -160,14 +160,19 @@ async fn fake_cron_jobs() -> axum::Json {
"id": "cron-failing",
"name": "Failing cron",
"enabled": true,
- "last_status": "error",
- "last_error": "boom"
+ "state": {
+ "last_status": "error",
+ "last_error": "boom"
+ }
},
{
"id": "cron-ok",
"name": "OK cron",
"enabled": true,
- "last_status": "success"
+ "state": {
+ "last_status": "success",
+ "last_error": null
+ }
}
]
}))
@@ -407,6 +412,34 @@ async fn diagnose_http_get_rejects_paths_outside_health_and_api() {
));
}
+#[tokio::test]
+async fn diagnose_cron_summary_preserves_nested_job_state_and_failing_jobs() {
+ let capture = Arc::new(Mutex::new(Capture::default()));
+ let (base_url, handle) = spawn_diagnose_probe_server(capture).await;
+
+ let output = diagnose_command()
+ .args(["cron", "summary"])
+ .env("AIONUI_BASE_URL", &base_url)
+ .env("AIONUI_CONVERSATION_ID", "conv-cron")
+ .env("AIONUI_USER_ID", "user-cron")
+ .output()
+ .await
+ .unwrap();
+
+ handle.abort();
+ assert!(
+ output.status.success(),
+ "diagnose cron summary failed\nstdout:\n{}\nstderr:\n{}",
+ String::from_utf8_lossy(&output.stdout),
+ String::from_utf8_lossy(&output.stderr)
+ );
+ let stdout: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
+ assert_eq!(stdout["data"]["total"], 2);
+ assert_eq!(stdout["data"]["failing"][0]["state"]["last_status"], "error");
+ assert_eq!(stdout["data"]["failing"][0]["state"]["last_error"], "boom");
+ assert_eq!(stdout["data"]["all"][1]["state"]["last_status"], "success");
+}
+
#[tokio::test]
async fn diagnose_overview_aggregates_common_failure_signals() {
let capture = Arc::new(Mutex::new(Capture::default()));
@@ -434,6 +467,8 @@ async fn diagnose_overview_aggregates_common_failure_signals() {
assert_eq!(stdout["data"]["providers"]["unhealthy"][0]["model"], "gpt-5");
assert_eq!(stdout["data"]["mcp"]["enabled_but_no_tools"][0]["id"], "mcp-empty");
assert_eq!(stdout["data"]["cron"]["failing"][0]["id"], "cron-failing");
+ assert_eq!(stdout["data"]["cron"]["failing"][0]["last_status"], "error");
+ assert_eq!(stdout["data"]["cron"]["failing"][0]["last_error"], "boom");
assert_eq!(stdout["data"]["running_conversations"][0]["id"], "conv-running");
}