fix: prevent phantom team diffs caused by slug vs name mismatch#997
Draft
fgenois-coveo wants to merge 5 commits into
Draft
fix: prevent phantom team diffs caused by slug vs name mismatch#997fgenois-coveo wants to merge 5 commits into
fgenois-coveo wants to merge 5 commits into
Conversation
Teams in YAML use slug format (e.g. name: "my-team") while the GitHub API returns display name (e.g. name: "My Team") with a separate slug field. This caused phantom diffs in NOP mode: teams reported as additions + deletions when no actual changes exist. The fix adds slug-aware matching in processArrays addition/deletion filters. When a target item has a slug field, it's compared against the source name (which is the slug in safe-settings convention). This is backward compatible: items without slug (labels, rulesets) continue to match by name as before.
43a788a to
39b0bdb
Compare
Add 'slug' (first) and 'title' (last) to NAME_FIELDS for teams and milestones identity matching. Remove hardcoded slug special case in favor of unified lookup. Guard compareDeepIfVisited against mixed primitive/object arrays.
39b0bdb to
6e205ac
Compare
fgenois-coveo
commented
Jun 16, 2026
fgenois-coveo
commented
Jun 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When running safe-settings in NOP mode (or any diff-reporting path), teams are incorrectly reported as additions + deletions even when nothing has changed.
Root cause:
MergeDeep.processArrays()resolves item identity viaNAME_FIELDS, butslugwas missing from that list. For teams, the GitHub API returns bothname(display name like "Dev Tooling") andslug(like "dev-tooling"). YAML configs use the slug value in thenamefield. Since the API object'snamediffers from the YAML'sname, MergeDeep treats them as different items.The sync path in
teams.jsalready handles this correctly (existing.slug === attrs.name.toLowerCase()), so the mismatch only affects diff reporting.Fix
Add
slug(first position) toNAME_FIELDS— API team objects now resolve identity viaslug, while YAML objects (which lackslug) resolve vianame. Both produce the same value → correct match.Add
titletoNAME_FIELDS— milestones usetitleas identity but it was missing from the list.Remove the hardcoded
if (item.slug) return item.slugspecial case — the priority-orderedNAME_FIELDShandles this uniformly.Guard
compareDeepIfVisitedagainst mixed primitive/object arrays — prevents crashes when branch protection comparesusers: ["test"]againstusers: [{login: "test", type: "User"}].Strip identity fields per-item — when source uses
nameand target usesslug, each side strips its own identity field before deep comparison.Backward compatible — no other plugin returns objects with a
slugfield, andtitleis only used by milestones (which have nonamefield).Test matrix
{name: "dev-tooling", permission: "admin"}{name: "Dev Tooling", slug: "dev-tooling", permission: "admin"}{name: "dev-tooling", permission: "push"}{name: "Dev Tooling", slug: "dev-tooling", permission: "admin"}{name: "My Team", permission: "admin"}{name: "My Team", slug: "my-team", permission: "admin"}{name: "new-team", permission: "push"}{name: "Old Team", slug: "old-team"}