diff --git a/spec/audit.py b/spec/audit.py index fd8e889b..c7f99966 100644 --- a/spec/audit.py +++ b/spec/audit.py @@ -39,9 +39,17 @@ "has_wiki", "has_projects", "allow_merge_commit", "allow_squash_merge", "allow_rebase_merge", "allow_auto_merge", "allow_update_branch", "delete_branch_on_merge", ] -RULESET_SUBSET = ["name", "target", "enforcement", "bypass_actors", "conditions", "rules"] -# Phrases in a registry driftNote that assert work still outstanding. Deliberately specific: a note -# recording a permanent deviation ("no get-version-task; relies on validate-task") must not match. +# The bypass_actors field is deliberately absent from this list. +# Who may bypass a ruleset is a per-repository human decision taken in the UI. +# The configure.sh script in repo-config treats it that way, since apply writes the live list back unchanged and check reports it without asserting. +# Comparing it here would contradict that, and did. +# Once the payloads stopped declaring a bypass list, every repo whose live ruleset still had one reported a ruleset DEFECT. +# That was a field the fleet config had deliberately stopped managing. +# Two tools comparing one field under opposite policies is the defect, rather than the field's value. +RULESET_SUBSET = ["name", "target", "enforcement", "conditions", "rules"] +# Phrases in a registry driftNote that assert work is still outstanding. +# Deliberately specific, so a note recording a permanent deviation must not match. +# An example of one that must not match is a note reading that there is no get-version-task and validate-task is relied on instead. PENDING_MARKERS = ["pending", "not yet", "owed", "todo", "still", "behind", "missing", "absent"] @@ -102,8 +110,6 @@ def normalize_ruleset(payload): sub = {k: payload.get(k) for k in RULESET_SUBSET} if isinstance(sub.get("rules"), list): sub["rules"] = sorted(sub["rules"], key=lambda r: json.dumps(r, sort_keys=True)) - if isinstance(sub.get("bypass_actors"), list): - sub["bypass_actors"] = sorted(sub["bypass_actors"], key=lambda a: (str(a.get("actor_type")), str(a.get("actor_id")))) return json.dumps(sub, sort_keys=True)