Skip to content

Add upstream-sync agent skill (cherry-pick from microsoft/terminal)#218

Open
yeelam-gordon wants to merge 81 commits into
mainfrom
dev/yeelam/upstream-sync-skill
Open

Add upstream-sync agent skill (cherry-pick from microsoft/terminal)#218
yeelam-gordon wants to merge 81 commits into
mainfrom
dev/yeelam/upstream-sync-skill

Conversation

@yeelam-gordon

@yeelam-gordon yeelam-gordon commented Jun 4, 2026

Copy link
Copy Markdown
Collaborator

Adds the upstream-sync agent skill: a cherry-pick-per-commit pipeline that periodically pulls new commits from microsoft/terminal into this fork, preserving the original author, committer, and dates on every commit.

What's in this PR

  • .github/skills/upstream-sync/ — full skill (SKILL.md + references + scripts).
  • No .github/upstream-sync/ directory and no state.json. The skill derives all state from authoritative sources:
    • Watermark = the most recent (cherry picked from commit <sha>) trailer on origin/main that is an ancestor of upstream/main.
    • Stuck lock = an open GitHub issue with the upstream-sync-stuck label. Closing the issue clears the lock; the issue body is plain markdown (stuck SHA, upstream URL, author, branch, conflicting paths) — no machine-parseable metadata.
    • Pending list = git log --cherry-pick --right-only origin/main...upstream/main, then drop ancestors of the watermark.
  • Transient artifacts (reports, build logs) go to Generated Files/upstream-sync/<date>/, which is gitignored at the repo root and never committed.
  • .github/actions/spelling/excludes.txt now excludes the whole .github/skills/ tree from spell-check (per reviewer feedback that skill docs naturally contain technical strings the project-wide allow/expect lists shouldn't have to track).

Why cherry-pick (not rebase / not merge)

  • Rebase was tried on the sister agentic-terminal repo and blew up because the fork's own Merge upstream commits get replayed and conflict against themselves.
  • Merge loses the per-commit attribution.
  • Cherry-pick preserves per-commit content and identity; revert-pairs in the pending range and empty picks are auto-dropped.

Verified

  • 5-commit smoke test on a synthetic baseline: every author/committer/date — including TZ offsets — matched upstream character-for-character.
  • All scripts parse-clean.
  • Code-review and rubber-duck sub-agent passes; multiple Copilot review rounds.

Merge method

⚠️ PLEASE USE REBASE-MERGE OR MERGE-COMMIT — NOT SQUASH for the follow-up sync PRs this skill creates. Squash would destroy the per-commit attribution the whole design exists to preserve. (This PR itself is fine to squash.)

First-time sync

Because the watermark comes from a cherry picked from commit trailer, a freshly bootstrapped fork needs one seed commit. SKILL.md → "First-time sync" walks through it: one git commit --allow-empty with the trailer pointing at the upstream SHA the fork was branched from. No scripted bootstrap, no state file.

Concurrency

The stuck-lock (open labeled issue) is a read-then-check gate. The skill assumes a single scheduler host. For multi-host fan-out, wrap the runner in a GitHub Actions concurrency: upstream-sync group.

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

Cherry-picks new commits from microsoft/terminal into this fork one at a
time, preserving per-commit author/committer/dates (verified by smoke
test: 5 picks from upstream/main~5..upstream/main matched character-for-
character including timezone offsets).

Pipeline (scheduler-friendly, resumable):
  fetch upstream -> compute pending (drop revert pairs + empties)
    -> branch upstream-sync/YYYY-MM-DD -> cherry-pick loop
    -> always write report -> open PR (or push direct to main)

Safety:
  - state.json checkpoint (last_synced_upstream_sha + stuck-lock)
  - Tier-0 known-take-upstream auto-resolve (seed: spelling2.yml)
  - Stuck -> abort, open GitHub issue, set lock, exit 10 (not an error)
  - 'DO NOT squash' banner on PR body; -AutoMergeStrategy rebase arms
    gh auto-merge with the correct strategy

Bootstrap: baseline = a325a2f ('Fix settings error text legibility in
High Contrast mode' #20098), the merge-base between fork main and
upstream/main on 2026-06-04. 16 upstream commits currently pending; the
first real sync run will be a follow-up PR after this one merges.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 4, 2026 06:14
@yeelam-gordon yeelam-gordon enabled auto-merge (rebase) June 4, 2026 06:14
Comment thread .github/skills/upstream-sync/references/bootstrap.md Fixed
Comment thread .github/skills/upstream-sync/references/bootstrap.md Fixed
Comment thread .github/skills/upstream-sync/references/bootstrap.md Fixed
Comment thread .github/skills/upstream-sync/references/bootstrap.md Fixed
Comment thread .github/skills/upstream-sync/references/conflict-triage.md Fixed
Comment thread .github/skills/upstream-sync/references/workflow.md Fixed
Comment thread .github/skills/upstream-sync/scripts/03-cherry-pick-one.ps1 Fixed
Comment thread .github/skills/upstream-sync/scripts/03-cherry-pick-one.ps1 Fixed
Comment thread .github/skills/upstream-sync/scripts/06b-finalize-direct.ps1 Fixed
Comment thread .github/skills/upstream-sync/scripts/Common.ps1 Fixed

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

Adds an upstream-sync Agent Skill to periodically cherry-pick commits from microsoft/terminal into this repo with stateful tracking (state.json) and automated reporting.

Changes:

  • Introduces .github/skills/upstream-sync/ with PowerShell scripts to fetch upstream, compute pending commits, cherry-pick with basic auto-resolution, and open PRs/issues.
  • Adds reference documentation describing bootstrap, workflow, conflict triage tiers, reporting, known conflict rules, and the state.json schema.
  • Bootstraps .github/upstream-sync/state.json plus a reports folder placeholder.

Reviewed changes

Copilot reviewed 19 out of 20 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
.github/upstream-sync/state.json Initial sync state (baseline SHA, lock fields, history).
.github/upstream-sync/reports/.gitkeep Ensures reports directory is present in git.
.github/skills/upstream-sync/SKILL.md Skill definition + operator-facing workflow, gotchas, and usage.
.github/skills/upstream-sync/scripts/Common.ps1 Shared helpers for repo root/state/report paths and JSON read/write.
.github/skills/upstream-sync/scripts/00-bootstrap.ps1 One-time state initialization (baseline SHA) on a dedicated branch.
.github/skills/upstream-sync/scripts/01-fetch-upstream.ps1 Creates/fetches the upstream remote and resolves upstream HEAD SHA.
.github/skills/upstream-sync/scripts/02-compute-pending.ps1 Computes pending commit list and drops revert pairs / empty commits.
.github/skills/upstream-sync/scripts/03-cherry-pick-one.ps1 Performs one cherry-pick with Tier-0/Tier-1 conflict handling and JSON status output.
.github/skills/upstream-sync/scripts/04-run-batch.ps1 Orchestrates a full run: gate on lock, pick loop, report, finalize.
.github/skills/upstream-sync/scripts/05-write-report.ps1 Produces Markdown run reports used as PR/issue bodies.
.github/skills/upstream-sync/scripts/06-finalize-pr.ps1 Commits state+report, pushes branch, opens PR, optionally arms auto-merge.
.github/skills/upstream-sync/scripts/06b-finalize-direct.ps1 Optional direct fast-forward of main to the sync branch.
.github/skills/upstream-sync/scripts/07-open-stuck-issue.ps1 Pushes stuck branch, opens an issue, sets stuck-lock on main, copies report.
.github/skills/upstream-sync/scripts/clear-stuck.ps1 Clears stuck-lock after manual resolution has been merged.
.github/skills/upstream-sync/references/workflow.md Authoritative step-by-step workflow and exit code semantics.
.github/skills/upstream-sync/references/state-schema.md state.json schema and operational/concurrency notes.
.github/skills/upstream-sync/references/reporting.md Report + stuck-issue templates and retention rationale.
.github/skills/upstream-sync/references/known-conflicts.md Tier-0 “known resolution” list format and guidance.
.github/skills/upstream-sync/references/conflict-triage.md Tiered conflict-resolution rubric, including line-ending cautions.
.github/skills/upstream-sync/references/bootstrap.md Baseline SHA discovery approaches and bootstrap procedure.

Comment thread .github/skills/upstream-sync/SKILL.md
Comment thread .github/skills/upstream-sync/SKILL.md Outdated
Comment thread .github/skills/upstream-sync/SKILL.md Outdated
Comment thread .github/skills/upstream-sync/references/workflow.md Outdated
Comment thread .github/skills/upstream-sync/scripts/Common.ps1 Outdated
Comment thread .github/skills/upstream-sync/scripts/clear-stuck.ps1 Outdated
Comment thread .github/skills/upstream-sync/scripts/clear-stuck.ps1 Outdated
Comment thread .github/skills/upstream-sync/scripts/03-cherry-pick-one.ps1 Outdated
Comment thread .github/skills/upstream-sync/scripts/06b-finalize-direct.ps1 Outdated
Comment thread .github/skills/upstream-sync/SKILL.md Outdated
@github-actions

This comment has been minimized.

…kill

Closes the PR #220 audit gap: clean cherry-picks were producing broken PRs because git-level conflict detection missed content-level issues (duplicate .resw keys, dropped fork-specific warning suppressions).

New gates run AFTER the cherry-pick loop, BEFORE push/PR:
  1. Toolchain preflight  -> detect missing PlatformToolset (infra)
  2. Static breakage scan -> resw dup baseline-diff + fork invariants
  3. Try-build            -> razzle + bz no_clean (45min timeout)

Failures become Tier-4 stuck (post-pick validation), distinct from Tier-3 cherry-pick conflicts. State schema extended with a new stuck_validation field alongside the existing stuck_on_sha; either being set causes the scheduler to skip.

Smoke-tested 08-static-scan against the known-bad PR #220 worktree: returns 26 critical resw-duplicate findings + 1 high C4459 invariant finding, blocking=true (matches the PR #220 audit exactly). Toolchain preflight verified to detect missing v143 on a v145-only host. 10-try-build is wired but not end-to-end tested (would take 30+ min).

Also fixed:
- gh now uses -R microsoft/intelligent-terminal explicitly on issue/pr calls (the upstream remote was making gh default to microsoft/terminal).
- workflow.md: --tags=false -> --no-tags (invalid flag).

v1 scope: resw duplicate keys (baseline-aware) + fork invariants from references/fork-invariants.json (seed: C4459 suppression). v2 deferred: missing-include / vcxproj drift (try-build catches these with zero false positives, so not worth a separate static check).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread .github/skills/upstream-sync/references/build-verification.md Fixed
Comment thread .github/skills/upstream-sync/references/fork-invariants.json Fixed
Comment thread .github/skills/upstream-sync/references/static-scan.md Fixed
Comment thread .github/skills/upstream-sync/references/static-scan.md Fixed
Comment thread .github/skills/upstream-sync/references/static-scan.md Fixed
Comment thread .github/skills/upstream-sync/scripts/09-toolchain-preflight.ps1 Fixed
Comment thread .github/skills/upstream-sync/scripts/09-toolchain-preflight.ps1 Fixed
Comment thread .github/skills/upstream-sync/scripts/09-toolchain-preflight.ps1 Fixed
Comment thread .github/skills/upstream-sync/scripts/09-toolchain-preflight.ps1 Fixed
Comment thread .github/skills/upstream-sync/scripts/04-try-build.ps1 Fixed
@github-actions

This comment has been minimized.

yeelam-gordon added a commit that referenced this pull request Jun 4, 2026
Two content-level issues slipped past the clean git-level cherry-pick (now caught by the new static-scan in PR #218):

1. Duplicate <data name> entries in 20 .resw files (10 locales x 2 projects, 210 blocks total). Root cause: a fork-local commit (ddf97ab) appended ConfirmCloseDialog_* / NotificationMessage_TabActivity* keys; upstream commit b753e3d then renamed the old QuitDialog_* keys to the same names in-place. Resolution: drop the fork-appended duplicates, keep upstream's in-place positions (which preserves alphabetical ordering).

2. C4459 warning suppression dropped from src/common.build.pre.props. Root cause: upstream removed unrelated C4467 in the same DisableSpecificWarnings list during the ATL/MFC cleanup, and the take-upstream resolution wholesale lost the fork-specific C4459 too. C4459 (declaration of 'X' hides class member) is required because the fork builds with TreatWarningsAsError=true and fork-specific code triggers it. Restored.

Verified with .github/skills/upstream-sync/scripts/08-static-scan.ps1: blocking=false, 0 critical, 0 high.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… audit miss)

Get-FileTextOnDisk used [System.IO.File]::ReadAllText with a relative path.
.NET resolves relative paths against [System.Environment]::CurrentDirectory,
NOT PowerShell's $PWD, so the scan was silently reading from
`Q:\official\intelligent-terminal` (the unrelated main worktree) while
the orchestrator was cd'd into `Q:\official\it-sync` (the sync worktree
with the duplicates).

PR #220 symptom: the scan returned �locking=false / 0 critical even
though the cherry-pick batch had introduced 63 new duplicate `<data
name>` entries across 6 pseudo-locale files, and the build subsequently
failed with PRI175 / PRI277.

Fix:
- Get-FileTextOnDisk: resolve to absolute via Join-Path (Get-RepoRoot)
  when the input is relative.
- Get-FileTextAtRef: capture `git show` output through a temp file via
  `cmd /c "git show ref:path > tmp 2>nul"` instead of PowerShell's
  pipeline, which truncates/mangles high-Unicode pseudo-locale bytes
  when the subprocess's stdout binds to PSObject string formatting.

Verified against PR #220 commits:
- HEAD = fd8332b (the buggy state): 6 critical findings, blocking=true ✅
- HEAD = d6b4dc3 (the fixed state): 0 critical, blocking=false ✅

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 4, 2026 08:06

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

Copilot reviewed 27 out of 28 changed files in this pull request and generated 4 comments.

Comment thread .github/skills/upstream-sync/scripts/03-cherry-pick-one.ps1 Outdated
Comment thread .github/skills/upstream-sync/scripts/clear-stuck.ps1 Outdated
Comment thread .github/upstream-sync/state.json Outdated
Comment thread .github/skills/upstream-sync/SKILL.md
Comment thread .github/skills/upstream-sync/references/static-scan.md Fixed
@github-actions

This comment has been minimized.

yeelam-gordon added a commit that referenced this pull request Jun 4, 2026
Two content-level issues slipped past the clean git-level cherry-pick (now caught by the new static-scan in PR #218):

1. Duplicate <data name> entries in 20 .resw files (10 locales x 2 projects, 210 blocks total). Root cause: a fork-local commit (ddf97ab) appended ConfirmCloseDialog_* / NotificationMessage_TabActivity* keys; upstream commit b753e3d then renamed the old QuitDialog_* keys to the same names in-place. Resolution: drop the fork-appended duplicates, keep upstream's in-place positions (which preserves alphabetical ordering).

2. C4459 warning suppression dropped from src/common.build.pre.props. Root cause: upstream removed unrelated C4467 in the same DisableSpecificWarnings list during the ATL/MFC cleanup, and the take-upstream resolution wholesale lost the fork-specific C4459 too. C4459 (declaration of 'X' hides class member) is required because the fork builds with TreatWarningsAsError=true and fork-specific code triggers it. Restored.

Verified with .github/skills/upstream-sync/scripts/08-static-scan.ps1: blocking=false, 0 critical, 0 high.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update skill docs to match same-repo PR creation, direct-push mode, and pinned upstream author/committer dates. Harden native git error checks and empty cherry-pick skip validation, keep state writes newline-terminated, seed the Tier-4 state field, and route stable spelling identifiers through patterns.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread .github/skills/upstream-sync/scripts/05-write-report.ps1 Fixed
@github-actions

This comment has been minimized.

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

Copilot reviewed 28 out of 29 changed files in this pull request and generated 4 comments.

Comment thread .github/skills/upstream-sync/scripts/07-open-stuck-issue.ps1 Outdated
Comment thread .github/skills/upstream-sync/scripts/07b-open-validation-stuck-issue.ps1 Outdated
Comment thread .github/skills/upstream-sync/scripts/10-try-build.ps1 Outdated
Comment thread .github/skills/upstream-sync/scripts/00-bootstrap.ps1 Outdated
Extend the upstream-sync spelling pattern to cover underscore-prefixed toolsets identifiers emitted by the report script.

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

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

Copilot reviewed 28 out of 29 changed files in this pull request and generated 6 comments.

Comment thread .github/skills/upstream-sync/scripts/05-write-report.ps1 Outdated
Comment thread .github/skills/upstream-sync/references/build-verification.md Outdated
Comment thread .github/skills/upstream-sync/references/workflow.md Outdated
Comment thread .github/skills/upstream-sync/references/reporting.md Outdated
Comment thread .github/skills/upstream-sync/references/known-conflicts.md Outdated
Comment thread .github/skills/upstream-sync/references/03-known-conflicts.md
Validate native git branch switches before stuck-lock writes, seed Tier-4 state during bootstrap, and wait for asynchronous build output callbacks before closing the build log writer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
02-compute-pending.ps1:
- `git log --format='%H'` lines could carry trailing CR or whitespace
  on some PS hosts/terminals; the SHA regex would then drop them and
  silently truncate the pending list. Each line is now `.Trim()`'d
  before the `^[0-9a-f]{40}\$` check.

03-cherry-pick-one.ps1:
- `Get-ConflictPaths` split `git diff --name-only` on LF but didn't
  strip a trailing CR. A CRLF-normalized stream would yield paths ending
  in `\r`, missing the exact-string lookup in 03-known-conflicts.md
  and unnecessarily escalating Tier-0-eligible commits to Tier-3.
  Added `.TrimEnd(\"\
\")` per line.

04-try-build.ps1:
- `-LogDir` overrides now get rooted to the repo when supplied as a
  relative path. Previously the path stayed relative through Join-Path,
  then `ConvertTo-RepoRelativePath` threw because the input wasn't
  rooted under the repo (since round 16 removed the silent absolute-path
  fallback). Absolute paths outside the repo still abort, as intended.

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

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

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

Comment thread .github/skills/upstream-sync/SKILL.md Outdated
Comment thread .github/skills/upstream-sync/SKILL.md Outdated
SKILL.md prerequisites:
- Added explicit prereq that `origin/main` must have full git history.
  Watermark discovery scans up to 5000 commits on origin/main for
  cherry-pick trailers and the pending walk uses `merge-base
  --is-ancestor`. A shallow clone (e.g. GitHub Actions default
  `fetch-depth=1`) will produce empty/wrong results. CI should use
  `actions/checkout@v4` with `fetch-depth: 0` or
  `git fetch --unshallow`.

SKILL.md step 8 (gh pr create retry):
- The retry loop used `Select-Object -Last 1` to capture gh's output,
  which drops every line before the last — usually losing the actual
  error context (auth failure, missing head ref, etc.). Now captures
  full output via `Out-String`, surfaces it in the `Write-Warning`,
  and extracts the URL line by filtering for `^https://github.com/`
  so the success path still works.

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

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

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Comment thread .github/skills/upstream-sync/scripts/04-try-build.ps1 Outdated
04-try-build.ps1:
- `\` used nested `cmd /c \"cd /d \"\\" && …\"` to ensure
  the build ran in the repo root, but `ProcessStartInfo.WorkingDirectory`
  is already set to `\` two lines below — the `cd /d` prefix was
  redundant *and* the double-nested quoting breaks when the repo path
  contains spaces or quotes (cmd.exe quote parsing is famously fragile).
  Dropped to a plain `/c \`; the working directory is
  enforced by the ProcessStartInfo, not by an in-line `cd`.

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

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

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Comment thread .github/skills/upstream-sync/scripts/02-compute-pending.ps1
Comment thread .github/skills/upstream-sync/scripts/02-compute-pending.ps1
Comment thread .github/skills/upstream-sync/scripts/03-cherry-pick-one.ps1
02-compute-pending.ps1:
- Trailer regex and SHA validator now accept uppercase A–F as well as
  lowercase a–f. Hand-edited or seed-commit trailers using uppercase
  hex no longer slip past watermark discovery.
- `git merge-base --is-ancestor` previously treated *any* non-zero
  exit as `not an ancestor`. That conflated the documented exit 1
  (semantic `not an ancestor`, keep the SHA) with exit 128 (bad
  object / missing ref / shallow-clone error). Now switches on the
  exit code: 0 = ancestor (drop), 1 = keep, anything else throws so a
  broken repo state can't silently produce a wrong pending list.

03-cherry-pick-one.ps1:
- `Get-ConflictPaths` now captures stderr via `2>&1` and throws on
  non-zero `git diff --diff-filter=U` exit, so a real repo error
  can't be misreported as `no conflict paths`.

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

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

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Comment thread .github/skills/upstream-sync/scripts/03-cherry-pick-one.ps1 Outdated
Comment thread .github/skills/upstream-sync/scripts/03-cherry-pick-one.ps1
Comment thread .github/skills/upstream-sync/scripts/02-compute-pending.ps1 Outdated
…UpstreamShas

03-cherry-pick-one.ps1:
- `git cherry-pick` output was streamed straight to stderr, so when
  the exit was non-zero AND there were no unmerged paths (e.g. `cherry-
  pick` rejected a merge commit without `-m`, or a git version
  rejected `--keep-redundant-commits`), the stuck result said only
  `exited N with no conflict paths` and the actionable git message
  was nowhere in the JSON / issue body.
- Now captures the stream into `\` first, forwards it to
  stderr as before for live visibility, AND grabs the last 20 lines as
  `\`. The Write-Warning and the `result.error` field both
  include that tail so the operator can diagnose the failure without
  rerunning to reproduce.

02-compute-pending.ps1 (real bug — Copilot was right):
- `Get-PendingUpstreamShas` ended with `return ,\`. The comma
  wraps the string[] as a single pipeline object, so the caller's
  `\ = @(Get-PendingUpstreamShas …)` ended up with one element
  that was itself the SHA[], and the subsequent `foreach (\ in
  \)` iterated once with `\` set to a System.Object[].
  Verified the bug interactively (`count=1, type[0]=Object[]`) and
  the fix (`return \`, `count=N, type[0]=String`). PowerShell's
  `@(...)` already flattens the stream — the comma was actively
  harmful here.

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

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

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

Comment thread .github/skills/upstream-sync/scripts/03-cherry-pick-one.ps1 Outdated
Comment thread .github/skills/upstream-sync/SKILL.md Outdated
…eflects failure class

03-cherry-pick-one.ps1:
- When git cherry-pick fails *before* starting (bad args, unsupported
  option on older git, hook reject), the in-progress state is empty
  and the subsequent `git cherry-pick --abort` itself fails with
  `no cherry-pick or revert in progress`. Previously we threw on
  that, which discarded the carefully-built stuck JSON and aborted
  the orchestration with a misleading error.
- Now capture --abort's exit and output, classify the "nothing to
  abort" case as benign, and fold any abort diagnostic into
  `result.error` so the operator still gets the JSON-stuck payload
  with full context.

SKILL.md step 5a (stuck-issue body):
- Body said "stopped at a conflict" unconditionally, which misled
  operators when 03 stuck on a non-conflict failure (empty conflict
  list, error like "merge commit without -m"). Body now branches on
  whether conflict_paths is non-empty:
    - conflict path > 0 → "stopped at a conflict that needs human
      judgment"
    - empty → "non-conflict cherry-pick failure (e.g. merge commit
      without `-m`, unsupported git option, hook failure)"
  and the "Conflicting paths" section renders `_(none …)_` instead
  of an empty list when there are none.

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

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

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

Comment thread .github/skills/upstream-sync/SKILL.md Outdated
Comment thread .github/skills/upstream-sync/scripts/03-cherry-pick-one.ps1
…it log

SKILL.md Get-OwnerRepo:
- Earlier rewrite (round 15) split out HTTPS + scp-style only. A
  remote like `ssh://git@github.com/microsoft/terminal.git` (the
  fully-qualified SSH-protocol form, including `ssh://…:22/…`)
  matched neither branch and was treated as "wrong fork" — the
  identity guard then aborted the sync.
- Now three explicit branches: https, ssh://[user@]host[:port]/, and
  scp-style `user@host:owner/repo`. Verified against eight URL
  variants (with/without `.git`, with/without `user@`, with
  trailing slash, with port) — all resolve to `microsoft/terminal`.

03-cherry-pick-one.ps1:
- Tier-1 empty-commit detection ran `git diff-tree` and `git log`
  without checking `\0`. If either failed (corrupt
  ref, plumbing change, hook issue), an empty stdout would
  `-not \` true → silently reset --hard \;
  non-empty stdout from a failure would proceed as if the pick had
  real changes.
- Now captures stderr, fails fast on non-zero exit with the actual
  git diagnostic, and only then evaluates the change list /
  cherry-pick footer match.

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

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

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Comment thread .github/skills/upstream-sync/scripts/04-try-build.ps1
Comment thread .github/skills/upstream-sync/scripts/04-try-build.ps1
Comment thread .github/skills/upstream-sync/scripts/03-cherry-pick-one.ps1
…n catch under Stop; exit-check git diff --cached

04-try-build.ps1:
- Was `Process::Start(psi)` then attached OutputDataReceived /
  ErrorDataReceived afterwards. Anything the cmd shell, razzle.cmd
  preamble, or MSBuild banner emitted before .NET wired up the
  handlers was dropped, so `log_tail` could miss the only line
  that explained the failure (e.g. "razzle: bad arg").
- Now construct a `New-Object Process`, assign StartInfo, attach
  both handlers, `[void]\.Start()`, then BeginOutputReadLine /
  BeginErrorReadLine. No window between Start and the handler
  subscription.
- Outer `catch` did `Write-Error \.Exception.Message` while
  `\Continue='Stop'` was set at the top of the
  script. That turns each Write-Error into its own terminating
  error, so the `throw` after it never sees the original
  exception — operators got the second-order stop record instead
  of the actual git/msbuild failure. Switched to
  `[Console]::Error.WriteLine` for the diagnostic and kept the
  bare `throw` to rethrow `\` unmodified.

03-cherry-pick-one.ps1:
- `git diff --cached --name-only` after a failed
  `cherry-pick --continue` ran without an exit-code check. If
  `git diff` itself failed (corrupted index, missing object) the
  stderr text would be assigned to `\`, become truthy, and
  the script would proceed to `git cherry-pick --abort` instead
  of taking the `--skip` branch — or worse, masked the underlying
  repo problem with a misleading stuck issue.
- Now captures stderr (`2>&1`), throws with the actual git
  message on non-zero exit, and filters whitespace-only lines
  before deciding the staged set is empty.

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

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

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Comment thread .github/skills/upstream-sync/scripts/02-compute-pending.ps1 Outdated
The comment said "ancestor (already on origin/main, drop it)" but the
ancestor check is `\` vs `\` (the watermark from
`Get-LastSyncedUpstreamSha`), not `origin/main` directly. The
distinction matters: the watermark is the *newest* upstream SHA we've
already picked, recorded in the trailer; the filter drops any SHA at
or before the watermark on upstream/main's history. Rewrote to call
that out — "reachable from \ (the watermark)" — and explained
exit-1 as "newer than the watermark, keep it".

No behavior change.

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

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

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Comment thread .github/skills/upstream-sync/scripts/03-cherry-pick-one.ps1
Comment thread .github/skills/upstream-sync/scripts/03-cherry-pick-one.ps1
Comment thread .github/skills/upstream-sync/scripts/03-cherry-pick-one.ps1

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

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

yeelam-gordon and others added 2 commits June 7, 2026 14:26
…ete duplicated reference

After convergence on Copilot review, a fresh structural review caught
3 concrete issues against `.github/instructions/agent-skills.instructions.md`:

1. SKILL.md was 568 lines, exceeding the hard 500-line cap
   (`agent-skills.instructions.md:364` — "500 is the hard maximum").
2. `references/04-build-verification.md` duplicated SKILL.md step 7
   without adding unique content.
3. (Considered: absolute URLs in SKILL.md gh-issue/PR-body heredocs.
   Kept absolute — GitHub-rendered issue/PR bodies do not resolve
   relative repo paths, so absolute is correct in those contexts.)

Changes:
- Extracted ``Direct-to-main``, ``First-time sync``, and
  ``Squash-merge recovery`` (55 lines) from SKILL.md into a new
  `references/recovery-procedures.md`. Replaced with a 6-line pointer
  section in SKILL.md.
- Compacted the ``After-PR review handling`` section (40 lines) into
  a 10-line summary plus a pointer to the existing
  `references/follow-up-pr.md` (which already carries the full
  rubric, so the in-SKILL.md version was duplicate prose).
- Deleted `references/04-build-verification.md`. Its JSON output
  contract lives in `04-try-build.ps1`'s docstring; its
  Generated-Files artifact note is already in SKILL.md step 7.
- Updated SKILL.md References list to drop 04-build-verification and
  add recovery-procedures.
- Fixed two stale ``#first-time-sync`` anchor links (in the State
  Model bullet at line 52 and in Troubleshooting) to point at the
  extracted section in `references/recovery-procedures.md`.

Result: SKILL.md is now 495 lines (down from 568), under the 500-line
cap. No information is lost — all extracted content is preserved in
the references, and the SKILL.md body stays focused on the runbook
the agent actually executes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
SKILL.md: 495 → 156 lines (well under the 200-line soft target from
agent-skills.instructions.md L312; matches sibling skill
copilot-pr-review-loop/SKILL.md which is 117 lines).

The full 8-step procedure with commands, JSON contracts, and
failure-handling moved verbatim into references/run-a-sync.md (336
lines). SKILL.md now keeps only the ASCII flow diagram + four key
invariants and points at the runbook — same progressive-disclosure
pattern the sibling skill uses.

Gotchas compressed from 13 to 9 entries; kept only items Copilot would
not know from training (the trailer-as-watermark trick, squash-merge
hazard, gh pr create retry pattern, take-upstream tier-0 file,
single-host scheduler caveat, CRLF/LF on manifests). Generic git advice
dropped.

No information lost — everything is reachable via the References list.
The 8-step contract, all scripts, and all reference docs are unchanged.

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

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

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Comment thread .github/skills/upstream-sync/references/recovery-procedures.md Outdated
Comment thread .github/skills/upstream-sync/references/recovery-procedures.md Outdated
Comment thread .github/skills/upstream-sync/references/recovery-procedures.md Outdated
Three findings on Squash-merge recovery section, all correct:

1. `-AutoMergeStrategy rebase` is not a real flag in this skill — the
   step-8 recipe uses `gh pr merge --rebase --auto`. Wording updated.

2. The watermark resolver in 02-compute-pending.ps1 walks trailers
   bottom-up (newest-first, lines 60-66), so a squash commit with the
   trailers preserved picks the NEWEST trailer, not the first/oldest.
   Watermark does NOT move backward in that case. Doc was wrong.

3. Therefore recovery is conditional: needed only when the squash body
   was hand-edited to strip the newest trailer (or all trailers).
   Re-seeding unconditionally would be unnecessary work most of the
   time. Section rewritten to make the condition explicit.

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

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

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

Comment thread .github/skills/upstream-sync/SKILL.md
Comment thread .github/skills/upstream-sync/scripts/02-compute-pending.ps1
…case revert SHAs

Two findings from Copilot:

1. SKILL.md troubleshooting table listed `union` as a Tier-0 strategy.
   03-cherry-pick-one.ps1:191 emits "union strategy not implemented
   yet" and escalates to stuck, and 03-known-conflicts.md:12 says so
   explicitly. Dropped `union` from the parenthetical and added the
   "reserved, currently escalates" note so operators don't add entries
   that won't auto-resolve.

2. Revert-pair regex `[0-9a-f]{40}` is case-sensitive. While `git
   revert` itself emits lowercase, the body could carry an uppercase
   SHA (hand-edited message, scripted commits, third-party tools).
   Switched to `[0-9a-fA-F]{40}` so we don't silently miss a
   revert-pair and re-apply both halves on the fork.

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

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

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Comment thread .github/skills/upstream-sync/scripts/04-try-build.ps1 Outdated
Copilot review: synopsis described the default as the full
`cmd /c "tools\razzle.cmd && bz no_clean"` wrapper, but `-BuildCommand`
and the `command` field in the JSON output are just the inner cmd
string (the `/c` wrapper is added at line 106). Clarified the synopsis
to match what callers actually pass.

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

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

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Comment thread .github/skills/upstream-sync/scripts/03-cherry-pick-one.ps1 Outdated
Copilot review claimed `$u -split "`n"` produces a bogus single
`System.String[]` entry when `$u` is a string[]. Verified
interactively that PowerShell's binary -split operator iterates over
arrays element-wise, so the original code worked correctly:

  $u = @('a/b.txt','c/d.txt')
  @($u -split "`n") -> @('a/b.txt','c/d.txt')  (count=2, String)

So the bug Copilot described doesn't exist — but the -split was
redundant. Removed it; iteration is now obvious to any reader. Also
quoted `$_` in the TrimEnd call to defend against the (theoretical)
case where 2>&1 pulls an ErrorRecord into the pipeline.

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

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

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants