@@ -59,6 +59,46 @@ def load_report(path: str | Path) -> dict[str, Any]:
5959 return json .load (handle )
6060
6161
62+ def report_content_fingerprint (report : dict [str , Any ]) -> str :
63+ ignored_top_level_keys = {"as_of" , "generated_at" , "source_artifacts" }
64+ normalized = {key : value for key , value in report .items () if key not in ignored_top_level_keys }
65+ return json .dumps (normalized , ensure_ascii = False , sort_keys = True , separators = ("," , ":" ))
66+
67+
68+ def report_as_of_date (report : dict [str , Any ]) -> dt .date | None :
69+ try :
70+ return dt .date .fromisoformat (str (report .get ("as_of" , "" )))
71+ except ValueError :
72+ return None
73+
74+
75+ def is_same_period_duplicate (report : dict [str , Any ], previous_report : dict [str , Any ]) -> bool :
76+ if str (report .get ("cadence" , "" )) != str (previous_report .get ("cadence" , "" )):
77+ return False
78+ as_of = report_as_of_date (report )
79+ previous_as_of = report_as_of_date (previous_report )
80+ if as_of is None or previous_as_of is None :
81+ return True
82+ if str (report .get ("cadence" , "" )) == "weekly" :
83+ return abs ((as_of - previous_as_of ).days ) < 7
84+ return as_of == previous_as_of
85+
86+
87+ def unique_report_paths_by_content (report_paths : list [str | Path ]) -> list [Path ]:
88+ unique_paths : list [Path ] = []
89+ seen_reports_by_fingerprint : dict [str , list [dict [str , Any ]]] = {}
90+ for report_path in report_paths :
91+ path = Path (report_path )
92+ report = load_report (path )
93+ fingerprint = report_content_fingerprint (report )
94+ previous_reports = seen_reports_by_fingerprint .setdefault (fingerprint , [])
95+ if any (is_same_period_duplicate (report , previous ) for previous in previous_reports ):
96+ continue
97+ previous_reports .append (report )
98+ unique_paths .append (path )
99+ return unique_paths
100+
101+
62102def format_datetime (value : str ) -> str :
63103 normalized = value [:- 1 ] + "+00:00" if value .endswith ("Z" ) else value
64104 parsed = dt .datetime .fromisoformat (normalized )
@@ -1191,6 +1231,7 @@ def render_feed_xml(reports: list[dict[str, Any]], *, site_url: str, feed_title:
11911231def publish_reports (report_paths : list [str | Path ], output_dir : str | Path , * , site_url : str , feed_title : str ) -> list [Path ]:
11921232 output = Path (output_dir )
11931233 output .mkdir (parents = True , exist_ok = True )
1234+ report_paths = unique_report_paths_by_content (report_paths )
11941235 reports = [load_report (path ) for path in report_paths ]
11951236 written : list [Path ] = []
11961237 for report in reports :
0 commit comments