From 86f944d568e1834ed3693dbc792b9498e0e1934f Mon Sep 17 00:00:00 2001 From: Sait Cakmak Date: Fri, 28 Aug 2026 14:23:17 -0700 Subject: [PATCH] Populate analysis card TTL timestamps Summary: - map the sentinel-backed `analysis_card_v2.ttl_timestamp` column in SQA - copy each group and leaf card creation timestamp into the TTL column - verify persisted TTL timestamps match the existing card timestamp Differential Revision: D117531053 --- ax/storage/sqa_store/encoder.py | 4 ++++ ax/storage/sqa_store/sqa_classes.py | 3 +++ ax/storage/sqa_store/tests/test_sqa_store.py | 6 ++++++ 3 files changed, 13 insertions(+) diff --git a/ax/storage/sqa_store/encoder.py b/ax/storage/sqa_store/encoder.py index 09b7357bd43..5e7b2ea38ae 100644 --- a/ax/storage/sqa_store/encoder.py +++ b/ax/storage/sqa_store/encoder.py @@ -1255,6 +1255,8 @@ def analysis_card_to_sqa( ) -> SQAAnalysisCard: """Convert Ax analysis to SQLAlchemy.""" + ttl_timestamp = int(analysis_card._timestamp.timestamp()) + # pyre-fixme: Expected `Base` for 1st...ot `typing.Type[BaseAnalysis]`. analysis_card_class: SQAAnalysisCard = self.config.class_to_sqa_class[ AnalysisCard @@ -1267,6 +1269,7 @@ def analysis_card_to_sqa( experiment_id=experiment_id, name=analysis_card.name, timestamp=analysis_card._timestamp, + ttl_timestamp=ttl_timestamp, order=order, title=analysis_card.title, subtitle=analysis_card.subtitle, @@ -1307,6 +1310,7 @@ def analysis_card_to_sqa( experiment_id=experiment_id, name=card.name, timestamp=card._timestamp, + ttl_timestamp=ttl_timestamp, order=order, title=card.title, subtitle=card.subtitle, diff --git a/ax/storage/sqa_store/sqa_classes.py b/ax/storage/sqa_store/sqa_classes.py index 1cb3f14cd4e..858070bc5fa 100644 --- a/ax/storage/sqa_store/sqa_classes.py +++ b/ax/storage/sqa_store/sqa_classes.py @@ -470,6 +470,9 @@ class SQAAnalysisCard(Base): ) name: Mapped[str] = Column(String(NAME_OR_TYPE_FIELD_LENGTH), nullable=False) timestamp: Mapped[datetime] = Column(IntTimestamp, nullable=False) + ttl_timestamp: Mapped[int] = Column( + BigInteger, nullable=False, server_default="18446744073709551615" + ) parent_id: Mapped[int | None] = Column( Integer, diff --git a/ax/storage/sqa_store/tests/test_sqa_store.py b/ax/storage/sqa_store/tests/test_sqa_store.py index 216842cc579..86327644703 100644 --- a/ax/storage/sqa_store/tests/test_sqa_store.py +++ b/ax/storage/sqa_store/tests/test_sqa_store.py @@ -128,6 +128,7 @@ ) from ax.storage.sqa_store.sqa_classes import ( SQAAbandonedArm, + SQAAnalysisCard, SQAArm, SQAExperiment, SQAGeneratorRun, @@ -3085,6 +3086,11 @@ def test_analysis_card(self) -> None: big_group, self.experiment, ) + for saved_card in get_session().query(SQAAnalysisCard).all(): + self.assertEqual( + saved_card.ttl_timestamp, + int(saved_card.timestamp.timestamp()), + ) with self.subTest("test_load_analysis_cards"): loaded_analysis_cards = load_analysis_cards_by_experiment_name(