From 842d313a88e5f4f2ffb8299c33d0d5ce78b65aa7 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Wed, 21 Oct 2026 05:13:59 +0200 Subject: [PATCH] fix: keep truth model notes out of the native rows check_freshness --only native rebuilds the truth model to compare it, and the hash conflict notes generate_truth reports opened the freshness output. They are dropped there, and any other stderr line still passes through. --- scripts/check_freshness.py | 54 ++++++++++++++++++++++++----------- tests/test_check_freshness.py | 19 ++++++++++++ 2 files changed, 57 insertions(+), 16 deletions(-) diff --git a/scripts/check_freshness.py b/scripts/check_freshness.py index 1037b55f..7dba5c5c 100644 --- a/scripts/check_freshness.py +++ b/scripts/check_freshness.py @@ -472,6 +472,27 @@ def _transcribed_at(platforms_dir: Path, platform: str) -> float: return newest +# How the truth model settles two cores' hashes: generate_truth reports it, +# and it says nothing about whether a cached original is current. +_MODEL_NOTES = ("WARNING: hash conflict",) + + +@contextlib.contextmanager +def _without_model_notes(): + """Keep the model build's own notes out of the freshness report. + + Anything else written to stderr passes through. + """ + sink = io.StringIO() + try: + with contextlib.redirect_stderr(sink): + yield + finally: + for line in sink.getvalue().splitlines(keepends=True): + if not line.startswith(_MODEL_NOTES): + sys.stderr.write(line) + + def check_native( platforms_dir: Path, cache_dir: Path, truth_dir: Path, published: Path = Path("exports"), @@ -484,24 +505,25 @@ def check_native( exporter_class = exporters.get(name) if not exporter_class: continue - try: - truth, scraped = export_native.load_inputs(name, truth_dir, str(platforms_dir)) - except export_native.StaleTruth as exc: - findings.append(Finding("native", name, STALE, detail=str(exc))) - continue - systems, _ = build_native_model(truth or {}, scraped) - wanted = export_native.wanted_sources(exporter_class(), systems, scraped) - reason = native_cache_state( - wanted, cache_dir / name, recorded, index, _transcribed_at(platforms_dir, name) - ) - if reason: - reason += ", export_native.py --refresh-cache fetches it" - else: - reason = published_export_state( - name, exporter_class, truth_dir, platforms_dir, cache_dir, published + with _without_model_notes(): + try: + truth, scraped = export_native.load_inputs(name, truth_dir, str(platforms_dir)) + except export_native.StaleTruth as exc: + findings.append(Finding("native", name, STALE, detail=str(exc))) + continue + systems, _ = build_native_model(truth or {}, scraped) + wanted = export_native.wanted_sources(exporter_class(), systems, scraped) + reason = native_cache_state( + wanted, cache_dir / name, recorded, index, _transcribed_at(platforms_dir, name) ) if reason: - reason += f", export_native.py --platform {name} writes it again" + reason += ", export_native.py --refresh-cache fetches it" + else: + reason = published_export_state( + name, exporter_class, truth_dir, platforms_dir, cache_dir, published + ) + if reason: + reason += f", export_native.py --platform {name} writes it again" findings.append( Finding( "native", diff --git a/tests/test_check_freshness.py b/tests/test_check_freshness.py index 12a96beb..a0c36df1 100644 --- a/tests/test_check_freshness.py +++ b/tests/test_check_freshness.py @@ -87,6 +87,25 @@ class NativeCacheTests(unittest.TestCase): self.assertEqual({r.status for r in rows}, {cf.STALE}) self.assertIn("batocera", {r.subject for r in rows}) + def test_the_model_build_notes_stay_out_of_the_report(self): + """generate_truth reports how two cores' hashes were settled. Under + `--only native` they opened the report and named no step to take.""" + import contextlib + import io + + def noisy(truth, scraped): + print("WARNING: hash conflict for GameIndex.yaml (sha1: a vs b, core yaps2)", + file=sys.stderr) + print("other diagnostic", file=sys.stderr) + return {}, None + + err = io.StringIO() + with mock.patch.object(cf, "build_native_model", side_effect=noisy), \ + contextlib.redirect_stderr(err): + cf.check_native(REPO_ROOT / "platforms", self.cache, self.cache / "truth") + self.assertNotIn("hash conflict", err.getvalue()) + self.assertIn("other diagnostic", err.getvalue()) + class PublishedExportTests(unittest.TestCase): """exports/ is committed and published, and CI cannot rebuild it."""