From af5101e9e49ea4462ada262f949dcda6b4a95eae Mon Sep 17 00:00:00 2001 From: jedarden Date: Sat, 25 Apr 2026 12:11:12 -0400 Subject: [PATCH] feat(feedback): enhance false positive explanations with diagnostic context When users mark detections as incorrect, the system now provides: - Contributing link name (MAC prefix) - DeltaRMS value and threshold ratio - Root cause from diagnostic checks - Note about applying corrections Co-Authored-By: Claude Opus 4.7 --- dashboard/js/proactive.js | 6 ++--- mothership/internal/api/feedback.go | 37 +++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/dashboard/js/proactive.js b/dashboard/js/proactive.js index 43afe42..8e67ec1 100644 --- a/dashboard/js/proactive.js +++ b/dashboard/js/proactive.js @@ -1193,7 +1193,7 @@ const explanation = eventData.explainability; const contributingLinks = explanation.contributing_links || []; - const allLinks = explanation.all_links || []; + const diagnosis = explanation.diagnosis || null; // Find the primary contributing link const primaryLink = contributingLinks.length > 0 ? contributingLinks[0] : null; @@ -1209,13 +1209,13 @@ explanationText = `The system detected motion here because: ${linkName}'s signal (deltaRMS: ${deltaRMS}) exceeded the motion threshold by ${ratio}x.`; // Add root cause from diagnostic if available - if (primaryLink.diagnosis) { - const diagnosis = primaryLink.diagnosis; + if (diagnosis) { explanationText += `

Possible cause: ${diagnosis.detail}`; if (diagnosis.advice) { explanationText += `
What to do: ${diagnosis.advice}`; } + explanationText += `

We've noted this and will apply corrections.`; } else { explanationText += `

Possible cause: Ambient RF interference or environmental changes. We've noted this and will apply corrections.`; } diff --git a/mothership/internal/api/feedback.go b/mothership/internal/api/feedback.go index 489303a..1e6cab0 100644 --- a/mothership/internal/api/feedback.go +++ b/mothership/internal/api/feedback.go @@ -3,6 +3,7 @@ package api import ( "encoding/json" + "fmt" "log" "net/http" "strconv" @@ -174,7 +175,21 @@ func (h *FeedbackHandler) handleSubmitFeedback(w http.ResponseWriter, r *http.Re // We'll use the blob ID to get the explanation // Get explanation from the handler directly if exp := h.getExplainabilityForBlob(req.BlobID, timestamp); exp != nil { - // Build explainability response + // Build contributing links data with detailed information + contributingLinksData := make([]map[string]interface{}, 0, len(exp.ContributingLinks)) + for _, link := range exp.ContributingLinks { + linkData := map[string]interface{}{ + "link_id": link.LinkID, + "node_mac": link.NodeMAC, + "peer_mac": link.PeerMAC, + "delta_rms": link.DeltaRMS, + "zone_number": link.ZoneNumber, + "weight": link.Weight, + "contributing": link.Contributing, + } + contributingLinksData = append(contributingLinksData, linkData) + } + explainabilityData := map[string]interface{}{ "blob_id": exp.BlobID, "x": exp.X, @@ -182,8 +197,7 @@ func (h *FeedbackHandler) handleSubmitFeedback(w http.ResponseWriter, r *http.Re "z": exp.Z, "confidence": exp.Confidence, "timestamp_ms": exp.Timestamp, - "contributing_links": exp.ContributingLinks, - "all_links": exp.AllLinks, + "contributing_links": contributingLinksData, } // Add diagnostic info for primary contributing link @@ -206,7 +220,22 @@ func (h *FeedbackHandler) handleSubmitFeedback(w http.ResponseWriter, r *http.Re // Update the inline response message with diagnostic context if diagnosis.RuleID != "no_issue_detected" && diagnosis.RuleID != "insufficient_data" { - inlineResp["message"] = diagnosis.Detail + " " + diagnosis.Advice + // Build a more detailed explanation message + linkName := linkID + if len(primaryLink.NodeMAC) >= 8 { + linkName = primaryLink.NodeMAC[:8] + } + deltaRMS := primaryLink.DeltaRMS + threshold := 0.02 + ratio := "1.0" + if threshold > 0 { + ratio = fmt.Sprintf("%.1f", deltaRMS/threshold) + } + + explanationMsg := fmt.Sprintf("The system detected motion here because: %s's signal (deltaRMS: %.4f) exceeded the motion threshold by %sx. ", + linkName, deltaRMS, ratio) + explanationMsg += diagnosis.Detail + " " + diagnosis.Advice + " We've noted this and will apply corrections." + inlineResp["message"] = explanationMsg } } }