Improve vmr-codeflow-status skill: current-state-first analysis, force push & empty diff detection#124231
Conversation
…and post-action state Add three improvements based on investigating a stale codeflow PR: 1. Force push detection - Query PR timeline for head_ref_force_pushed events, showing who force-pushed and when. 2. Empty diff detection - Check changedFiles/additions/deletions from the PR API to flag 0-change PRs that are effectively no-ops. 3. Post-action staleness analysis - Cross-reference force push timestamps against conflict/staleness warnings. When a force push post-dates these warnings and produces an empty diff, the PR is identified as a no-op with tailored recommendations (merge empty, close, or force-trigger).
There was a problem hiding this comment.
Pull request overview
Updates the vmr-codeflow-status Copilot CLI skill to better diagnose codeflow PR state transitions by detecting force-pushes, recognizing empty/no-op PR diffs, and refining recommendations when warnings have likely already been acted on.
Changes:
- Adds PR “empty diff” detection using
changedFiles/additions/deletionsfromgh pr view. - Queries the PR timeline for
head_ref_force_pushedevents and reports actor/time/SHA. - Cross-references force-push timestamps against conflict/staleness warning timestamps to adjust recommendations (merge/close/force-trigger vs resolve-conflict).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
.github/skills/vmr-codeflow-status/scripts/Get-CodeflowStatus.ps1 |
Adds force-push timeline querying, empty-diff detection, and post-action staleness/conflict analysis to refine recommendations. |
.github/skills/vmr-codeflow-status/SKILL.md |
Documents the new force-push and empty-diff detection behavior and adds guidance for “Maestro may be stuck” scenarios. |
.github/skills/vmr-codeflow-status/scripts/Get-CodeflowStatus.ps1
Outdated
Show resolved
Hide resolved
Inspired by the code-review skill pattern (PR dotnet#124229), restructure the codeflow analysis to form an independent assessment from primary signals before consulting Maestro comments: - New 'Current State' section (Step 2) synthesizes empty diff, force push events, and activity recency into an immediate verdict: NO-OP / IN PROGRESS / STALE / ACTIVE - PR Branch Analysis now appears before comments, providing commit categorization as primary data - Renamed 'Staleness & Conflict Check' to 'Codeflow History' to clearly signal these are past events, not current state. Framing line directs reader to Current State for present status. - Recommendations driven by current state assessment, with comment history as supporting context The principle: comments tell you the history, not the present. Determine the PR's actual state from primary signals (diff, branch, timeline) before consulting Maestro comments for context.
- Current State now checks PR state first: MERGED and CLOSED override all other heuristics (force push, staleness, etc.) - Empty diff alone is now sufficient for NO-OP verdict (previously required both empty diff AND force push) - Recommendations are state-aware: skip merge/close advice for already-terminal PRs - Updated SKILL.md with MERGED/CLOSED state documentation Fixes consensus findings from multi-model review (Claude Sonnet 4, GPT-5).
Use --slurp to merge paginated results into a single JSON array before filtering, avoiding invalid JSON when timeline spans multiple pages. Add try/catch for parse resilience. Addresses Copilot review comment.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
.github/skills/vmr-codeflow-status/scripts/Get-CodeflowStatus.ps1:1523
- The closing-brace comment
# end of else (non-terminal state)appears to annotate the wrongelseblock (it actually closes the$issues.Count -eq 0branch). Consider updating/removing the comment (and/or re-indenting the nested blocks) to avoid confusion when modifying this section later.
Write-Host " 1. Wait — Maestro should auto-update the PR" -ForegroundColor White
Write-Host " 2. Trigger manually — if auto-updates seem delayed" -ForegroundColor White
if ($subscriptionId) {
The script's Step 9 (Recommendations) was 130+ lines of hardcoded if/elseif branching logic reasoning about state combinations. This is exactly what LLMs do better — given structured facts, produce contextual advice. Changes: - Script now emits a [CODEFLOW_SUMMARY] JSON block with all key facts (currentState, freshness, warnings, commits, etc.) - Removed hardcoded recommendations from script - Added 'Generating Recommendations' section to SKILL.md that teaches the agent how to reason over the JSON summary - Agent synthesizes contextual, nuanced recommendations instead of canned text from a decision tree The script still produces full human-readable output for Steps 1-8. The JSON summary is the structured handoff point where the agent takes over for the reasoning-heavy final step.
…exit code Multi-model testing (Claude Sonnet 4, GPT-5) identified 5 issues: - Add isCodeflowPR boolean to JSON summary for explicit classification - isUpToDate is now null (not false) when freshness data unavailable - daysSinceUpdate clamped to 0 minimum (was negative due to clock skew) - Script exits 0 on completion (gh api failures leaked LASTEXITCODE=1) - SKILL.md: non-codeflow PRs skip all darc command suggestions
.github/skills/vmr-codeflow-status/scripts/Get-CodeflowStatus.ps1
Outdated
Show resolved
Hide resolved
.github/skills/vmr-codeflow-status/scripts/Get-CodeflowStatus.ps1
Outdated
Show resolved
Hide resolved
- Collapse duplicate isEmptyDiff check (with/without force push both returned NO-OP) - Rename lastWarnTime2 to lastStalenessTime for consistency
Force-trigger overwrites the existing PR branch; it does not create a new PR. A normal trigger after closing does create a new PR. Added a table and warning to prevent the common mistake of recommending 'close then force-trigger'.
.github/skills/vmr-codeflow-status/scripts/Get-CodeflowStatus.ps1
Outdated
Show resolved
Hide resolved
.github/skills/vmr-codeflow-status/scripts/Get-CodeflowStatus.ps1
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
.github/skills/vmr-codeflow-status/scripts/Get-CodeflowStatus.ps1:176
- In
Get-CodeflowPRHealth, clearingHasStalenessdepends on successfully fetching/parsinggh pr checks(the commit-date comparison is nested under the$checksJsonblock). Ifgh pr checksfails/returns nothing (auth/rate limit), staleness will remain flagged even when the PR has commits newer than the last staleness warning. Consider running the “last commit after last warning” check independently ofgh pr checks(and independently of mergeability), using the already-fetched comments + agh pr view --json commitscall guarded withtry/catch/exit-code checks.
$checksJson = gh pr checks $PRNumber -R $Repo --json name,state 2>$null
if ($LASTEXITCODE -eq 0 -and $checksJson) {
try {
$checks = ($checksJson -join "`n") | ConvertFrom-Json
$codeflowCheck = @($checks | Where-Object { $_.name -match 'Codeflow verification' }) | Select-Object -First 1
if (($codeflowCheck -and $codeflowCheck.state -eq 'SUCCESS') -or $isMergeable) {
# No merge conflict — either Codeflow verification passes or PR is mergeable
$hasConflict = $false
# For staleness, check if there are commits after the last staleness warning
if ($hasStaleness) {
$commitsJson = gh pr view $PRNumber -R $Repo --json commits --jq '.commits[-1].committedDate' 2>$null
if ($LASTEXITCODE -eq 0 -and $commitsJson) {
$lastCommitTime = ($commitsJson -join "").Trim()
$lastWarnTime = $null
foreach ($comment in $prDetail.comments) {
if ($comment.author.login -match '^dotnet-maestro' -and $comment.body -match 'codeflow cannot continue|the source repository has received code changes') {
$warnDt = [DateTimeOffset]::Parse($comment.createdAt).UtcDateTime
if (-not $lastWarnTime -or $warnDt -gt $lastWarnTime) {
$lastWarnTime = $warnDt
}
}
}
$commitDt = if ($lastCommitTime) { [DateTimeOffset]::Parse($lastCommitTime).UtcDateTime } else { $null }
if ($lastWarnTime -and $commitDt -and $commitDt -gt $lastWarnTime) {
$hasStaleness = $false
}
}
Addresses review comment: when gh api .../timeline fails, emit Write-Warning so the user knows force push data is missing, and add forcePushes.fetchSucceeded boolean to the JSON summary so recommendation logic can account for incomplete timeline data.
This improves the vmr-codeflow-status Copilot CLI skill with enhancements discovered while investigating a stale codeflow PR (#124095).
Design Change: Current State First
Inspired by the code-review skill restructuring in #124229, the analysis now follows a "current state first, comments as history" pattern:
Previously, the script read Maestro conflict/staleness comments first and drew conclusions from them — even when those comments were stale (e.g., after someone had already force-pushed a resolution). Recommendations were a 130-line if/elseif chain that couldn't adapt to edge cases.
New Capabilities
1. Current State Assessment (Step 2)
Synthesizes primary signals into an immediate verdict before any comment parsing:
✅ MERGED— PR has been merged, no action needed✖️ CLOSED— PR was closed without merging, Maestro should create a replacement📭 NO-OP— empty diff, likely already resolved🔄 IN PROGRESS— recent force push, awaiting update⏳ STALE— no activity for >3 days✅ ACTIVE— PR has content and recent activity2. Force Push Detection
Queries PR timeline for
head_ref_force_pushedevents, showing who force-pushed and when. Uses--slurpfor correct pagination handling.3. Empty Diff Detection
Checks
changedFiles/additions/deletionsto flag 0-change PRs as NO-OP (regardless of whether a force push caused it).4. Post-Action Staleness Analysis
Cross-references force push timestamps against conflict/staleness warnings. When a force push post-dates these warnings, the script correctly identifies the issues as potentially resolved.
5. JSON Summary + Agent-Generated Recommendations
The script's hardcoded recommendations (130+ lines of branching logic) have been replaced with:
[CODEFLOW_SUMMARY]JSON block emitted at the end of the script with all key factsisCodeflowPRboolean for explicit codeflow vs non-codeflow classification6. Codeflow History (renamed section)
The former "Staleness & Conflict Check" is now "Codeflow History" with a framing line: "Maestro warnings (historical — see Current State for present status)". This signals that comments describe past events, not necessarily current state.
Testing
--slurppagination fixisUpToDatenull handling, negativedaysSinceUpdate, addedisCodeflowPRfield, clean exit codes, non-codeflow guidance in SKILL.md