From f9f75f44eaa9680308102b247e2e4c8fdbc9d54b Mon Sep 17 00:00:00 2001 From: Shruti Patel Date: Sun, 15 Mar 2026 20:50:32 -0700 Subject: [PATCH] Include INFO status healthcheck cards in overview to save to db (#5022) Summary: In order for the INFO healthcheck cards to be shown in the Ax UI, they need to be saved to the db. This diff adds those cards to overview cards so they can be saved appropriately. Reviewed By: bernardbeckerman Differential Revision: D96492464 --- .../healthcheck/healthcheck_analysis.py | 13 +++++++++ .../tests/test_healthcheck_analysis.py | 29 +++++++++++++++++++ ax/analysis/overview.py | 9 +++--- 3 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 ax/analysis/healthcheck/tests/test_healthcheck_analysis.py diff --git a/ax/analysis/healthcheck/healthcheck_analysis.py b/ax/analysis/healthcheck/healthcheck_analysis.py index 1f9589fd3b7..8f220c38396 100644 --- a/ax/analysis/healthcheck/healthcheck_analysis.py +++ b/ax/analysis/healthcheck/healthcheck_analysis.py @@ -26,6 +26,19 @@ def get_status(self) -> HealthcheckStatus: def is_passing(self) -> bool: return self.get_status() in (HealthcheckStatus.PASS, HealthcheckStatus.INFO) + def is_user_facing(self) -> bool: + """Returns True if this card should be displayed to users. + + User-facing cards: + - FAIL: Critical issues blocking the experiment + - WARNING: Potential issues that can lead to issues in the future + - INFO: Informational context and feature upsells + + Hidden cards: + - PASS: No issues, nothing noteworthy to display + """ + return self.get_status() != HealthcheckStatus.PASS + def get_aditional_attrs(self) -> dict[str, str | int | float | bool]: return json.loads(self.blob) diff --git a/ax/analysis/healthcheck/tests/test_healthcheck_analysis.py b/ax/analysis/healthcheck/tests/test_healthcheck_analysis.py new file mode 100644 index 00000000000..632676643b0 --- /dev/null +++ b/ax/analysis/healthcheck/tests/test_healthcheck_analysis.py @@ -0,0 +1,29 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# pyre-strict + +import pandas as pd +from ax.analysis.healthcheck.healthcheck_analysis import ( + create_healthcheck_analysis_card, + HealthcheckStatus, +) +from ax.utils.common.testutils import TestCase + + +class TestHealthcheckAnalysisCard(TestCase): + def test_is_user_facing(self) -> None: + # Only PASS status should be hidden; all others are user-facing + for status in HealthcheckStatus: + with self.subTest(status=status.name): + card = create_healthcheck_analysis_card( + name="TestAnalysis", + title="Test Healthcheck", + subtitle="Test subtitle", + df=pd.DataFrame(), + status=status, + ) + expected = status != HealthcheckStatus.PASS + self.assertEqual(card.is_user_facing(), expected) diff --git a/ax/analysis/overview.py b/ax/analysis/overview.py index 67b18689e69..53b27427167 100644 --- a/ax/analysis/overview.py +++ b/ax/analysis/overview.py @@ -265,10 +265,11 @@ def compute( if analyis is not None ] - non_passing_health_checks = [ + user_facing_health_check_cards = [ card for card in health_check_cards - if (isinstance(card, HealthcheckAnalysisCard) and not card.is_passing()) + if isinstance(card, HealthcheckAnalysisCard) + and card.is_user_facing() or isinstance(card, ErrorAnalysisCard) ] @@ -277,9 +278,9 @@ def compute( name="HealthchecksAnalysis", title=HEALTH_CHECK_CARDGROUP_TITLE, subtitle=HEALTH_CHECK_CARDGROUP_SUBTITLE, - children=non_passing_health_checks, + children=user_facing_health_check_cards, ) - if len(non_passing_health_checks) > 0 + if len(user_facing_health_check_cards) > 0 else None )