From a05907b76d69204d3c374a170911382fe77e442f Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Mon, 11 May 2026 09:18:09 -0500 Subject: [PATCH] fix(insights): add logging to diagnose why AI network observations never persist The parse function silently returned {:ok, []} on any decode failure or observation rejection. Log warnings for both cases so we can see what the LLM is actually returning. --- lib/towerops/llm/network_insight_prompt.ex | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/towerops/llm/network_insight_prompt.ex b/lib/towerops/llm/network_insight_prompt.ex index 40b67711..3cde1c31 100644 --- a/lib/towerops/llm/network_insight_prompt.ex +++ b/lib/towerops/llm/network_insight_prompt.ex @@ -10,6 +10,8 @@ defmodule Towerops.LLM.NetworkInsightPrompt do comments on findings the rule-based workers already produced. """ + require Logger + @valid_urgencies ~w(critical warning info) @system """ @@ -71,12 +73,21 @@ defmodule Towerops.LLM.NetworkInsightPrompt do observations = case decode(cleaned) do {:ok, %{"observations" => list}} when is_list(list) -> - list - |> Enum.map(&normalize_observation/1) - |> Enum.reject(&is_nil/1) - |> Enum.take(@max_observations) + raw_count = length(list) + normalized = list |> Enum.map(&normalize_observation/1) |> Enum.reject(&is_nil/1) + rejected = raw_count - length(normalized) + + if rejected > 0 do + Logger.warning("AI network insight: #{rejected}/#{raw_count} observations rejected by normalize_observation") + end + + Enum.take(normalized, @max_observations) _ -> + Logger.warning( + "AI network insight: could not decode LLM response, content preview: #{String.slice(cleaned, 0, 200)}" + ) + [] end