From 554ec5f449e25f7bcd268dc2146d030b4e6f04e2 Mon Sep 17 00:00:00 2001 From: "Caroline G." Date: Mon, 10 Aug 2026 20:40:09 +0000 Subject: [PATCH 1/7] feat(governance): enforce author-dependent Governance Council approval rules --- org-tools/governance/scripts/pr_validator.py | 48 ++++++++-- .../governance/tests/test_pr_validator.py | 88 ++++++++++++++++++- 2 files changed, 129 insertions(+), 7 deletions(-) diff --git a/org-tools/governance/scripts/pr_validator.py b/org-tools/governance/scripts/pr_validator.py index 297b887..620adf9 100755 --- a/org-tools/governance/scripts/pr_validator.py +++ b/org-tools/governance/scripts/pr_validator.py @@ -174,12 +174,12 @@ def validate(self, pr: PullRequest) -> ValidationResult: # 7. Approvals & Assignments Evaluation (Global) requirement_statuses = self._evaluate_requirements( - merged_requirements, approver_usernames, assigned_usernames + merged_requirements, approver_usernames, assigned_usernames, author=pr.author ) # 8. File-by-File Evaluation file_statuses = self._evaluate_file_statuses( - requirements_by_file, approver_usernames, assigned_usernames + requirements_by_file, approver_usernames, assigned_usernames, author=pr.author ) # 9. Changes Requested Check @@ -223,6 +223,7 @@ def _evaluate_requirement( req: RuleRequirement, approver_usernames: set[str], requested_users_set: set[str], + author: str | None = None, ) -> RequirementStatus: """Calculate and return status for a requirement under the Venn Diagram model.""" approver_users = [User.create(u, self.memberships) for u in approver_usernames] @@ -231,11 +232,44 @@ def _evaluate_requirement( approvers = [u.username for u in approver_users if req.is_satisfied_by(u)] assigned_count = sum(1 for u in assigned_users if req.is_satisfied_by(u)) approved_count = len(approvers) + + # Dynamic Governance Council requirement evaluation based on PR author + is_gc_req = (req.team and req.team.name == "governance-council") or ( + req.min_team and req.min_team.name == "governance-council" + ) + + effective_req = req + required_approver = None + + if is_gc_req and author: + author_user = User.create(author, self.memberships) + is_author_gc = "governance-council" in author_user.teams + + if is_author_gc: + if author == "amithanda": + min_approvals = 1 + else: + min_approvals = 2 + required_approver = "amithanda" + else: + min_approvals = 2 + + if min_approvals != req.min_approvals: + effective_req = RuleRequirement( + min_approvals=min_approvals, + team=req.team, + min_team=req.min_team, + ) + + is_satisfied = approved_count >= effective_req.min_approvals + if required_approver and required_approver not in approvers: + is_satisfied = False + return RequirementStatus( - requirement=req, + requirement=effective_req, approved_count=approved_count, assigned_count=assigned_count, - is_satisfied=approved_count >= req.min_approvals, + is_satisfied=is_satisfied, approvers=sorted(approvers), ) @@ -244,12 +278,13 @@ def _evaluate_requirements( requirements: list[RuleRequirement], approver_usernames: set[str], assigned_usernames: set[str], + author: str | None = None, ) -> list[RequirementStatus]: """Evaluate each requirement's approvals and assignments count under the Venn Diagram model.""" requirement_statuses = [] for req in requirements: status = self._evaluate_requirement( - req, approver_usernames, assigned_usernames + req, approver_usernames, assigned_usernames, author=author ) requirement_statuses.append(status) @@ -305,12 +340,13 @@ def _evaluate_file_statuses( requirements_by_file: dict[str, list[RuleRequirement]], approver_usernames: set[str], assigned_usernames: set[str], + author: str | None = None, ) -> list[FileValidationStatus]: """Evaluates and generates validation statuses for each changed file in the PR.""" file_statuses = [] for file, file_requirements in requirements_by_file.items(): file_req_statuses = self._evaluate_requirements( - file_requirements, approver_usernames, assigned_usernames + file_requirements, approver_usernames, assigned_usernames, author=author ) file_satisfied = all(status.is_satisfied for status in file_req_statuses) diff --git a/org-tools/governance/tests/test_pr_validator.py b/org-tools/governance/tests/test_pr_validator.py index 9fc1217..d4fd561 100644 --- a/org-tools/governance/tests/test_pr_validator.py +++ b/org-tools/governance/tests/test_pr_validator.py @@ -120,6 +120,8 @@ def setUp(self): "governance-council": { "gov-member1", "gov-member2", + "gov-member3", + "amithanda", "proxy1", }, }, @@ -259,7 +261,7 @@ def test_specific_team_requirement(self): self.assertFalse(res.is_mergeable) self.assertEqual(res.error, ValidationErrorReason.INSUFFICIENT_APPROVALS) - # gov-member1 is in governance-council, should pass + # gov-member1 and gov-member2 (2 GC members) for non-GC author1 should pass pr_ok = PullRequest( number=1, author="author1", @@ -267,11 +269,95 @@ def test_specific_team_requirement(self): changed_files=["LICENSE"], reviews=[ Review(user="gov-member1", state=ReviewState.APPROVED), + Review(user="gov-member2", state=ReviewState.APPROVED), ], ) res_ok = self.validator.validate(pr_ok) self.assertTrue(res_ok.is_mergeable) + def test_gc_author_non_gc_author_requires_two_approvals(self): + """Non-GC author requires 2 GC approvers.""" + pr_1_app = PullRequest( + number=1, + author="author1", + is_draft=False, + changed_files=["LICENSE"], + reviews=[ + Review(user="gov-member1", state=ReviewState.APPROVED), + ], + ) + res_1 = self.validator.validate(pr_1_app) + self.assertFalse(res_1.is_mergeable) + self.assertEqual(res_1.error, ValidationErrorReason.INSUFFICIENT_APPROVALS) + + pr_2_app = PullRequest( + number=1, + author="author1", + is_draft=False, + changed_files=["LICENSE"], + reviews=[ + Review(user="gov-member1", state=ReviewState.APPROVED), + Review(user="gov-member2", state=ReviewState.APPROVED), + ], + ) + res_2 = self.validator.validate(pr_2_app) + self.assertTrue(res_2.is_mergeable) + + def test_gc_author_amithanda_requires_one_approval(self): + """GC author amithanda requires 1 GC approver.""" + pr_0_app = PullRequest( + number=1, + author="amithanda", + is_draft=False, + changed_files=["LICENSE"], + reviews=[], + ) + res_0 = self.validator.validate(pr_0_app) + self.assertFalse(res_0.is_mergeable) + + pr_1_app = PullRequest( + number=1, + author="amithanda", + is_draft=False, + changed_files=["LICENSE"], + reviews=[ + Review(user="gov-member1", state=ReviewState.APPROVED), + ], + ) + res_1 = self.validator.validate(pr_1_app) + self.assertTrue(res_1.is_mergeable) + + def test_gc_author_other_gc_member_requires_two_approvals_including_amit(self): + """GC author who is not amithanda requires 2 GC approvers, one of which must be amithanda.""" + # 2 GC approvals without amithanda (non-proxy reviewers) -> fails + pr_no_amit = PullRequest( + number=1, + author="gov-member1", + is_draft=False, + changed_files=["LICENSE"], + reviews=[ + Review(user="gov-member2", state=ReviewState.APPROVED), + Review(user="gov-member3", state=ReviewState.APPROVED), + ], + ) + res_no_amit = self.validator.validate(pr_no_amit) + self.assertFalse(res_no_amit.is_mergeable) + self.assertEqual(res_no_amit.error, ValidationErrorReason.INSUFFICIENT_APPROVALS) + + # 2 GC approvals with amithanda -> passes + pr_with_amit = PullRequest( + number=1, + author="gov-member1", + is_draft=False, + changed_files=["LICENSE"], + reviews=[ + Review(user="amithanda", state=ReviewState.APPROVED), + Review(user="gov-member2", state=ReviewState.APPROVED), + ], + ) + res_with_amit = self.validator.validate(pr_with_amit) + self.assertTrue(res_with_amit.is_mergeable) + def test_changes_requested_blocks(self): """Test that changes requested block validation.""" pr = PullRequest( From bee4374577a46c9317023ed2195592a23da33082 Mon Sep 17 00:00:00 2001 From: damaz91 Date: Wed, 12 Aug 2026 09:33:46 +0000 Subject: [PATCH 2/7] feat(governance): simplify GC dynamic approval rules to 1 for GC, 2 for non-GC --- org-tools/governance/scripts/pr_validator.py | 19 +++++++++---------- .../governance/tests/test_pr_validator.py | 13 +++++-------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/org-tools/governance/scripts/pr_validator.py b/org-tools/governance/scripts/pr_validator.py index 620adf9..3f1a82d 100755 --- a/org-tools/governance/scripts/pr_validator.py +++ b/org-tools/governance/scripts/pr_validator.py @@ -174,12 +174,18 @@ def validate(self, pr: PullRequest) -> ValidationResult: # 7. Approvals & Assignments Evaluation (Global) requirement_statuses = self._evaluate_requirements( - merged_requirements, approver_usernames, assigned_usernames, author=pr.author + merged_requirements, + approver_usernames, + assigned_usernames, + author=pr.author, ) # 8. File-by-File Evaluation file_statuses = self._evaluate_file_statuses( - requirements_by_file, approver_usernames, assigned_usernames, author=pr.author + requirements_by_file, + approver_usernames, + assigned_usernames, + author=pr.author, ) # 9. Changes Requested Check @@ -239,18 +245,13 @@ def _evaluate_requirement( ) effective_req = req - required_approver = None if is_gc_req and author: author_user = User.create(author, self.memberships) is_author_gc = "governance-council" in author_user.teams if is_author_gc: - if author == "amithanda": - min_approvals = 1 - else: - min_approvals = 2 - required_approver = "amithanda" + min_approvals = 1 else: min_approvals = 2 @@ -262,8 +263,6 @@ def _evaluate_requirement( ) is_satisfied = approved_count >= effective_req.min_approvals - if required_approver and required_approver not in approvers: - is_satisfied = False return RequirementStatus( requirement=effective_req, diff --git a/org-tools/governance/tests/test_pr_validator.py b/org-tools/governance/tests/test_pr_validator.py index d4fd561..64fea3d 100644 --- a/org-tools/governance/tests/test_pr_validator.py +++ b/org-tools/governance/tests/test_pr_validator.py @@ -327,9 +327,9 @@ def test_gc_author_amithanda_requires_one_approval(self): res_1 = self.validator.validate(pr_1_app) self.assertTrue(res_1.is_mergeable) - def test_gc_author_other_gc_member_requires_two_approvals_including_amit(self): - """GC author who is not amithanda requires 2 GC approvers, one of which must be amithanda.""" - # 2 GC approvals without amithanda (non-proxy reviewers) -> fails + def test_gc_author_other_gc_member_requires_one_approval(self): + """GC author who is not amithanda requires 1 GC approver (not necessarily amithanda).""" + # 1 GC approval without amithanda -> passes pr_no_amit = PullRequest( number=1, author="gov-member1", @@ -337,14 +337,12 @@ def test_gc_author_other_gc_member_requires_two_approvals_including_amit(self): changed_files=["LICENSE"], reviews=[ Review(user="gov-member2", state=ReviewState.APPROVED), - Review(user="gov-member3", state=ReviewState.APPROVED), ], ) res_no_amit = self.validator.validate(pr_no_amit) - self.assertFalse(res_no_amit.is_mergeable) - self.assertEqual(res_no_amit.error, ValidationErrorReason.INSUFFICIENT_APPROVALS) + self.assertTrue(res_no_amit.is_mergeable) - # 2 GC approvals with amithanda -> passes + # 1 GC approval with amithanda -> passes pr_with_amit = PullRequest( number=1, author="gov-member1", @@ -352,7 +350,6 @@ def test_gc_author_other_gc_member_requires_two_approvals_including_amit(self): changed_files=["LICENSE"], reviews=[ Review(user="amithanda", state=ReviewState.APPROVED), - Review(user="gov-member2", state=ReviewState.APPROVED), ], ) res_with_amit = self.validator.validate(pr_with_amit) From 08157f1e3ecdef324684fd420c2eae59eacb3154 Mon Sep 17 00:00:00 2001 From: damaz91 Date: Wed, 12 Aug 2026 09:37:22 +0000 Subject: [PATCH 3/7] feat(governance): only override GC approvals for GC authors --- org-tools/governance/scripts/pr_validator.py | 15 ++++---- .../governance/tests/test_pr_validator.py | 35 ++++++++++++++++++- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/org-tools/governance/scripts/pr_validator.py b/org-tools/governance/scripts/pr_validator.py index 3f1a82d..2216889 100755 --- a/org-tools/governance/scripts/pr_validator.py +++ b/org-tools/governance/scripts/pr_validator.py @@ -252,15 +252,12 @@ def _evaluate_requirement( if is_author_gc: min_approvals = 1 - else: - min_approvals = 2 - - if min_approvals != req.min_approvals: - effective_req = RuleRequirement( - min_approvals=min_approvals, - team=req.team, - min_team=req.min_team, - ) + if min_approvals != req.min_approvals: + effective_req = RuleRequirement( + min_approvals=min_approvals, + team=req.team, + min_team=req.min_team, + ) is_satisfied = approved_count >= effective_req.min_approvals diff --git a/org-tools/governance/tests/test_pr_validator.py b/org-tools/governance/tests/test_pr_validator.py index 64fea3d..c292d27 100644 --- a/org-tools/governance/tests/test_pr_validator.py +++ b/org-tools/governance/tests/test_pr_validator.py @@ -80,7 +80,7 @@ def setUp(self): patterns=["LICENSE", ".github/CODEOWNERS"], requires_all=[ RuleRequirement( - min_approvals=1, team=self.hierarchy["governance-council"] + min_approvals=2, team=self.hierarchy["governance-council"] ) ], ), @@ -355,6 +355,39 @@ def test_gc_author_other_gc_member_requires_one_approval(self): res_with_amit = self.validator.validate(pr_with_amit) self.assertTrue(res_with_amit.is_mergeable) + def test_gc_requirement_non_gc_author_respects_yaml_1(self): + """Test that if YAML requires 1 approval, non-GC author only needs 1 (no override to 2).""" + rules = [ + GovernanceRule( + name="Gov 1", + patterns=["LICENSE"], + requires_all=[ + RuleRequirement( + min_approvals=1, team=self.hierarchy["governance-council"] + ) + ], + ) + ] + config = GovernanceConfig( + teams=self.hierarchy, + rules=rules, + fallback=self.fallback, + proxy_reviewers=self.proxy_reviewers, + ) + validator = PullRequestValidator(config, self.memberships) + + pr = PullRequest( + number=1, + author="author1", # Not GC + is_draft=False, + changed_files=["LICENSE"], + reviews=[ + Review(user="gov-member1", state=ReviewState.APPROVED), + ], + ) + res = validator.validate(pr) + self.assertTrue(res.is_mergeable) + def test_changes_requested_blocks(self): """Test that changes requested block validation.""" pr = PullRequest( From 315d1a508dda52c5858dace1c8cba363b8db8033 Mon Sep 17 00:00:00 2001 From: damaz91 Date: Wed, 12 Aug 2026 09:42:50 +0000 Subject: [PATCH 4/7] test(governance): clean up redundant GC author approval tests --- .../governance/tests/test_pr_validator.py | 41 ++++--------------- 1 file changed, 8 insertions(+), 33 deletions(-) diff --git a/org-tools/governance/tests/test_pr_validator.py b/org-tools/governance/tests/test_pr_validator.py index c292d27..fba2cd6 100644 --- a/org-tools/governance/tests/test_pr_validator.py +++ b/org-tools/governance/tests/test_pr_validator.py @@ -303,34 +303,22 @@ def test_gc_author_non_gc_author_requires_two_approvals(self): res_2 = self.validator.validate(pr_2_app) self.assertTrue(res_2.is_mergeable) - def test_gc_author_amithanda_requires_one_approval(self): - """GC author amithanda requires 1 GC approver.""" + def test_gc_author_requires_one_approval(self): + """GC author requires 1 GC approver.""" + # gov-member1 (GC) author, 0 approvals -> fails pr_0_app = PullRequest( number=1, - author="amithanda", + author="gov-member1", is_draft=False, changed_files=["LICENSE"], reviews=[], ) res_0 = self.validator.validate(pr_0_app) self.assertFalse(res_0.is_mergeable) + self.assertEqual(res_0.error, ValidationErrorReason.INSUFFICIENT_APPROVALS) + # gov-member1 (GC) author, 1 GC approval -> passes pr_1_app = PullRequest( - number=1, - author="amithanda", - is_draft=False, - changed_files=["LICENSE"], - reviews=[ - Review(user="gov-member1", state=ReviewState.APPROVED), - ], - ) - res_1 = self.validator.validate(pr_1_app) - self.assertTrue(res_1.is_mergeable) - - def test_gc_author_other_gc_member_requires_one_approval(self): - """GC author who is not amithanda requires 1 GC approver (not necessarily amithanda).""" - # 1 GC approval without amithanda -> passes - pr_no_amit = PullRequest( number=1, author="gov-member1", is_draft=False, @@ -339,21 +327,8 @@ def test_gc_author_other_gc_member_requires_one_approval(self): Review(user="gov-member2", state=ReviewState.APPROVED), ], ) - res_no_amit = self.validator.validate(pr_no_amit) - self.assertTrue(res_no_amit.is_mergeable) - - # 1 GC approval with amithanda -> passes - pr_with_amit = PullRequest( - number=1, - author="gov-member1", - is_draft=False, - changed_files=["LICENSE"], - reviews=[ - Review(user="amithanda", state=ReviewState.APPROVED), - ], - ) - res_with_amit = self.validator.validate(pr_with_amit) - self.assertTrue(res_with_amit.is_mergeable) + res_1 = self.validator.validate(pr_1_app) + self.assertTrue(res_1.is_mergeable) def test_gc_requirement_non_gc_author_respects_yaml_1(self): """Test that if YAML requires 1 approval, non-GC author only needs 1 (no override to 2).""" From f783e458dfd1d9402d78e74cbe8f426407d55c30 Mon Sep 17 00:00:00 2001 From: damaz91 Date: Wed, 12 Aug 2026 09:45:40 +0000 Subject: [PATCH 5/7] test(governance): remove amithanda from test GC team --- org-tools/governance/tests/test_pr_validator.py | 1 - 1 file changed, 1 deletion(-) diff --git a/org-tools/governance/tests/test_pr_validator.py b/org-tools/governance/tests/test_pr_validator.py index fba2cd6..5d93ac9 100644 --- a/org-tools/governance/tests/test_pr_validator.py +++ b/org-tools/governance/tests/test_pr_validator.py @@ -121,7 +121,6 @@ def setUp(self): "gov-member1", "gov-member2", "gov-member3", - "amithanda", "proxy1", }, }, From 17fea2ceee345a6fbeaa17605aaed699664447eb Mon Sep 17 00:00:00 2001 From: damaz91 Date: Wed, 12 Aug 2026 09:56:19 +0000 Subject: [PATCH 6/7] feat(governance): require 2 total approvals when GC rule min_approvals is overridden --- org-tools/governance/scripts/pr_validator.py | 7 ++++ .../governance/scripts/validation_logger.py | 24 +++++++----- .../governance/tests/test_pr_validator.py | 37 +++++++++++++++++-- 3 files changed, 56 insertions(+), 12 deletions(-) diff --git a/org-tools/governance/scripts/pr_validator.py b/org-tools/governance/scripts/pr_validator.py index 2216889..fb7648d 100755 --- a/org-tools/governance/scripts/pr_validator.py +++ b/org-tools/governance/scripts/pr_validator.py @@ -245,6 +245,7 @@ def _evaluate_requirement( ) effective_req = req + require_total_approvals = None if is_gc_req and author: author_user = User.create(author, self.memberships) @@ -258,8 +259,14 @@ def _evaluate_requirement( team=req.team, min_team=req.min_team, ) + require_total_approvals = req.min_approvals is_satisfied = approved_count >= effective_req.min_approvals + if ( + require_total_approvals is not None + and len(approver_usernames) < require_total_approvals + ): + is_satisfied = False return RequirementStatus( requirement=effective_req, diff --git a/org-tools/governance/scripts/validation_logger.py b/org-tools/governance/scripts/validation_logger.py index f6d9e14..aea26ce 100644 --- a/org-tools/governance/scripts/validation_logger.py +++ b/org-tools/governance/scripts/validation_logger.py @@ -147,15 +147,21 @@ def _format_requirement_status( return f"{req_line}\n{met_line}" missing = req.min_approvals - status.approved_count - if status.assigned_count >= missing: - hint = f"Waiting for approval from {team_desc}." + if missing <= 0: + pending_line = ( + f"{indent} * **Pending:** Governance Council requirement met ({status.approved_count}/{req.min_approvals}), " + f"waiting for additional peer review to satisfy total required approvals." + ) else: - needed = missing - status.assigned_count - hint = f"Waiting for {needed} more reviewer(s) to be assigned from {team_desc}." - pending_line = ( - f"{indent} * **Pending:** Needs {missing} approval{'s' if missing > 1 else ''} " - f"from {team_desc} ({status.assigned_count} eligible " - f"reviewer{'s' if status.assigned_count != 1 else ''} assigned). {hint}" - ) + if status.assigned_count >= missing: + hint = f"Waiting for approval from {team_desc}." + else: + needed = missing - status.assigned_count + hint = f"Waiting for {needed} more reviewer(s) to be assigned from {team_desc}." + pending_line = ( + f"{indent} * **Pending:** Needs {missing} approval{'s' if missing > 1 else ''} " + f"from {team_desc} ({status.assigned_count} eligible " + f"reviewer{'s' if status.assigned_count != 1 else ''} assigned). {hint}" + ) return f"{req_line}\n{met_line}\n{pending_line}" diff --git a/org-tools/governance/tests/test_pr_validator.py b/org-tools/governance/tests/test_pr_validator.py index 5d93ac9..728817e 100644 --- a/org-tools/governance/tests/test_pr_validator.py +++ b/org-tools/governance/tests/test_pr_validator.py @@ -303,7 +303,7 @@ def test_gc_author_non_gc_author_requires_two_approvals(self): self.assertTrue(res_2.is_mergeable) def test_gc_author_requires_one_approval(self): - """GC author requires 1 GC approver.""" + """GC author requires 1 GC approver and 2 total approvers when rule requires 2.""" # gov-member1 (GC) author, 0 approvals -> fails pr_0_app = PullRequest( number=1, @@ -316,7 +316,7 @@ def test_gc_author_requires_one_approval(self): self.assertFalse(res_0.is_mergeable) self.assertEqual(res_0.error, ValidationErrorReason.INSUFFICIENT_APPROVALS) - # gov-member1 (GC) author, 1 GC approval -> passes + # gov-member1 (GC) author, 1 GC approval alone -> fails (needs 2 total approvals) pr_1_app = PullRequest( number=1, author="gov-member1", @@ -327,7 +327,38 @@ def test_gc_author_requires_one_approval(self): ], ) res_1 = self.validator.validate(pr_1_app) - self.assertTrue(res_1.is_mergeable) + self.assertFalse(res_1.is_mergeable) + self.assertEqual(res_1.error, ValidationErrorReason.INSUFFICIENT_APPROVALS) + + # gov-member1 (GC) author, 1 GC approval + 1 peer/maintainer approval -> passes + pr_1_gc_1_peer = PullRequest( + number=1, + author="gov-member1", + is_draft=False, + changed_files=["LICENSE"], + reviews=[ + Review(user="gov-member2", state=ReviewState.APPROVED), + Review(user="maint1", state=ReviewState.APPROVED), + ], + ) + res_gc_peer = self.validator.validate(pr_1_gc_1_peer) + self.assertTrue(res_gc_peer.is_mergeable) + self.assertEqual(res_gc_peer.mergeable_reason, MergeableReason.RULES_SATISFIED) + + # gov-member1 (GC) author, 2 GC approvals -> passes + pr_2_gc = PullRequest( + number=1, + author="gov-member1", + is_draft=False, + changed_files=["LICENSE"], + reviews=[ + Review(user="gov-member2", state=ReviewState.APPROVED), + Review(user="gov-member3", state=ReviewState.APPROVED), + ], + ) + res_2_gc = self.validator.validate(pr_2_gc) + self.assertTrue(res_2_gc.is_mergeable) + self.assertEqual(res_2_gc.mergeable_reason, MergeableReason.RULES_SATISFIED) def test_gc_requirement_non_gc_author_respects_yaml_1(self): """Test that if YAML requires 1 approval, non-GC author only needs 1 (no override to 2).""" From 0f76fbd7d0e8b3d699a829888668a5278e51e08f Mon Sep 17 00:00:00 2001 From: damaz91 Date: Wed, 12 Aug 2026 09:58:22 +0000 Subject: [PATCH 7/7] style(logger): update pending message phrasing to any member review --- org-tools/governance/scripts/validation_logger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org-tools/governance/scripts/validation_logger.py b/org-tools/governance/scripts/validation_logger.py index aea26ce..919bfab 100644 --- a/org-tools/governance/scripts/validation_logger.py +++ b/org-tools/governance/scripts/validation_logger.py @@ -150,7 +150,7 @@ def _format_requirement_status( if missing <= 0: pending_line = ( f"{indent} * **Pending:** Governance Council requirement met ({status.approved_count}/{req.min_approvals}), " - f"waiting for additional peer review to satisfy total required approvals." + f"waiting for additional review from any member to satisfy total required approvals." ) else: if status.assigned_count >= missing: