From 7b509b78a14785189d93b9b9f542be6198a58c14 Mon Sep 17 00:00:00 2001 From: shuse2 Date: Thu, 7 May 2026 22:01:25 +0900 Subject: [PATCH] feat: round-robin within team when no domain specialist is eligible Make the squad-wide fallback unconditional so a sole-specialist author (matjazv on backend/contracts, vardan10 on backend, ricott1 on contracts, Nazgolze on infra) gets a teammate via round-robin instead of cascading to a sibling squad. In-team review is now the priority; sibling cascade only fires when the entire team has no other eligible member. Drop the now-obsolete fallback_to_squad_members_for field and its validator block. --- .github/workflows/auto-assign-reviewer.yml | 22 +++++++++------------- .github/workflows/validate-review-map.yml | 9 --------- docs/auto-reviewer.md | 14 +++++++------- review-map.yml | 7 ++----- 4 files changed, 18 insertions(+), 34 deletions(-) diff --git a/.github/workflows/auto-assign-reviewer.yml b/.github/workflows/auto-assign-reviewer.yml index 43d92bb..ed2f153 100644 --- a/.github/workflows/auto-assign-reviewer.yml +++ b/.github/workflows/auto-assign-reviewer.yml @@ -7,7 +7,7 @@ name: Auto-assign Reviewer (Reusable) # Cascade (see docs/auto-reviewer.md): # 1. own-squad specialists for the domain (round-robin via PR# % N) # 2. own-squad specialists for an equivalent domain (web ↔ mobile) -# 3. for fallback_to_squad_members_for domains: any other squad member +# 3. any other own-squad member (round-robin) — keeps review in-team # 4. sibling squads in sibling_fallback_order (actual domain only) # 5. soft-fail with PR comment @@ -180,19 +180,15 @@ jobs: done fi - # Step 3: squad-wide fallback for designated domains (e.g., infra) + # Step 3: squad-wide fallback — any other team member (in-team priority) if [ -z "$SELECTED" ]; then - FB=$(jq -r --arg s "$AUTHOR_SQUAD" ' - .squads[$s].fallback_to_squad_members_for // [] | .[]' "$MAP_JSON") - if printf '%s\n' "$FB" | grep -Fxq "$DOMAIN"; then - SQUAD_MEMBERS=$(jq -r --arg s "$AUTHOR_SQUAD" '.squads[$s].members[]' "$MAP_JSON") - CAND=$(printf '%s\n' "$SQUAD_MEMBERS" | grep -v -Fx "$PR_AUTHOR" || true) - if [ -n "$CAND" ]; then - COUNT=$(printf '%s\n' "$CAND" | wc -l | tr -d ' ') - IDX=$(( PR_NUMBER % COUNT )) - SELECTED=$(printf '%s\n' "$CAND" | sed -n "$((IDX + 1))p") - REASON="own-squad ($AUTHOR_SQUAD) member fallback for $DOMAIN" - fi + SQUAD_MEMBERS=$(jq -r --arg s "$AUTHOR_SQUAD" '.squads[$s].members[]' "$MAP_JSON") + CAND=$(printf '%s\n' "$SQUAD_MEMBERS" | grep -v -Fx "$PR_AUTHOR" || true) + if [ -n "$CAND" ]; then + COUNT=$(printf '%s\n' "$CAND" | wc -l | tr -d ' ') + IDX=$(( PR_NUMBER % COUNT )) + SELECTED=$(printf '%s\n' "$CAND" | sed -n "$((IDX + 1))p") + REASON="own-squad ($AUTHOR_SQUAD) team round-robin (no $DOMAIN specialist available)" fi fi diff --git a/.github/workflows/validate-review-map.yml b/.github/workflows/validate-review-map.yml index f64f806..dd6ce2f 100644 --- a/.github/workflows/validate-review-map.yml +++ b/.github/workflows/validate-review-map.yml @@ -95,15 +95,6 @@ jobs: fi done < <(jq -r '.bot_pr_owners // {} | to_entries[] | [.key, .value] | @tsv' "$MAP_JSON") - # fallback_to_squad_members_for entries must be valid domains - while IFS=$'\t' read -r squad domain; do - [ -z "$domain" ] && continue - case " $ALLOWED_DOMAINS " in - *" $domain "*) ;; - *) err "squad '$squad' fallback_to_squad_members_for contains unknown domain: '$domain'" ;; - esac - done < <(jq -r '.squads | to_entries[] | .key as $s | (.value.fallback_to_squad_members_for // [])[] | [$s, .] | @tsv' "$MAP_JSON") - # domain_equivalence keys and values must all be valid domains while IFS=$'\t' read -r k v; do [ -z "$k" ] && continue diff --git a/docs/auto-reviewer.md b/docs/auto-reviewer.md index 96afbfd..377cc1b 100644 --- a/docs/auto-reviewer.md +++ b/docs/auto-reviewer.md @@ -37,8 +37,11 @@ Given a human PR author `A`, repo domain `D`, author squad `S`: 2. **Own-squad equivalent domain.** For each `E` in `domain_equivalence[D]`, if `S.specialists[E]` minus `A` is non-empty, pick `eligible[PR# % len]`. Keeps the review inside the squad when web/mobile are interchangeable. -3. **Squad-wide fallback.** If `D ∈ S.fallback_to_squad_members_for` and prior - steps produced nothing, pick from `S.members` minus `A`. +3. **Own-squad team round-robin.** If prior steps produced nothing, pick from + `S.members` minus `A`. In-team review is the priority — only after every + teammate is exhausted do we cross squads. Useful when the author is the + sole specialist for the domain (e.g., matjazv on a backend or contracts + PR in `org`) so the PR still gets reviewed by their own team. 4. **Sibling cascade.** Walk `sibling_fallback_order`. For each sibling squad `T` (`T ≠ S`), if `T.specialists[D]` minus `A` is non-empty, pick `eligible[PR# % len]`. Equivalence is **not** applied cross-squad. @@ -70,11 +73,8 @@ cascade always uses the actual domain. | org | matjazv | mmarinovic, mvuco00, ikem-legend, mislavtomic | — | — | matjazv | | global | — | — | — | — | ricott1 | -`—` = no own-squad specialist; cascades to siblings. - -`platform.fallback_to_squad_members_for: [infra]` — when Nazgolze opens an -infra PR, fall back to any other platform member instead of jumping to -siblings. +`—` = no own-squad specialist; falls back to any other team member, then +cascades to siblings if the team has no one else available. `sibling_fallback_order: [money, org, platform, global]`. diff --git a/review-map.yml b/review-map.yml index f61b29c..bb3fae0 100644 --- a/review-map.yml +++ b/review-map.yml @@ -46,8 +46,8 @@ domain_equivalence: web: [mobile] mobile: [web] -# When own-squad has no eligible specialist (and no equivalent), walk -# siblings in this order. +# When own-squad has no eligible reviewer at all (no specialist, no equivalent +# specialist, no other squad member), walk siblings in this order. sibling_fallback_order: - money - org @@ -64,9 +64,6 @@ squads: specialists: backend: [sameersubudhi, ishantiw] infra: [Nazgolze] - # Domains where, if no specialist is eligible, the cascade falls back to - # any other squad member (instead of jumping straight to siblings). - fallback_to_squad_members_for: [infra] money: tl: 5heri