Repository: dotnet/runtime
File: .github/skills/vmr-codeflow-status/scripts/Get-CodeflowStatus.ps1 (PowerShell)

Code before:
if (-not $isMaestroPR -and -not $isBackflow -and -not $isForwardFlow) {
    Write-Warning "This does not appear to be a codeflow PR (author: $($pr.author.login), title: $($pr.title))"
    Write-Warning "Expected author 'dotnet-maestro[bot]' and title containing 'Source code updates from'"
}

if ($isForwardFlow) {
    $sourceRepo = $Matches[1]
    Write-Status "Flow" "Forward ($sourceRepo → $Repository)" "Cyan"
}
elseif ($isBackflow) {
    Write-Status "Flow" "Backflow (dotnet/dotnet → $Repository)" "Cyan"
}

# Check for empty diff (0 changed files)
$isEmptyDiff = ($pr.changedFiles -eq 0 -and $pr.additions -eq 0 -and $pr.deletions -eq 0)
if ($isEmptyDiff) {
    Write-Host ""
    Write-Host "  📭 Empty diff: 0 changed files, 0 additions, 0 deletions" -ForegroundColor Yellow
}

# Check PR timeline for force pushes
$forcePushEvents = @()
$owner, $repo = $Repository -split '/'
$timelineJson = gh api "repos/$owner/$repo/issues/$PRNumber/timeline" --paginate --jq '[.[] | select(.event == "head_ref_force_pushed")]' 2>$null
if ($LASTEXITCODE -eq 0 -and $timelineJson) {
    $forcePushEvents = @(($timelineJson -join "`n") | ConvertFrom-Json)
}

if ($forcePushEvents.Count -gt 0) {
    Write-Host ""
    foreach ($fp in $forcePushEvents) {
        $fpActor = if ($fp.actor) { $fp.actor.login } else { "unknown" }
        $fpTime = $fp.created_at
        $fpSha = if ($fp.commit_id) { Get-ShortSha $fp.commit_id } else { "unknown" }
        Write-Host "  🔄 Force push by @$fpActor at $fpTime (→ $fpSha)" -ForegroundColor Cyan
    }
    $lastForcePush = $forcePushEvents[-1]
    $lastForcePushTime = if ($lastForcePush.created_at) {
        [DateTimeOffset]::Parse($lastForcePush.created_at).UtcDateTime
    } else { $null }
    $lastForcePushActor = if ($lastForcePush.actor) { $lastForcePush.actor.login } else { "unknown" }
}

# --- Step 2: Parse PR body metadata ---
Write-Section "Codeflow Metadata"

$body = $pr.body

# Extract subscription ID
$subscriptionId = $null
if ($body -match '\(Begin:([a-f0-9-]+)\)') {

Review comment (bug):
`gh api ... --paginate --jq '[...]'` emits one JSON array per page; joining the output and piping to `ConvertFrom-Json` will produce invalid JSON (and can terminate the script) when the timeline spans multiple pages. Consider using `gh api --paginate --slurp` (or emitting individual events with `--jq '.[] | ...'` and then slurping) so the output is a single valid JSON array, and/or wrap the parse in a try/catch to avoid aborting the whole run on parse errors.
```suggestion
$timelineJson = gh api "repos/$owner/$repo/issues/$PRNumber/timeline" --paginate --slurp --jq 'map(.[] | select(.event == "head_ref_force_pushed"))' 2>$null
if ($LASTEXITCODE -eq 0 -and $timelineJson) {
    try {
        $forcePushEvents = @($timelineJson | ConvertFrom-Json)
    }
    catch {
        Write-Verbose "Failed to parse timeline JSON for force push events: $($_.Exception.Message)"
        $forcePushEvents = @()
    }
```

Code after:
Write-Status "Branch" "$($pr.headRefName) -> $($pr.baseRefName)"
Write-Status "Created" $pr.createdAt
Write-Status "Updated" $pr.updatedAt
Write-Host "  URL: $($pr.url)"

# Check if this is actually a codeflow PR and detect flow direction
$isMaestroPR = $pr.author.login -eq "dotnet-maestro[bot]"
$isBackflow = $pr.title -match "Source code updates from dotnet/dotnet"
$isForwardFlow = $pr.title -match "Source code updates from (dotnet/\S+)" -and -not $isBackflow
if (-not $isMaestroPR -and -not $isBackflow -and -not $isForwardFlow) {
    Write-Warning "This does not appear to be a codeflow PR (author: $($pr.author.login), title: $($pr.title))"
    Write-Warning "Expected author 'dotnet-maestro[bot]' and title containing 'Source code updates from'"
}

if ($isForwardFlow) {
    $sourceRepo = $Matches[1]
    Write-Status "Flow" "Forward ($sourceRepo → $Repository)" "Cyan"
}
elseif ($isBackflow) {
    Write-Status "Flow" "Backflow (dotnet/dotnet → $Repository)" "Cyan"
}

# --- Step 2: Current State (independent assessment from primary signals) ---
Write-Section "Current State"

# Check for empty diff (0 changed files)
$isEmptyDiff = ($pr.changedFiles -eq 0 -and $pr.additions -eq 0 -and $pr.deletions -eq 0)
if ($isEmptyDiff) {
    Write-Host "  📭 Empty diff: 0 changed files, 0 additions, 0 deletions" -ForegroundColor Yellow
}

# Check PR timeline for force pushes
$forcePushEvents = @()
$owner, $repo = $Repository -split '/'
$forcePushFetchSucceeded = $false
try {
    $timelineJson = gh api "repos/$owner/$repo/issues/$PRNumber/timeline" --paginate --slurp --jq 'map(.[] | select(.event == "head_ref_force_pushed"))' 2>$null
    if ($LASTEXITCODE -eq 0 -and $timelineJson) {
        $forcePushEvents = @($timelineJson | ConvertFrom-Json)
        $forcePushFetchSucceeded = $true
    } elseif ($LASTEXITCODE -ne 0) {
        Write-Warning "Could not fetch PR timeline for force push detection (gh api exit code $LASTEXITCODE). Current state assessment may be incomplete."
    } else {
        $forcePushFetchSucceeded = $true
    }
}
catch {
    Write-Warning "Failed to parse timeline JSON for force push events: $($_.Exception.Message)"
    $forcePushEvents = @()
}