Skip to content

fix(pr-docs-check): remove duplicate aspire.dev checkout that broke create_pull_request branch pinning - #18320

Merged
Ankit Jain (radical) merged 1 commit into
microsoft:mainfrom
radical:radical/fix-pr-docs-check-base-branch
Jun 25, 2026
Merged

fix(pr-docs-check): remove duplicate aspire.dev checkout that broke create_pull_request branch pinning#18320
Ankit Jain (radical) merged 1 commit into
microsoft:mainfrom
radical:radical/fix-pr-docs-check-base-branch

Conversation

@radical

Copy link
Copy Markdown
Member

What broke

The pr-docs-check agentic workflow failed on run 27765082872 (source PR #18312, milestone 13.5). Every create_pull_request attempt died at the branch-pin step:

Failed to pin branch 'docs/aspire-18312-chart-calculator-refactor' before bundle generation: ERR_SYSTEM: fatal: Needed a single revision

No docs PR was opened on microsoft/aspire.dev.

Root cause

Not the base-branch / milestone resolution — that part was correct. The resolver emitted effective_target_branch=release/13.5 (resolution=exact_match), release/13.5 exists on aspire.dev, and the agent based the docs branch on it correctly.

The real defect is a duplicate checkout. The agent job checked out microsoft/aspire.dev twice:

  • once as the current workspace (path: "") — where the agent authors docs and creates the docs branch, and
  • once as a mirror at _repos/aspire.dev.

gh-aw builds a checkout manifest keyed by the lowercased repo slug with last-wins semantics (build_checkout_manifest.cjs). The mirror entry shadowed the workspace entry, so create_pull_request's findRepoCheckout("microsoft/aspire.dev") resolved to the mirror. The pin step then ran:

git -C _repos/aspire.dev rev-parse --verify refs/heads/<branch>^{commit}

against the mirror, where the docs branch never existed → fatal: Needed a single revision.

(The agent's own logged hypothesis — a git remote-URL mismatch — is a red herring: findRepoCheckout consults the manifest first and only falls back to a git scan, so the duplicate-slug shadowing is the operative bug.)

The fix

Remove the redundant _repos/aspire.dev mirror from the agent-job checkout: block, leaving a single microsoft/aspire.dev -> path: "" entry that resolves to the workspace where the docs branch is actually created.

The mirror was unnecessary: the manifest already maps the current workspace for the slug, so the handler can rediscover the target repo without it.

Call-outs

  • The safe-outputs job keeps its own independent _repos/aspire.dev checkout for bundle apply — that's a different job and is left untouched.
  • Lock file regenerated with gh aw compile (v0.79.8, 0 error(s), 0 warning(s)); the only .lock.yml changes are dropping the second checkout/app-token steps and GH_AW_CHECKOUT_MANIFEST_COUNT: 2 -> 1. actions-lock.json is unchanged.
  • Distinct from Improve pr-docs-check reliability guidance #17552 ("Improve pr-docs-check reliability guidance"), which touches the same file but explicitly leaves branch resolution unchanged and does not address this pin failure.

Fixes #18319
Refs #18223

…reate_pull_request branch pinning

The pr-docs-check agentic workflow failed on run 27765082872 (source PR
microsoft#18312) when the create_pull_request safe-output could
not pin the docs branch before generating its bundle:

    Failed to pin branch 'docs/aspire-18312-chart-calculator-refactor'
    before bundle generation: ERR_SYSTEM: fatal: Needed a single revision

Root cause: the agent-job checked out microsoft/aspire.dev twice -- once
as the current workspace (path "") where the agent authors docs and
creates the docs branch, and once as a mirror at _repos/aspire.dev.
gh-aw builds a checkout manifest keyed by the lowercased repo slug with
last-wins semantics (build_checkout_manifest.cjs), so the mirror entry
shadowed the workspace entry. create_pull_request's
findRepoCheckout("microsoft/aspire.dev") then resolved to the mirror,
and the pin step ran

    git -C _repos/aspire.dev rev-parse --verify refs/heads/<branch>^{commit}

against the mirror, where the branch never existed -> "Needed a single
revision".

The resolver and base-branch selection were NOT at fault: it emitted
effective_target_branch=release/13.5 (resolution=exact_match), that
branch exists on aspire.dev, and the agent used it correctly. The only
defect was the duplicate checkout shadowing the workspace.

Fix: drop the redundant _repos/aspire.dev mirror from the agent-job
checkout block so a single microsoft/aspire.dev -> path="" entry resolves
to the workspace where the docs branch is created. The safe-outputs job
keeps its own independent _repos/aspire.dev checkout for bundle apply, so
that path is unaffected. Regenerated the lock file (gh aw compile,
v0.79.8, clean).

Fixes microsoft#18319
Refs microsoft#18223

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 18320

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 18320"

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a bug in the pr-docs-check agentic workflow where create_pull_request failed with fatal: Needed a single revision because microsoft/aspire.dev was checked out twice in the agent job — once as the workspace and once as a mirror under _repos/aspire.dev. The gh-aw checkout manifest uses last-wins semantics keyed by lowercased repo slug, so the mirror entry shadowed the workspace entry, causing the branch-pin step to look for the docs branch in the mirror (where it didn't exist).

Changes:

  • Removed the redundant _repos/aspire.dev mirror checkout (and its app-token generation step) from the agent job's checkout: block, leaving a single microsoft/aspire.dev → path="" workspace entry.
  • Updated the inline comment to document why a second microsoft/aspire.dev checkout must not be added to this block, and updated the agent prompt note to reflect the single-checkout setup.
  • Regenerated the lock file (gh aw compile), reflecting the removal of the duplicate checkout steps and manifest count change from 2 to 1.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
.github/workflows/pr-docs-check.md Removed the duplicate microsoft/aspire.dev mirror checkout from the agent job, added a detailed explanatory comment about the last-wins manifest behavior, and updated the agent prompt note.
.github/workflows/pr-docs-check.lock.yml Auto-regenerated lock file reflecting the removal: updated metadata hashes, removed the second checkout + app-token steps, reduced GH_AW_CHECKOUT_MANIFEST_COUNT from "2" to "1", and dropped the mirror from the checkouts prompt.

@radical

Copy link
Copy Markdown
Member Author

PR Testing Report — CI Infrastructure Validation

PR Information

Artifact Version Verification

  • Validation method: Source checkout at PR head + gh-aw recompile (no CLI artifact involved for an infra-only PR).
  • gh-aw compiler: gh aw v0.79.8 locally — same compiler_version recorded in the PR's lock file.
  • Status: ✅ Verified — recompiling pr-docs-check.md at PR head reproduces the committed pr-docs-check.lock.yml byte-for-byte (zero drift), proving the lock was generated by the compiler and not hand-edited.

Changes Analyzed

Files Changed (2 files, +32 / -50)

  • .github/workflows/pr-docs-check.md — gh-aw source (human-edited). Removes the second microsoft/aspire.dev checkout block (path: _repos/aspire.dev) and its app-token step from the agent job; rewrites the rationale comment to explain the single workspace checkout and the last-wins manifest bug.
  • .github/workflows/pr-docs-check.lock.yml — generated lock. Drops the duplicate checkout + app-token steps and flips GH_AW_CHECKOUT_MANIFEST_COUNT from 21.

Change Categories

  • CLI changes
  • Hosting integration changes
  • Dashboard changes
  • CI infrastructure changes (GitHub Actions — gh-aw workflow)
  • Azure DevOps pipeline changes
  • VS Code extension changes
  • Test changes

CI Infrastructure Validation

What runs on this PR

  • pr-docs-check itself triggers only on PR close/merge (pull_request: [closed], gated merged == true) and workflow_dispatch. It does not run on PR open, so this PR's own CI does not exercise the workflow end-to-end.
  • Both changed files match CI-skip globs in eng/testing/github-ci-trigger-patterns.txt:
    • pr-docs-check.md**.md (line 25)
    • pr-docs-check.lock.yml.github/workflows/*.lock.yml (line 62)
    • Since every changed file matches a skip glob, ci.yml's build/test job (and therefore Infrastructure.Tests) is skipped on this PR. This is correct behavior — there is no product code to build or test.

Automated tests

  • No automated coverage exists for pr-docs-check. There is no dedicated test class and no generic gh-aw lock-drift / workflow-parse contract test in tests/Infrastructure.Tests/ (the only workflow-script tests cover auto-rerun-transient-ci-failures and create-failing-test-issue). This is expected for gh-aw workflows, which are validated by recompile + real runs rather than unit tests. Recorded as a known gap, not a regression introduced by this PR.

Static validation performed (all ✅)

  • YAML parse: both pr-docs-check.md front-matter and pr-docs-check.lock.yml parse cleanly.
  • Recompile invariant (load-bearing): gh aw compile at PR head → 0 errors, 0 warnings, and zero diff vs the committed lock.
  • Trigger/permission/gating audit: no on:, permissions:, if:, or needs: changes — the only differences besides the removed steps are comment text. Activation gate (merged == true || workflow_dispatch, repository_owner == 'microsoft') is unchanged.
  • Whitespace / conflict markers: clean.

Results validation (root cause confirmed against primary source)

  • Root cause verified in github/gh-aw build_checkout_manifest.cjs (last-wins) and find_repo_checkout.cjs (manifest-first), both confirmed present in the pinned v0.79.8 runtime: the manifest is built as manifest[repo.toLowerCase()] = {…path} in entry order → last-wins for a repeated repo slug (build_checkout_manifest.cjs:120). Two microsoft/aspire.dev entries meant the _repos/aspire.dev mirror shadowed the path:"" workspace entry; findRepoCheckout (manifest-first, find_repo_checkout.cjs@v0.79.8:192, per the patch-find-repo-checkout-manifest-first changeset) then resolved docs operations to the mirror, where the docs branch never existed, and the branch-pin step failed with fatal: Needed a single revision.
  • On the failing command: the literal failing invocation is the safe-outputs MCP server's "pin branch before bundle generation" step (per [aw] PR Documentation Check reported incomplete result #18319: "Failed to pin branch '…' before bundle generation: ERR_SYSTEM: fatal: Needed a single revision"). That code is in gh-aw's MCP server, not the readable .cjs runtime files, so the exact git -C _repos/aspire.dev rev-parse --verify … form is a faithful reconstruction of the mechanism, not a source-quoted command. The signature and the failing directory (_repos/aspire.dev) are what [aw] PR Documentation Check reported incomplete result #18319 reports.
  • Reconciliation with [aw] PR Documentation Check reported incomplete result #18319's stated cause: the issue's headline diagnosis is a remote-URL mismatch — the workspace .git/config origin points at microsoft/aspire.git, not aspire.dev. That is a symptom, not the root cause. The agent job's unchanged "Configure Git credentials" step deliberately rewrites origin to ${{ github.repository }}.git (= microsoft/aspire.git); manifest-first resolution already neutralizes that rewrite by keying on the repo slug, not the remote. The true fault is the shadowed duplicate manifest entry, which [aw] PR Documentation Check reported incomplete result #18319's own body corroborates ("the _repos/aspire.dev mirror is on main and does not have the release content"). The fix targets the real cause.
  • Why no live run is needed — the actual invariant: with the duplicate removed, the generated manifest is COUNT=1, REPO_0=microsoft/aspire.dev, PATH_0="". The fix is sound specifically because manifest-first resolution (present in v0.79.8) returns the path:"" workspace despite the credential-rewrite step having pointed origin at aspire.gitfindRepoCheckout's git-scan fallback matches by remote URL and would not match microsoft/aspire.dev, so the manifest lookup is load-bearing. Post-fix there is exactly one aspire.dev checkout (the workspace, where the staged docs branch exists), so the lookup resolves there and branch pinning succeeds. This depends on the pinned-runtime manifest-first behavior, which was verified, rather than on bare "the manifest has one entry."

Failure-modes §6 (gh-aw) scan — all pass

  1. Stale lock (lock not regenerated after editing .md) → recompile shows zero diff ✅
  2. Cross-repo safe_outputs checkout needs explicit path: (Fix pr-docs safe outputs checkout path #15960) → the safe_outputs job keeps its own independent _repos/aspire.dev checkout with an explicit path: (untouched by this PR). The fix only removes the agent-job duplicate. ✅
  3. Compiler stripping manual lock overrides → clean recompile means there were no manual overrides to lose. ✅
  4. Deterministic branch resolution before agent steps (Make pr-docs-check target-branch resolution deterministic and prefer latest aspire.dev release branch #16950) → the PR does not touch the release/X.Y resolver shell block; it remains intact. ✅

Manual / live triggers

  • Not performed. pr-docs-check is a real-side-effect workflow: a real run creates an actual PR on microsoft/aspire.dev and there is no dry_run input. The activation gate github.repository_owner == 'microsoft' means it cannot be validated on a fork — a live run would require pushing the branch to upstream microsoft/aspire and maintainer approval, and would produce a real docs PR. Per the ci-infra-testing.md Step I-4 guidance for side-effecting workflows, a live dispatch was not run without explicit authorization.

Summary

Check Status Notes
Recompile zero-drift Lock matches compiler output exactly
YAML parse Source + lock both valid
Trigger/permission/gating audit Only comment text differs
§6 gh-aw failure-modes scan All 4 gotchas checked; safe_outputs path preserved
Root cause vs gh-aw source last-wins + manifest-first confirmed in v0.79.8; reconciled with #18319 symptom
Automated test coverage ⚠️ None exists for pr-docs-check (expected for gh-aw)
Live workflow_dispatch run ⏭️ Skipped — real side effects, org-gated, needs maintainer approval

Overall Result

✅ PR VERIFIED (static + recompile + source-confirmed).

The fix is correct, minimal, and well-scoped. The generated lock is in sync, no triggers/permissions/gating changed, the safe_outputs cross-repo checkout invariant is preserved, and the corrected single-entry manifest resolves microsoft/aspire.dev to the workspace where branch pinning succeeds — relying on manifest-first resolution (verified present in v0.79.8) to win over the credential-rewritten origin. The only residual is end-to-end confirmation via a real pr-docs-check run, which carries real side effects on microsoft/aspire.dev and was deliberately not triggered.

Independent cross-check: these conclusions were re-verified by a separate rubber-duck critique (Opus 4.8, high) against gh-aw source at both main and the pinned v0.79.8 tag, plus a fresh lock-drift recompile from a clean PR-head checkout (sha256 identical, git status clean). The critique found no blocking issue; its three refinements (name the manifest-first linchpin, mark the failing command as a reconstruction, reconcile root cause with #18319's symptom) are incorporated above. Note _repos/aspire (source repo microsoft/aspire, consumed by compute_signals.py) is a different checkout that the agent job correctly retains — only _repos/aspire.dev was removed.

Recommendations

  • Land on static + recompile evidence; let the first post-merge pr-docs-check run on a real merged PR serve as the live confirmation (it self-validates on the next significant-docs PR).
  • Optional follow-up (not blocking): consider a lightweight gh-aw lock-drift contract test in Infrastructure.Tests so future .md/.lock.yml skew is caught automatically.

@IEvangelist David Pine (IEvangelist) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought there was a limitation that I seem to remember with the gh aw that required the dual checkout. I guess, we can try this to see if it works now.

@radical
Ankit Jain (radical) merged commit 4aca535 into microsoft:main Jun 25, 2026
9 checks passed
@github-actions github-actions Bot added this to the 13.5 milestone Jun 25, 2026
@radical
Ankit Jain (radical) deleted the radical/fix-pr-docs-check-base-branch branch June 25, 2026 18:44
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 26, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[aw] PR Documentation Check reported incomplete result

3 participants