From 885c4c3c0650398135230da36aa55c92736aebc1 Mon Sep 17 00:00:00 2001 From: Abdessamad Derraz <3028866+Abdess@users.noreply.github.com> Date: Mon, 10 Aug 2026 17:22:00 +0200 Subject: [PATCH] refactor: judge a self-checked entry whole --- scripts/profile_sync.py | 28 +++++++++++++++++++++++++-- tests/test_profile_sync.py | 39 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/scripts/profile_sync.py b/scripts/profile_sync.py index 4be15954..1e051973 100644 --- a/scripts/profile_sync.py +++ b/scripts/profile_sync.py @@ -690,6 +690,11 @@ def verify_at_pin(part: RefPart, pin_lines, tokens) -> PartResult: contains, so comparing the two says nothing. What can still be checked is self-consistency: does the cited range carry the value the entry declares? """ + if is_external_citation(part.path): + return PartResult( + part, "EXTERNAL", None, None, None, [], + "names a project the profile does not declare", + ) if pin_lines is None: return PartResult( part, "GONE", None, None, None, [], "absent at the pinned revision" @@ -733,6 +738,25 @@ def verify_at_pin(part: RefPart, pin_lines, tokens) -> PartResult: ) +def reconcile_self_check(parts: list[PartResult]) -> list[PartResult]: + """Judge a self-checked entry whole rather than part by part. + + A ref often cites both the table carrying the value and the code that + loads the file. Once one part anchors on the value, the others describe + behaviour and cannot be judged by value: the checker would only rediscover + the value where the first part already points. A structurally absent part + still counts, since that verdict does not rest on the value. + """ + if not any(part.status == "ANCHORED" for part in parts): + return parts + kept = ("ANCHORED", "GONE", "EXTERNAL") + return [ + part if part.status in kept + else PartResult(part.part, "ANCHORED", None, None, None, []) + for part in parts + ] + + def version_tag_candidates(core_version: str) -> list[str]: """Tag spellings a declared core_version might use.""" version = str(core_version or "").strip() @@ -905,10 +929,10 @@ def build_report( self_check = bool(report.pinned_tag) or primary.pin == primary.head if self_check: staged = [ - (entry_name, ref, [ + (entry_name, ref, reconcile_self_check([ verify_at_pin(part, fetch(PIN, part.path), tokens) for part in split_source_ref(ref) - ]) + ])) for entry_name, ref, tokens in refs ] else: diff --git a/tests/test_profile_sync.py b/tests/test_profile_sync.py index b18553dd..4c89f81a 100644 --- a/tests/test_profile_sync.py +++ b/tests/test_profile_sync.py @@ -347,6 +347,45 @@ class TestVerifyAtPin(unittest.TestCase): result = profile_sync.verify_at_pin(part, lines, ["cafebabe"]) self.assertEqual(result.status, "AMBIGUOUS") + def test_one_anchored_part_settles_the_others(self): + parts = [ + profile_sync.PartResult( + RefPart("a.c", 1, 1, "a.c:1"), "ANCHORED", None, None, None, [] + ), + profile_sync.PartResult( + RefPart("a.c", 9, 9, "a.c:9"), "AMBIGUOUS", None, None, None, [1, 2] + ), + ] + settled = profile_sync.reconcile_self_check(parts) + self.assertEqual([p.status for p in settled], ["ANCHORED", "ANCHORED"]) + + def test_an_absent_part_survives_reconciliation(self): + parts = [ + profile_sync.PartResult( + RefPart("a.c", 1, 1, "a.c:1"), "ANCHORED", None, None, None, [] + ), + profile_sync.PartResult( + RefPart("b.c", 9, 9, "b.c:9"), "GONE", None, None, None, [] + ), + ] + settled = profile_sync.reconcile_self_check(parts) + self.assertEqual([p.status for p in settled], ["ANCHORED", "GONE"]) + + def test_nothing_anchored_leaves_the_verdicts_alone(self): + parts = [ + profile_sync.PartResult( + RefPart("a.c", 1, 1, "a.c:1"), "MOVED", None, 5, 5, [5] + ), + ] + self.assertEqual( + [p.status for p in profile_sync.reconcile_self_check(parts)], ["MOVED"] + ) + + def test_external_citation_is_out_of_reach_at_the_pin_too(self): + part = RefPart("munt ROMInfo.cpp", 1, 1, "munt ROMInfo.cpp:1") + result = profile_sync.verify_at_pin(part, None, ["cafebabe"]) + self.assertEqual(result.status, "EXTERNAL") + def test_missing_file(self): part = RefPart("a.c", 1, 1, "a.c:1") self.assertEqual(