@@ -109,12 +109,23 @@ Write-Status "Created" $pr.createdAt
109109Write-Status " Updated" $pr.updatedAt
110110Write-Host " URL: $ ( $pr.url ) "
111111
112- # Check if this is actually a codeflow PR
112+ # Check if this is actually a codeflow PR and detect flow direction
113113$isMaestroPR = $pr.author.login -eq " dotnet-maestro[bot]"
114- $isCodeflowPR = $pr.title -match " Source code updates from dotnet/dotnet"
115- if (-not $isMaestroPR -and -not $isCodeflowPR ) {
114+ $isBackflow = $pr.title -match " Source code updates from dotnet/dotnet"
115+ $isForwardFlow = $pr.title -match " Source code updates from (dotnet/\S+)" -and -not $isBackflow
116+ $flowDirection = if ($isBackflow ) { " backflow" } elseif ($isForwardFlow ) { " forward" } else { " unknown" }
117+
118+ if (-not $isMaestroPR -and -not $isBackflow -and -not $isForwardFlow ) {
116119 Write-Warning " This does not appear to be a codeflow PR (author: $ ( $pr.author.login ) , title: $ ( $pr.title ) )"
117- Write-Warning " Expected author 'dotnet-maestro[bot]' and title containing 'Source code updates from dotnet/dotnet'"
120+ Write-Warning " Expected author 'dotnet-maestro[bot]' and title containing 'Source code updates from'"
121+ }
122+
123+ if ($isForwardFlow ) {
124+ $sourceRepo = $Matches [1 ]
125+ Write-Status " Flow" " Forward ($sourceRepo → $Repository )" " Cyan"
126+ }
127+ elseif ($isBackflow ) {
128+ Write-Status " Flow" " Backflow (dotnet/dotnet → $Repository )" " Cyan"
118129}
119130
120131# --- Step 2: Parse PR body metadata ---
@@ -129,12 +140,15 @@ if ($body -match '\(Begin:([a-f0-9-]+)\)') {
129140 Write-Status " Subscription" $subscriptionId
130141}
131142
132- # Extract VMR commit
133- $vmrCommit = $null
143+ # Extract source commit ( VMR commit for backflow, repo commit for forward flow)
144+ $sourceCommit = $null
134145if ($body -match ' \*\*Commit\*\*:\s*\[([a-f0-9]+)\]' ) {
135- $vmrCommit = $Matches [1 ]
136- Write-Status " VMR Commit" $vmrCommit
146+ $sourceCommit = $Matches [1 ]
147+ $commitLabel = if ($isForwardFlow ) { " Source Commit" } else { " VMR Commit" }
148+ Write-Status $commitLabel $sourceCommit
137149}
150+ # Keep $vmrCommit alias for backflow compatibility
151+ $vmrCommit = $sourceCommit
138152
139153# Extract build info
140154if ($body -match ' \*\*Build\*\*:\s*\[([^\]]+)\]\(([^\)]+)\)' ) {
@@ -147,11 +161,12 @@ if ($body -match '\*\*Date Produced\*\*:\s*(.+)') {
147161 Write-Status " Date Produced" $Matches [1 ].Trim()
148162}
149163
150- # Extract VMR branch
164+ # Extract source branch
151165$vmrBranch = $null
152166if ($body -match ' \*\*Branch\*\*:\s*\[([^\]]+)\]' ) {
153167 $vmrBranch = $Matches [1 ]
154- Write-Status " VMR Branch" $vmrBranch
168+ $branchLabel = if ($isForwardFlow ) { " Source Branch" } else { " VMR Branch" }
169+ Write-Status $branchLabel $vmrBranch
155170}
156171
157172# Extract commit diff
@@ -183,56 +198,62 @@ if (-not $vmrCommit -or -not $vmrBranch) {
183198 }
184199}
185200
186- # --- Step 3: Check VMR freshness ---
187- Write-Section " VMR Freshness"
201+ # --- Step 3: Check source freshness ---
202+ $freshnessLabel = if ($isForwardFlow ) { " Source Freshness" } else { " VMR Freshness" }
203+ Write-Section $freshnessLabel
188204
189- $vmrHeadSha = $null
205+ $sourceHeadSha = $null
190206$aheadBy = 0
191207$behindBy = 0
192208$compareStatus = $null
193209
210+ # For backflow: compare against VMR (dotnet/dotnet) branch HEAD
211+ # For forward flow: compare against product repo branch HEAD
212+ $freshnessRepo = if ($isForwardFlow ) { $sourceRepo } else { " dotnet/dotnet" }
213+ $freshnessRepoLabel = if ($isForwardFlow ) { $sourceRepo } else { " VMR" }
214+
194215if ($vmrCommit -and $vmrBranch ) {
195- # Get current VMR branch HEAD (URL-encode branch name for path segments with /)
216+ # Get current branch HEAD (URL-encode branch name for path segments with /)
196217 $encodedBranch = [uri ]::EscapeDataString($vmrBranch )
197- $vmrHead = Invoke-GitHubApi " /repos/dotnet/dotnet /commits/$encodedBranch "
198- if ($vmrHead ) {
199- $vmrHeadSha = $vmrHead .sha
200- $vmrHeadDate = $vmrHead .commit.committer.date
218+ $branchHead = Invoke-GitHubApi " /repos/$freshnessRepo /commits/$encodedBranch "
219+ if ($branchHead ) {
220+ $sourceHeadSha = $branchHead .sha
221+ $sourceHeadDate = $branchHead .commit.committer.date
201222 Write-Status " PR snapshot" " $ ( Get-ShortSha $vmrCommit ) (from PR body)"
202- Write-Status " VMR HEAD" " $ ( Get-ShortSha $vmrHeadSha ) ($vmrHeadDate )"
223+ Write-Status " $freshnessRepoLabel HEAD" " $ ( Get-ShortSha $sourceHeadSha ) ($sourceHeadDate )"
203224
204- if ($vmrCommit -eq $vmrHeadSha ) {
205- Write-Host " ✅ PR is up to date with VMR branch" - ForegroundColor Green
225+ if ($vmrCommit -eq $sourceHeadSha ) {
226+ Write-Host " ✅ PR is up to date with $freshnessRepoLabel branch" - ForegroundColor Green
206227 }
207228 else {
208- # Compare to find how many commits differ between the PR snapshot and the VMR
209- $compare = Invoke-GitHubApi " /repos/dotnet/dotnet/ compare/$vmrCommit ...$vmrHeadSha "
229+ # Compare to find how many commits differ
230+ $compare = Invoke-GitHubApi " /repos/$freshnessRepo / compare/$vmrCommit ...$sourceHeadSha "
210231 if ($compare ) {
211232 $aheadBy = $compare.ahead_by
212233 $behindBy = $compare.behind_by
213234 $compareStatus = $compare.status
214235
215236 switch ($compareStatus ) {
216237 ' ahead' {
217- Write-Host " ⚠️ VMR is $aheadBy commit(s) ahead of the PR snapshot" - ForegroundColor Yellow
238+ Write-Host " ⚠️ $freshnessRepoLabel is $aheadBy commit(s) ahead of the PR snapshot" - ForegroundColor Yellow
218239 }
219240 ' behind' {
220- Write-Host " ⚠️ VMR is $behindBy commit(s) behind the PR snapshot" - ForegroundColor Yellow
241+ Write-Host " ⚠️ $freshnessRepoLabel is $behindBy commit(s) behind the PR snapshot" - ForegroundColor Yellow
221242 }
222243 ' diverged' {
223- Write-Host " ⚠️ VMR and PR snapshot have diverged: VMR is $aheadBy commit(s) ahead and $behindBy commit(s) behind" - ForegroundColor Yellow
244+ Write-Host " ⚠️ $freshnessRepoLabel and PR snapshot have diverged: $aheadBy commit(s) ahead and $behindBy commit(s) behind" - ForegroundColor Yellow
224245 }
225246 default {
226- Write-Host " ⚠️ VMR and PR snapshot differ (status: $compareStatus )" - ForegroundColor Yellow
247+ Write-Host " ⚠️ $freshnessRepoLabel and PR snapshot differ (status: $compareStatus )" - ForegroundColor Yellow
227248 }
228249 }
229250
230251 if ($ShowCommits -and $compare.commits ) {
231252 Write-Host " "
232253 $commitLabel = switch ($compareStatus ) {
233254 ' ahead' { " Commits since PR snapshot:" }
234- ' behind' { " Commits in PR snapshot but not in VMR :" }
235- default { " Commits differing between VMR and PR snapshot :" }
255+ ' behind' { " Commits in PR snapshot but not in $freshnessRepoLabel ` :" }
256+ default { " Commits differing:" }
236257 }
237258 Write-Host " $commitLabel " - ForegroundColor Yellow
238259 foreach ($c in $compare.commits ) {
@@ -263,7 +284,7 @@ if ($vmrCommit -and $vmrBranch) {
263284 }
264285}
265286else {
266- Write-Warning " Cannot check VMR freshness without VMR commit and branch info"
287+ Write-Warning " Cannot check freshness without source commit and branch info"
267288}
268289
269290# --- Step 4: Check staleness warnings (using comments from gh pr view) ---
@@ -287,7 +308,8 @@ if ($pr.comments) {
287308if ($stalenessWarnings.Count -gt 0 ) {
288309 Write-Host " ⚠️ Staleness warning detected ($ ( $stalenessWarnings.Count ) warning(s))" - ForegroundColor Yellow
289310 Write-Status " Latest warning" $lastStalenessComment.createdAt
290- Write-Host " The VMR received opposite codeflow (forward flow merged) while this PR was open." - ForegroundColor Yellow
311+ $oppositeFlow = if ($isForwardFlow ) { " backflow from VMR merged into $sourceRepo " } else { " forward flow merged into VMR" }
312+ Write-Host " Opposite codeflow ($oppositeFlow ) while this PR was open." - ForegroundColor Yellow
291313 Write-Host " Maestro has blocked further codeflow updates to this PR." - ForegroundColor Yellow
292314
293315 # Extract darc commands from the warning
@@ -473,12 +495,12 @@ if ($stalenessWarnings.Count -gt 0) {
473495 $issues += " Staleness warning active — codeflow is blocked"
474496}
475497
476- if ($vmrCommit -and $vmrHeadSha -and $vmrCommit -ne $vmrHeadSha ) {
498+ if ($vmrCommit -and $sourceHeadSha -and $vmrCommit -ne $sourceHeadSha ) {
477499 switch ($compareStatus ) {
478- ' ahead' { $issues += " VMR is $aheadBy commit(s) ahead of PR snapshot" }
479- ' behind' { $issues += " VMR is $behindBy commit(s) behind PR snapshot" }
480- ' diverged' { $issues += " VMR and PR snapshot diverged ($aheadBy ahead, $behindBy behind)" }
481- default { $issues += " VMR and PR snapshot differ" }
500+ ' ahead' { $issues += " $freshnessRepoLabel is $aheadBy commit(s) ahead of PR snapshot" }
501+ ' behind' { $issues += " $freshnessRepoLabel is $behindBy commit(s) behind PR snapshot" }
502+ ' diverged' { $issues += " $freshnessRepoLabel and PR snapshot diverged ($aheadBy ahead, $behindBy behind)" }
503+ default { $issues += " $freshnessRepoLabel and PR snapshot differ" }
482504 }
483505}
484506
0 commit comments