From 78d6bbfb24c64aced31b2e9ad5613f0f18bc4fbc Mon Sep 17 00:00:00 2001 From: Vinta Chen Date: Wed, 14 Oct 2026 23:15:42 +0800 Subject: [PATCH] fix: match audit_priority entries by name or URL across revisions Entries were matched across revisions by normalized name only, so a rename (dateutil to python-dateutil, mock to unittest.mock) showed as one removal plus one addition and flagged the section as changed since its audit. Co-Authored-By: Claude --- .../audit-the-list/scripts/audit_priority.py | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/.claude/skills/audit-the-list/scripts/audit_priority.py b/.claude/skills/audit-the-list/scripts/audit_priority.py index 03b66d9e..f6766836 100644 --- a/.claude/skills/audit-the-list/scripts/audit_priority.py +++ b/.claude/skills/audit-the-list/scripts/audit_priority.py @@ -30,17 +30,25 @@ def git(*args: str) -> str: @cache -def entries_at(rev: str) -> dict[str, dict[str, str]]: - """Section -> {normalized entry name: display name}, so a recased or re-punctuated name is no change.""" +def entries_at(rev: str) -> dict[str, dict[str, set[str]]]: + """Section -> {display name: {normalized name, normalized URL}}. + + An entry matches across revisions on either key, so a rename that keeps its link, or a link fix that keeps its name, is no change. + """ sections = {} for group in parse_readme(git("show", f"{rev}:README.md")): for category in group["categories"]: - names = [entry["name"] for entry in category["entries"]] - names += [sub["name"] for entry in category["entries"] for sub in entry["also_see"]] - sections[category["name"]] = {re.sub(r"[-_.]+", "-", name).lower(): name for name in names} + links = [*category["entries"], *(sub for entry in category["entries"] for sub in entry["also_see"])] + sections[category["name"]] = {link["name"]: {re.sub(r"[-_.]+", "-", link["name"]).lower(), link["url"].rstrip("/").lower()} for link in links} return sections +def missing(entries: dict[str, set[str]], other: dict[str, set[str]]) -> list[str]: + """Display names in entries that match no entry in other.""" + keys = set().union(*other.values()) + return [name for name, own in entries.items() if not own & keys] + + def resolve(text: str, groups: dict[str, list[str]]) -> list[str]: """Sections named in text, longest name first so "Database Drivers" never counts as "Database".""" found = [] @@ -94,8 +102,8 @@ def main() -> None: for section in group_of: _, date, rev = last.get(section, (0, "never", REFORM)) before = entries_at(rev).get(section, {}) - added = [head[section][n] for n in head[section].keys() - before.keys()] - removed = [before[n] for n in before.keys() - head[section].keys()] + added = missing(head[section], before) + removed = missing(before, head[section]) row = (section, date, rev[:7] if section in last else "", added, removed) (changed if added or removed else unchanged).append(row)