From ffd5ad1f28bea5701735ff88b275931cf419691e Mon Sep 17 00:00:00 2001 From: BaiyuScope3 Date: Thu, 15 Jan 2026 14:01:33 -0500 Subject: [PATCH 1/6] feat: add click_tracker asset to clickable formats Added create_click_tracker_asset() helper function for 3rd party click tracking redirect URLs. Added click_tracker to 9 clickable formats: - display_image (responsive) - display_300x250_image - display_728x90_image - display_320x50_image - display_160x600_image - display_336x280_image - display_300x600_image - display_970x250_image - native_content Click tracker is optional (required=False) and uses url_type='tracker_redirect' to distinguish from impression trackers. --- src/creative_agent/data/standard_formats.py | 26 +++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/creative_agent/data/standard_formats.py b/src/creative_agent/data/standard_formats.py index 476a638..4ddbe73 100644 --- a/src/creative_agent/data/standard_formats.py +++ b/src/creative_agent/data/standard_formats.py @@ -83,6 +83,23 @@ def create_impression_tracker_asset() -> LibAssets: ) +def create_click_tracker_asset() -> LibAssets: + """Create an optional click tracker asset for 3rd party tracking. + + This creates a URL asset with url_type='tracker_redirect' that can be used + for third-party click tracking redirects. + """ + return create_asset( + asset_id="click_tracker", + asset_type=AssetType.url, + required=False, + requirements={ + "url_type": "tracker_redirect", + "description": "3rd party click tracking redirect URL", + }, + ) + + def create_fixed_render(width: int, height: int, role: str = "primary") -> LibRender: """Create a render with fixed dimensions (non-responsive). @@ -605,6 +622,7 @@ def create_responsive_render( }, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), # Concrete formats for backward compatibility @@ -636,6 +654,7 @@ def create_responsive_render( }, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), CreativeFormat( @@ -663,6 +682,7 @@ def create_responsive_render( required=True, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), CreativeFormat( @@ -690,6 +710,7 @@ def create_responsive_render( required=True, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), CreativeFormat( @@ -717,6 +738,7 @@ def create_responsive_render( required=True, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), CreativeFormat( @@ -744,6 +766,7 @@ def create_responsive_render( required=True, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), CreativeFormat( @@ -771,6 +794,7 @@ def create_responsive_render( required=True, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), CreativeFormat( @@ -798,6 +822,7 @@ def create_responsive_render( required=True, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), ] @@ -1093,6 +1118,7 @@ def create_responsive_render( }, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), ] From e378c9b59f3d22125dfa91f6435c69030c4b0bb4 Mon Sep 17 00:00:00 2001 From: BaiyuScope3 Date: Thu, 15 Jan 2026 14:18:17 -0500 Subject: [PATCH 2/6] test: add unit tests for click_tracker asset - Test click_tracker asset properties (id, type, required, url_type) - Test click_tracker is only on clickable formats (9 total) - Test click_tracker is NOT on audio/video/dooh formats --- tests/unit/test_click_tracker.py | 95 ++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 tests/unit/test_click_tracker.py diff --git a/tests/unit/test_click_tracker.py b/tests/unit/test_click_tracker.py new file mode 100644 index 0000000..ef9c3dd --- /dev/null +++ b/tests/unit/test_click_tracker.py @@ -0,0 +1,95 @@ +"""Unit tests for click_tracker asset functionality.""" + +from creative_agent.data.standard_formats import ( + STANDARD_FORMATS, + create_click_tracker_asset, +) + + +class TestClickTrackerAsset: + """Tests for the click_tracker asset helper function.""" + + def test_click_tracker_asset_id(self): + """Test click_tracker has correct asset_id.""" + tracker = create_click_tracker_asset() + assert tracker.asset_id == "click_tracker" + + def test_click_tracker_asset_type(self): + """Test click_tracker is a URL type asset.""" + tracker = create_click_tracker_asset() + assert tracker.asset_type.value == "url" + + def test_click_tracker_is_optional(self): + """Test click_tracker is not required.""" + tracker = create_click_tracker_asset() + assert tracker.required is False + + def test_click_tracker_url_type(self): + """Test click_tracker uses tracker_redirect url_type.""" + tracker = create_click_tracker_asset() + assert tracker.requirements["url_type"] == "tracker_redirect" + + def test_click_tracker_has_description(self): + """Test click_tracker has a description in requirements.""" + tracker = create_click_tracker_asset() + assert "description" in tracker.requirements + assert "click" in tracker.requirements["description"].lower() + + +class TestClickTrackerFormatCoverage: + """Tests for click_tracker coverage across formats.""" + + EXPECTED_FORMATS_WITH_CLICK_TRACKER = [ + "display_image", + "display_300x250_image", + "display_728x90_image", + "display_320x50_image", + "display_160x600_image", + "display_336x280_image", + "display_300x600_image", + "display_970x250_image", + "native_content", + ] + + def test_click_tracker_format_count(self): + """Verify exactly 9 formats have click_tracker.""" + count = sum( + 1 + for fmt in STANDARD_FORMATS + if "click_tracker" in [a.asset_id for a in (fmt.assets or [])] + ) + assert count == 9 + + def test_click_tracker_on_expected_formats(self): + """Verify click_tracker is on all expected formats.""" + for fmt in STANDARD_FORMATS: + asset_ids = [a.asset_id for a in (fmt.assets or [])] + if fmt.format_id.id in self.EXPECTED_FORMATS_WITH_CLICK_TRACKER: + assert "click_tracker" in asset_ids, ( + f"{fmt.format_id.id} should have click_tracker" + ) + + def test_click_tracker_only_on_clickable_formats(self): + """Verify click_tracker is only on formats with click_url or landing_url.""" + for fmt in STANDARD_FORMATS: + asset_ids = [a.asset_id for a in (fmt.assets or [])] + if "click_tracker" in asset_ids: + has_click_url = "click_url" in asset_ids or "landing_url" in asset_ids + assert has_click_url, ( + f"{fmt.format_id.id} has click_tracker but no click_url/landing_url" + ) + + def test_click_tracker_not_on_non_clickable_formats(self): + """Verify click_tracker is NOT on formats without click functionality.""" + non_clickable_types = ["audio", "dooh", "video"] + for fmt in STANDARD_FORMATS: + fmt_type = str(fmt.type).lower() if fmt.type else "" + asset_ids = [a.asset_id for a in (fmt.assets or [])] + + # Skip if not a non-clickable type + if not any(t in fmt_type for t in non_clickable_types): + continue + + assert "click_tracker" not in asset_ids, ( + f"{fmt.format_id.id} ({fmt_type}) should not have click_tracker" + ) From 5eb4c650976a4bbbd1fc837ee127fc2d2ad8dd13 Mon Sep 17 00:00:00 2001 From: BaiyuScope3 Date: Thu, 15 Jan 2026 14:20:53 -0500 Subject: [PATCH 3/6] feat: extend click_tracker to HTML, JS, and VAST formats Added click_tracker to 10 additional formats: - display_html (+ 7 sized variants) - display_js - video_vast - video_vast_30s Total formats with click_tracker: 19 Updated tests to reflect new coverage. --- src/creative_agent/data/standard_formats.py | 10 +++++++ tests/unit/test_click_tracker.py | 32 +++++++++++++++------ 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/creative_agent/data/standard_formats.py b/src/creative_agent/data/standard_formats.py index 4ddbe73..3a15726 100644 --- a/src/creative_agent/data/standard_formats.py +++ b/src/creative_agent/data/standard_formats.py @@ -403,6 +403,7 @@ def create_responsive_render( asset_type=AssetType.vast, required=True, ), + create_click_tracker_asset(), ], ), # Concrete formats for backward compatibility @@ -461,6 +462,7 @@ def create_responsive_render( "description": "VAST 4.x compatible tag", }, ), + create_click_tracker_asset(), ], ), CreativeFormat( @@ -848,6 +850,7 @@ def create_responsive_render( }, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), # Concrete formats for backward compatibility @@ -871,6 +874,7 @@ def create_responsive_render( }, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), CreativeFormat( @@ -892,6 +896,7 @@ def create_responsive_render( }, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), CreativeFormat( @@ -913,6 +918,7 @@ def create_responsive_render( }, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), CreativeFormat( @@ -934,6 +940,7 @@ def create_responsive_render( }, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), CreativeFormat( @@ -955,6 +962,7 @@ def create_responsive_render( }, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), CreativeFormat( @@ -976,6 +984,7 @@ def create_responsive_render( }, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), ] @@ -998,6 +1007,7 @@ def create_responsive_render( required=True, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), ] diff --git a/tests/unit/test_click_tracker.py b/tests/unit/test_click_tracker.py index ef9c3dd..6e379b0 100644 --- a/tests/unit/test_click_tracker.py +++ b/tests/unit/test_click_tracker.py @@ -40,6 +40,7 @@ class TestClickTrackerFormatCoverage: """Tests for click_tracker coverage across formats.""" EXPECTED_FORMATS_WITH_CLICK_TRACKER = [ + # Image formats "display_image", "display_300x250_image", "display_728x90_image", @@ -48,17 +49,31 @@ class TestClickTrackerFormatCoverage: "display_336x280_image", "display_300x600_image", "display_970x250_image", + # HTML formats + "display_html", + "display_300x250_html", + "display_728x90_html", + "display_160x600_html", + "display_336x280_html", + "display_300x600_html", + "display_970x250_html", + # JS format + "display_js", + # VAST formats + "video_vast", + "video_vast_30s", + # Native "native_content", ] def test_click_tracker_format_count(self): - """Verify exactly 9 formats have click_tracker.""" + """Verify exactly 19 formats have click_tracker.""" count = sum( 1 for fmt in STANDARD_FORMATS if "click_tracker" in [a.asset_id for a in (fmt.assets or [])] ) - assert count == 9 + assert count == 19 def test_click_tracker_on_expected_formats(self): """Verify click_tracker is on all expected formats.""" @@ -69,19 +84,20 @@ def test_click_tracker_on_expected_formats(self): f"{fmt.format_id.id} should have click_tracker" ) - def test_click_tracker_only_on_clickable_formats(self): - """Verify click_tracker is only on formats with click_url or landing_url.""" + def test_click_tracker_only_on_expected_formats(self): + """Verify click_tracker is only on formats in the expected list.""" for fmt in STANDARD_FORMATS: asset_ids = [a.asset_id for a in (fmt.assets or [])] if "click_tracker" in asset_ids: - has_click_url = "click_url" in asset_ids or "landing_url" in asset_ids - assert has_click_url, ( - f"{fmt.format_id.id} has click_tracker but no click_url/landing_url" + assert fmt.format_id.id in self.EXPECTED_FORMATS_WITH_CLICK_TRACKER, ( + f"{fmt.format_id.id} has click_tracker but is not in expected list" ) def test_click_tracker_not_on_non_clickable_formats(self): """Verify click_tracker is NOT on formats without click functionality.""" - non_clickable_types = ["audio", "dooh", "video"] + # Audio and DOOH don't support click tracking + # VAST video formats DO support click tracking (external to VAST tag) + non_clickable_types = ["audio", "dooh"] for fmt in STANDARD_FORMATS: fmt_type = str(fmt.type).lower() if fmt.type else "" asset_ids = [a.asset_id for a in (fmt.assets or [])] From 647d9f3033a3b08ef5616966f016f4dbcc436ba1 Mon Sep 17 00:00:00 2001 From: BaiyuScope3 Date: Thu, 15 Jan 2026 14:22:27 -0500 Subject: [PATCH 4/6] fix: move expected formats to module-level constant Fixes RUF012 linter warning about mutable class attributes. --- tests/unit/test_click_tracker.py | 59 ++++++++++++++++---------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/tests/unit/test_click_tracker.py b/tests/unit/test_click_tracker.py index 6e379b0..3e158d6 100644 --- a/tests/unit/test_click_tracker.py +++ b/tests/unit/test_click_tracker.py @@ -5,6 +5,34 @@ create_click_tracker_asset, ) +# Expected formats that should have click_tracker +EXPECTED_FORMATS_WITH_CLICK_TRACKER = [ + # Image formats + "display_image", + "display_300x250_image", + "display_728x90_image", + "display_320x50_image", + "display_160x600_image", + "display_336x280_image", + "display_300x600_image", + "display_970x250_image", + # HTML formats + "display_html", + "display_300x250_html", + "display_728x90_html", + "display_160x600_html", + "display_336x280_html", + "display_300x600_html", + "display_970x250_html", + # JS format + "display_js", + # VAST formats + "video_vast", + "video_vast_30s", + # Native + "native_content", +] + class TestClickTrackerAsset: """Tests for the click_tracker asset helper function.""" @@ -39,33 +67,6 @@ def test_click_tracker_has_description(self): class TestClickTrackerFormatCoverage: """Tests for click_tracker coverage across formats.""" - EXPECTED_FORMATS_WITH_CLICK_TRACKER = [ - # Image formats - "display_image", - "display_300x250_image", - "display_728x90_image", - "display_320x50_image", - "display_160x600_image", - "display_336x280_image", - "display_300x600_image", - "display_970x250_image", - # HTML formats - "display_html", - "display_300x250_html", - "display_728x90_html", - "display_160x600_html", - "display_336x280_html", - "display_300x600_html", - "display_970x250_html", - # JS format - "display_js", - # VAST formats - "video_vast", - "video_vast_30s", - # Native - "native_content", - ] - def test_click_tracker_format_count(self): """Verify exactly 19 formats have click_tracker.""" count = sum( @@ -79,7 +80,7 @@ def test_click_tracker_on_expected_formats(self): """Verify click_tracker is on all expected formats.""" for fmt in STANDARD_FORMATS: asset_ids = [a.asset_id for a in (fmt.assets or [])] - if fmt.format_id.id in self.EXPECTED_FORMATS_WITH_CLICK_TRACKER: + if fmt.format_id.id in EXPECTED_FORMATS_WITH_CLICK_TRACKER: assert "click_tracker" in asset_ids, ( f"{fmt.format_id.id} should have click_tracker" ) @@ -89,7 +90,7 @@ def test_click_tracker_only_on_expected_formats(self): for fmt in STANDARD_FORMATS: asset_ids = [a.asset_id for a in (fmt.assets or [])] if "click_tracker" in asset_ids: - assert fmt.format_id.id in self.EXPECTED_FORMATS_WITH_CLICK_TRACKER, ( + assert fmt.format_id.id in EXPECTED_FORMATS_WITH_CLICK_TRACKER, ( f"{fmt.format_id.id} has click_tracker but is not in expected list" ) From c136e8fc3d43e9f75fbbb402951a7a33e4a714a5 Mon Sep 17 00:00:00 2001 From: BaiyuScope3 Date: Thu, 15 Jan 2026 14:24:09 -0500 Subject: [PATCH 5/6] style: apply ruff format to test file --- tests/unit/test_click_tracker.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/tests/unit/test_click_tracker.py b/tests/unit/test_click_tracker.py index 3e158d6..0f6a19d 100644 --- a/tests/unit/test_click_tracker.py +++ b/tests/unit/test_click_tracker.py @@ -69,11 +69,7 @@ class TestClickTrackerFormatCoverage: def test_click_tracker_format_count(self): """Verify exactly 19 formats have click_tracker.""" - count = sum( - 1 - for fmt in STANDARD_FORMATS - if "click_tracker" in [a.asset_id for a in (fmt.assets or [])] - ) + count = sum(1 for fmt in STANDARD_FORMATS if "click_tracker" in [a.asset_id for a in (fmt.assets or [])]) assert count == 19 def test_click_tracker_on_expected_formats(self): @@ -81,9 +77,7 @@ def test_click_tracker_on_expected_formats(self): for fmt in STANDARD_FORMATS: asset_ids = [a.asset_id for a in (fmt.assets or [])] if fmt.format_id.id in EXPECTED_FORMATS_WITH_CLICK_TRACKER: - assert "click_tracker" in asset_ids, ( - f"{fmt.format_id.id} should have click_tracker" - ) + assert "click_tracker" in asset_ids, f"{fmt.format_id.id} should have click_tracker" def test_click_tracker_only_on_expected_formats(self): """Verify click_tracker is only on formats in the expected list.""" @@ -107,6 +101,4 @@ def test_click_tracker_not_on_non_clickable_formats(self): if not any(t in fmt_type for t in non_clickable_types): continue - assert "click_tracker" not in asset_ids, ( - f"{fmt.format_id.id} ({fmt_type}) should not have click_tracker" - ) + assert "click_tracker" not in asset_ids, f"{fmt.format_id.id} ({fmt_type}) should not have click_tracker" From f19b106536cabe834e3089913771326406152ad7 Mon Sep 17 00:00:00 2001 From: BaiyuScope3 Date: Thu, 15 Jan 2026 15:12:32 -0500 Subject: [PATCH 6/6] feat: add click_tracker to AI generative formats Added click_tracker to 8 generative formats: - display_generative (+ 7 sized variants) Total formats with click_tracker: 27 --- src/creative_agent/data/standard_formats.py | 8 ++++++++ tests/unit/test_click_tracker.py | 13 +++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/creative_agent/data/standard_formats.py b/src/creative_agent/data/standard_formats.py index 3a15726..aa74610 100644 --- a/src/creative_agent/data/standard_formats.py +++ b/src/creative_agent/data/standard_formats.py @@ -173,6 +173,7 @@ def create_responsive_render( requirements={"description": "Text prompt describing the desired creative"}, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), # Concrete formats for backward compatibility @@ -198,6 +199,7 @@ def create_responsive_render( requirements={"description": "Text prompt describing the desired creative"}, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), CreativeFormat( @@ -222,6 +224,7 @@ def create_responsive_render( requirements={"description": "Text prompt describing the desired creative"}, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), CreativeFormat( @@ -246,6 +249,7 @@ def create_responsive_render( requirements={"description": "Text prompt describing the desired creative"}, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), CreativeFormat( @@ -270,6 +274,7 @@ def create_responsive_render( requirements={"description": "Text prompt describing the desired creative"}, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), CreativeFormat( @@ -294,6 +299,7 @@ def create_responsive_render( requirements={"description": "Text prompt describing the desired creative"}, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), CreativeFormat( @@ -318,6 +324,7 @@ def create_responsive_render( requirements={"description": "Text prompt describing the desired creative"}, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), CreativeFormat( @@ -342,6 +349,7 @@ def create_responsive_render( requirements={"description": "Text prompt describing the desired creative"}, ), create_impression_tracker_asset(), + create_click_tracker_asset(), ], ), ] diff --git a/tests/unit/test_click_tracker.py b/tests/unit/test_click_tracker.py index 0f6a19d..daaa5f1 100644 --- a/tests/unit/test_click_tracker.py +++ b/tests/unit/test_click_tracker.py @@ -7,6 +7,15 @@ # Expected formats that should have click_tracker EXPECTED_FORMATS_WITH_CLICK_TRACKER = [ + # Generative formats + "display_generative", + "display_300x250_generative", + "display_728x90_generative", + "display_320x50_generative", + "display_160x600_generative", + "display_336x280_generative", + "display_300x600_generative", + "display_970x250_generative", # Image formats "display_image", "display_300x250_image", @@ -68,9 +77,9 @@ class TestClickTrackerFormatCoverage: """Tests for click_tracker coverage across formats.""" def test_click_tracker_format_count(self): - """Verify exactly 19 formats have click_tracker.""" + """Verify exactly 27 formats have click_tracker.""" count = sum(1 for fmt in STANDARD_FORMATS if "click_tracker" in [a.asset_id for a in (fmt.assets or [])]) - assert count == 19 + assert count == 27 def test_click_tracker_on_expected_formats(self): """Verify click_tracker is on all expected formats."""