diff --git a/scripts/generate_site.py b/scripts/generate_site.py index b16846c4..215f50a4 100644 --- a/scripts/generate_site.py +++ b/scripts/generate_site.py @@ -2690,7 +2690,7 @@ def generate_emulator_page( # Contributing page -def _render_problem_files(platform_problems: list) -> list[str]: +def _render_problem_files(platform_problems: list, settled: list | None = None) -> list[str]: """Files a platform declares that its own check then rejects. Split out of generate_gap_analysis, which reached complexity 56. This @@ -2786,6 +2786,23 @@ def _render_problem_files(platform_problems: list) -> list[str]: lines.append(f"| `{fname}` | {plats} | {f['discrepancy']} |") lines.append("") + if settled: + lines.extend([ + "### Other revisions of a held destination", + "", + "A platform can declare one path twice with different hashes. The " + "path holds the file one declaration accepts, so it is counted once, " + "as held; the other declaration cannot be met at the same time.", + "", + "| File | Platform | Status | Path held for system |", + "|------|----------|--------|--------------|", + ]) + for p in sorted(settled, key=lambda row: (row["name"], row["platform"])): + lines.append( + f"| `{p['name']}` | {p['platform']} | {p['status']} | `{p['held_by']}` |" + ) + lines.append("") + return lines @@ -2818,6 +2835,7 @@ def generate_gap_analysis( total_files_verify = 0 platform_problems: list[dict] = [] + settled_problems: list[dict] = [] for pname, cov in sorted(coverages.items(), key=lambda x: x[1]["platform"]): total_verified += cov["verified"] total_untested += cov["untested"] @@ -2825,6 +2843,15 @@ def generate_gap_analysis( total_files_verify += cov["total"] for d in cov["details"]: + if d.get("settled_by") and d["status"] != "ok": + # Its path holds another declaration's file: the headline, + # counted by destination, rightly leaves it out, and listing + # it under the same word made the page contradict itself. + settled_problems.append({ + "platform": cov["platform"], "name": d["name"], + "status": d["status"], "held_by": d["settled_by"], + }) + continue if d["status"] != "ok" or d.get("discrepancy"): platform_problems.append({ "platform": cov["platform"], @@ -3018,7 +3045,7 @@ def generate_gap_analysis( "", ]) - lines.extend(_render_problem_files(platform_problems)) + lines.extend(_render_problem_files(platform_problems, settled_problems)) # ---- Section 3: Core complement (cross-reference provenance) ---- diff --git a/scripts/verify.py b/scripts/verify.py index 9d04fea1..fbe3cae1 100644 --- a/scripts/verify.py +++ b/scripts/verify.py @@ -864,6 +864,9 @@ def _twin_unmet(result: dict, held_by: str | None) -> bool: result["discrepancy"] = ( f"{result.get('name', '')} is not met at the path {held_by} holds" ) + # Read by reports that list entries: the destination itself is held, and + # a count by destination does not include this one. + result["settled_by"] = held_by return True diff --git a/tests/test_audit_regressions.py b/tests/test_audit_regressions.py index f22226e1..65e8e025 100644 --- a/tests/test_audit_regressions.py +++ b/tests/test_audit_regressions.py @@ -4471,5 +4471,32 @@ class AdlerValuesReadLikeTheDownloads(unittest.TestCase): self.assertNotIn("['", text) + +class GapsPageCountsOneWay(unittest.TestCase): + """The stats block said 1 untested (by destination) while Problem Files + listed 4 untested entries, three of them at paths another declaration + of the same platform already holds.""" + + def test_settled_declarations_are_listed_apart(self): + from scripts.generate_site import _render_problem_files + + problems = [{"platform": "RetroDECK", "name": "dsifirmware.bin", "status": "untested", + "required": True, "reason": "x", "discrepancy": ""}] + settled = [{"platform": "RetroDECK", "name": "cdibios.zip", "status": "untested", + "held_by": "arcade"}] + text = "\n".join(_render_problem_files(problems, settled)) + self.assertIn("0 missing, 1 untested", text) + self.assertIn("Other revisions of a held destination", text) + self.assertIn("`cdibios.zip`", text) + + def test_verify_marks_the_settled_entry(self): + sys.path.insert(0, str(ROOT / "scripts")) + import verify + + result = {"name": "cdibios.zip", "status": verify.Status.UNTESTED} + self.assertTrue(verify._twin_unmet(result, "arcade")) + self.assertEqual(result["settled_by"], "arcade") + + if __name__ == "__main__": unittest.main()