feat(#403): /release-sync — main→dev sync after each release#406
Conversation
Introduces the /release-sync skill to address squash-merge divergence that accumulated across releases and produced 99 conflicts on the v2.0.0 release PR. After each release, /release-sync vX.Y.Z opens a sync PR that merges upstream/main into upstream/dev with -X ours (dev wins on conflicts), making the squash commit an ancestor of dev so future release PRs only show genuinely-new commits. - .claude/skills/release-sync/SKILL.md — new skill spec with pre-flight checks, idempotent no-op, edge-case table, and PR body template - .claude/skills/release/SKILL.md — adds Step 9 (mandatory invoke of /release-sync) and updates Related section - docs/agdr/AgDR-0052-release-sync-skill.md — records the design choice (explicit skill vs auto-invoke vs switch-to-merge-commit) and the merge-strategy direction reasoning (-X ours on a dev-based branch) - .claude/hooks/tests/test_release_sync.sh — 11 sandbox-based smoke tests covering already-in-sync no-op, diverged detection, branch name shape, -X ours direction, idempotence, post-sync state, and version argument validation; all 11 pass Refs #403 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
atlas-apex
left a comment
There was a problem hiding this comment.
Code Review: PR #406
Commit: daa3fc9642079547c3ff75006fb6b48ad34f4b3d
Summary
Adds a new /release-sync skill that closes the squash-divergence loop after each dev → main release by filing a sync/main-to-dev-after-vX.Y.Z → dev PR that merges upstream/main into upstream/dev with -X ours. Wires the skill into /release as a mandatory Step 9, documents the design choices in AgDR-0052, and ships 11 sandboxed smoke tests (all pass locally: Passed: 11, Failed: 0).
Checklist Results
- Architecture & Design: Pass — skill is framework-only (same
me2resh/apexyardorigin/upstream guard as/release), idempotent, no-auto-merge, branch-base + merge-strategy invariants explicit in## Rules - Code Quality: Pass — markdown specs follow sibling-skill convention (frontmatter, Usage, numbered Process, Edge Cases, Rules, Related)
- Testing: Pass — 11 sandboxed tests cover happy path, no-op, diverged detection,
-X oursconflict direction, idempotence, post-sync state, version validation;mktemp+rm -rfcleanup; no network calls - Security: Pass — N/A (no auth/crypto/secrets surface; tests use synthetic git sandboxes)
- Performance: Pass — N/A
- PR Description & Glossary: Pass — narrative summary bullets (all four bullets explain what + why, with the v2.0.0 99-conflict rationale), Testing section, Glossary with 4 terms
- Summary Bullet Narrative: Pass — bullets exceed the 6-word + verb heuristic and each carries rationale
- Technical Decisions (AgDR):Pass — AgDR-0052 is the next free number (0051 is the latest existing), follows
templates/agdr.mdshape (Context, 4 options A-D in Options Considered, Decision with reasoning, Consequences, Artifacts), explicitly walks through the explicit-vs-auto-invocation tradeoff AND the-X oursvs-X theirsdirection - Adopter Handbooks: N/A — no handbooks loaded for this diff (no architecture/general matches; no language buckets triggered — shell test file lives outside the conventional
language/shell/location)
Verified items
- Merge-strategy direction is correct. Spec uses
git checkout -b sync/main-to-dev-after-<version> upstream/devthengit merge --no-ff -X ours ... upstream/main. Because the sync branch is rooted in dev, "ours" = dev = the correct winner (dev already has the un-squashed equivalents of everything in the squash). Spec body § 5 and AgDR § "Merge strategy direction" both explicitly call out the common confusion and explain why-X theirswould be wrong. No-X theirsanywhere in the diff. /releaseStep 9 integration is clean. Appended after the existing tag-push step (Step 8). Doesn't break 1-8 semantics. Explicit "Do not skip this step" with the v2.0.0 99-conflict cite +#403reference. New entry added to Related links.- Framework-only guard matches
/releaseconvention. Origin-or-upstream-is-me2resh/apexyardcheck — same shape as the parent skill. (No_lib-portfolio-paths.shneeded here; that helper is for portfolio-aware skills that traverseapexyard.projects.yaml, and/releaseitself doesn't use it either.) - AgDR-0052 is the correct next number. Verified against
docs/agdr/listing — 0051 is the latest existing. - Test count matches. 11
mark_passinvocations in the test file; live run printsPassed: 11, Failed: 0. - Out-of-scope items correctly deferred. Auto-invocation, switching from squash to merge-commit, and branch-protection rules are all enumerated as Options B/C/D in the AgDR with reasoning for not pursuing them in this PR.
Issues Found
None blocking.
Handbook Findings
No loaded handbooks produced findings (no handbooks/architecture/ or handbooks/general/ matches in the diff; no language buckets triggered).
Suggestions (non-blocking)
-
nit:Test Case 3 is a tautology..claude/hooks/tests/test_release_sync.sh:148-153compares two identically-constructed strings:VERSION="v2.0.3" EXPECTED_BRANCH="sync/main-to-dev-after-${VERSION}" ACTUAL="sync/main-to-dev-after-${VERSION}" [ "$ACTUAL" = "$EXPECTED_BRANCH" ] && mark_pass ... || mark_fail ...
The test always passes by construction and doesn't actually verify any skill behaviour. A future hardening pass could either (a) compute
ACTUALfrom a shared helper that mirrors the spec's branch-name format, or (b) drop the case as zero-information. The branch-name format is also documented in the SKILL.md spec so the absence of this assertion isn't a real coverage gap — just calling out that the test is currently decorative. -
suggestion:Surface the cumulative-divergence number in the PR body. AgDR § Context cites "by v2.0.2, there were 6 squash commits onmainnot present ondev" — a concrete number that reinforces why this skill is needed. The current PR body bullets reference the v2.0.0 99-conflict incident but not the accumulation rate. Worth one extra phrase if you do a follow-up PR; not worth a rewrite for this one. -
nit:Spec § 2 and § 3 are mildly redundant. Both end at the same exit-0 conclusion whenCOMMITS_ON_MAIN_NOT_ON_DEV -eq 0. Not wrong — the explicit reasoning trail is useful — just slightly verbose for a future reader.
Verdict
APPROVED
The skill is well-scoped, the merge-strategy direction is correct (and explicitly defended in both the spec and the AgDR against the common "theirs vs ours" confusion), tests pass locally, the AgDR is thorough on the design-space exploration, and the integration into /release is non-invasive. None of the suggestions block merge.
🤖 Reviewed by Rex (Code Reviewer Agent)
📌 Reviewed commit: daa3fc9642079547c3ff75006fb6b48ad34f4b3d
Address red CI on Rex-approved release-sync PR: - site-counts drift: new /release-sync skill bumps total to 55. Update all 12 marketing-copy references across architecture.html, *.md.gen, llms.txt, llms-full.txt, skill.md (incl. 2 multiline / phrasing-variant references caught by the post-#377 cross-newline scanner). - markdownlint MD032: add blank lines around the bullet lists in release-sync SKILL.md (line 80) and AgDR-0052 (line 36). Refs #403
atlas-apex
left a comment
There was a problem hiding this comment.
Re-Review: PR #406 (after operator fixup)
Commit reviewed: 6e7f757b67ff6b252dff5fb67d64bb531b9ddd2c
Prior approved SHA: daa3fc9642079547c3ff75006fb6b48ad34f4b3d
Fixup commit: 6e7f757 — fix(#403): refresh site skill-count (54→55) + 2 MD032 lint fixes
Verdict: APPROVE (posted as comment — GitHub forbids self-approval on own PR).
Summary
Re-reviewed the single fixup commit on top of my previously-approved daa3fc9. The fixup does exactly what the commit message says: bumps 11 site-count references from 54 → 55 and adds blank lines around two MD032-flagged lists. No release-sync skill behavior, merge-strategy semantics, or AgDR content was touched.
Checklist Results
- Architecture & Design: Pass (no behavior change in fixup)
- Code Quality: Pass
- Testing: Pass (CI now green — was RED on the prior SHA for both
site-counts drift detectionandmarkdownlint-cli2) - Security: Pass (no security-sensitive surface in fixup)
- Performance: Pass
- PR Description & Glossary: Pass (carried over from prior verdict)
- Summary Bullet Narrative: Pass (carried over)
- Technical Decisions (AgDR): N/A (no new decisions in fixup; lint fix + count refresh)
- Adopter Handbooks: N/A (no handbooks loaded — fixup doesn't touch any language bucket)
Fixup scope verification (9 files)
.claude/skills/release-sync/SKILL.md +2 -0 (MD032 blank lines)
docs/agdr/AgDR-0052-release-sync-skill.md +2 -0 (MD032 blank lines)
site/architecture.html +1 -1 (54→55)
site/architecture.md.gen +1 -1 (54→55)
site/index.md.gen +2 -2 (54→55, ×2 lines)
site/llms-full.txt +4 -4 (54→55, ×4 lines)
site/llms.txt +3 -3 (54→55, ×3 lines)
site/skill.md +1 -1 (54→55)
site/skills.md.gen +2 -2 (54→55, ×2 lines)
Exactly 9 files, all changes are scoped to the stated purpose. No release-sync logic regressions.
CI state at new HEAD
All 5 checks pass:
Verify Ticket ID— passlychee— passmarkdownlint-cli2— pass (was RED at prior SHA)shellcheck .claude/hooks— passsite-counts drift detection— pass (was RED at prior SHA)
Site-count refresh: 11/12 references updated cleanly
The 11 references the drift checker catches are all correctly 54 → 55 (across .html, .md.gen, llms.txt, llms-full.txt, skill.md). Verified via GitHub Search API: zero residual "54 skills" matches on the PR branch.
MD032 fixes: clean
Both files show pure +2 -0 patches — blank lines added before/after the flagged lists with no list content changed. Exactly what MD032 requires, nothing else.
Nit (non-blocking, advisory)
site/index.md.gen:76 — one straggler reference to "54 of these in total":
74: ### Tools for every step of shipping software · 55 slash commands
75:
76: Want to adopt a project you've inherited? `/handover`. … `/launch-check`. 54 of these in total — each one is a focused workflow with safety rails.
The parallel paragraph in site/llms-full.txt:125 was correctly updated to "55 of these in total". This is the same content shape; the operator just missed this one. It's a customer-facing inconsistency (line 74 says "55 slash commands", line 76 immediately after says "54 of these in total"), but:
- It doesn't block CI — the drift checker's noun pattern list (
skills | slash commands | hooks | shell scripts | shell gates | mechanical gates | shell hooks | roles? | role definitions) doesn't include the "of these" phrasing - It's a trivial one-character fix (
4→5) - It's safely deferrable to a follow-up commit or carried into the next sync
Recommend the operator either include the 1-line fix in a tiny follow-up or roll it into the next site refresh. Optionally, consider extending test_site_counts.sh's noun-pattern list to include "of these in total" / "of them" so future drifts in this phrasing are caught mechanically.
Verdict
APPROVED — fixup achieves its stated purpose, CI is now green, and no regression on the prior approval. The single straggler is non-blocking advisory.
Reviewed by Rex (Code Reviewer Agent)
Reviewed commit: 6e7f757b67ff6b252dff5fb67d64bb531b9ddd2c
* fix(#404): remove stale --pdf-output-folder flag from md-to-pdf dispatch (#405) md-to-pdf removed --pdf-output-folder and --dest-name in a breaking API change; convert.sh still passed both flags, causing every npx md-to-pdf invocation to abort with: ArgError: unknown or unexpected option: --pdf-output-folder Fix: stage the source into a private temp dir under the desired output stem (e.g. WORK/out.pdf → WORK/out.md), invoke `npx -y md-to-pdf <tmp>.md`, then mv the resulting <tmp>.pdf to the requested TO_ABS. md-to-pdf writes <basename>.pdf next to the source by default, so this is compatible with every currently-released version. The same fix is applied to the md-to-pdf-html branch (HTML → PDF fallback), which had identical stale flags. Adds regression test at .claude/skills/pdf/tests/test_md_to_pdf_fallback.sh covering four cases: successful conversion, absence of the stale --pdf-output-folder flag, absence of --dest-name, and custom output path resolution. All four pass locally against the current npm latest. Refs #404 Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(#403): /release-sync — main→dev sync after each release (#406) * feat(#403): /release-sync skill — main→dev sync after each release Introduces the /release-sync skill to address squash-merge divergence that accumulated across releases and produced 99 conflicts on the v2.0.0 release PR. After each release, /release-sync vX.Y.Z opens a sync PR that merges upstream/main into upstream/dev with -X ours (dev wins on conflicts), making the squash commit an ancestor of dev so future release PRs only show genuinely-new commits. - .claude/skills/release-sync/SKILL.md — new skill spec with pre-flight checks, idempotent no-op, edge-case table, and PR body template - .claude/skills/release/SKILL.md — adds Step 9 (mandatory invoke of /release-sync) and updates Related section - docs/agdr/AgDR-0052-release-sync-skill.md — records the design choice (explicit skill vs auto-invoke vs switch-to-merge-commit) and the merge-strategy direction reasoning (-X ours on a dev-based branch) - .claude/hooks/tests/test_release_sync.sh — 11 sandbox-based smoke tests covering already-in-sync no-op, diverged detection, branch name shape, -X ours direction, idempotence, post-sync state, and version argument validation; all 11 pass Refs #403 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#403): refresh site skill-count (54→55) + 2 MD032 lint fixes Address red CI on Rex-approved release-sync PR: - site-counts drift: new /release-sync skill bumps total to 55. Update all 12 marketing-copy references across architecture.html, *.md.gen, llms.txt, llms-full.txt, skill.md (incl. 2 multiline / phrasing-variant references caught by the post-#377 cross-newline scanner). - markdownlint MD032: add blank lines around the bullet lists in release-sync SKILL.md (line 80) and AgDR-0052 (line 36). Refs #403 --------- Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(#408): CHANGELOG v2.1.0 + site version pill bump - Append [2.1.0] section above [2.0.2] - Bump site/index.html version pill v2.0.2 → v2.1.0 - Last cherry-pick release; /release-sync now live for v2.2.x+ Refs #408 --------- Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(me2resh#404): remove stale --pdf-output-folder flag from md-to-pdf dispatch (me2resh#405) md-to-pdf removed --pdf-output-folder and --dest-name in a breaking API change; convert.sh still passed both flags, causing every npx md-to-pdf invocation to abort with: ArgError: unknown or unexpected option: --pdf-output-folder Fix: stage the source into a private temp dir under the desired output stem (e.g. WORK/out.pdf → WORK/out.md), invoke `npx -y md-to-pdf <tmp>.md`, then mv the resulting <tmp>.pdf to the requested TO_ABS. md-to-pdf writes <basename>.pdf next to the source by default, so this is compatible with every currently-released version. The same fix is applied to the md-to-pdf-html branch (HTML → PDF fallback), which had identical stale flags. Adds regression test at .claude/skills/pdf/tests/test_md_to_pdf_fallback.sh covering four cases: successful conversion, absence of the stale --pdf-output-folder flag, absence of --dest-name, and custom output path resolution. All four pass locally against the current npm latest. Refs me2resh#404 Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(me2resh#403): /release-sync — main→dev sync after each release (me2resh#406) * feat(me2resh#403): /release-sync skill — main→dev sync after each release Introduces the /release-sync skill to address squash-merge divergence that accumulated across releases and produced 99 conflicts on the v2.0.0 release PR. After each release, /release-sync vX.Y.Z opens a sync PR that merges upstream/main into upstream/dev with -X ours (dev wins on conflicts), making the squash commit an ancestor of dev so future release PRs only show genuinely-new commits. - .claude/skills/release-sync/SKILL.md — new skill spec with pre-flight checks, idempotent no-op, edge-case table, and PR body template - .claude/skills/release/SKILL.md — adds Step 9 (mandatory invoke of /release-sync) and updates Related section - docs/agdr/AgDR-0052-release-sync-skill.md — records the design choice (explicit skill vs auto-invoke vs switch-to-merge-commit) and the merge-strategy direction reasoning (-X ours on a dev-based branch) - .claude/hooks/tests/test_release_sync.sh — 11 sandbox-based smoke tests covering already-in-sync no-op, diverged detection, branch name shape, -X ours direction, idempotence, post-sync state, and version argument validation; all 11 pass Refs me2resh#403 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(me2resh#403): refresh site skill-count (54→55) + 2 MD032 lint fixes Address red CI on Rex-approved release-sync PR: - site-counts drift: new /release-sync skill bumps total to 55. Update all 12 marketing-copy references across architecture.html, *.md.gen, llms.txt, llms-full.txt, skill.md (incl. 2 multiline / phrasing-variant references caught by the post-me2resh#377 cross-newline scanner). - markdownlint MD032: add blank lines around the bullet lists in release-sync SKILL.md (line 80) and AgDR-0052 (line 36). Refs me2resh#403 --------- Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(me2resh#408): CHANGELOG v2.1.0 + site version pill bump - Append [2.1.0] section above [2.0.2] - Bump site/index.html version pill v2.0.2 → v2.1.0 - Last cherry-pick release; /release-sync now live for v2.2.x+ Refs me2resh#408 --------- Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(#403): /release-sync skill — main→dev sync after each release Introduces the /release-sync skill to address squash-merge divergence that accumulated across releases and produced 99 conflicts on the v2.0.0 release PR. After each release, /release-sync vX.Y.Z opens a sync PR that merges upstream/main into upstream/dev with -X ours (dev wins on conflicts), making the squash commit an ancestor of dev so future release PRs only show genuinely-new commits. - .claude/skills/release-sync/SKILL.md — new skill spec with pre-flight checks, idempotent no-op, edge-case table, and PR body template - .claude/skills/release/SKILL.md — adds Step 9 (mandatory invoke of /release-sync) and updates Related section - docs/agdr/AgDR-0052-release-sync-skill.md — records the design choice (explicit skill vs auto-invoke vs switch-to-merge-commit) and the merge-strategy direction reasoning (-X ours on a dev-based branch) - .claude/hooks/tests/test_release_sync.sh — 11 sandbox-based smoke tests covering already-in-sync no-op, diverged detection, branch name shape, -X ours direction, idempotence, post-sync state, and version argument validation; all 11 pass Refs #403 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(#403): refresh site skill-count (54→55) + 2 MD032 lint fixes Address red CI on Rex-approved release-sync PR: - site-counts drift: new /release-sync skill bumps total to 55. Update all 12 marketing-copy references across architecture.html, *.md.gen, llms.txt, llms-full.txt, skill.md (incl. 2 multiline / phrasing-variant references caught by the post-#377 cross-newline scanner). - markdownlint MD032: add blank lines around the bullet lists in release-sync SKILL.md (line 80) and AgDR-0052 (line 36). Refs #403 --------- Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(me2resh#404): remove stale --pdf-output-folder flag from md-to-pdf dispatch (me2resh#405) md-to-pdf removed --pdf-output-folder and --dest-name in a breaking API change; convert.sh still passed both flags, causing every npx md-to-pdf invocation to abort with: ArgError: unknown or unexpected option: --pdf-output-folder Fix: stage the source into a private temp dir under the desired output stem (e.g. WORK/out.pdf → WORK/out.md), invoke `npx -y md-to-pdf <tmp>.md`, then mv the resulting <tmp>.pdf to the requested TO_ABS. md-to-pdf writes <basename>.pdf next to the source by default, so this is compatible with every currently-released version. The same fix is applied to the md-to-pdf-html branch (HTML → PDF fallback), which had identical stale flags. Adds regression test at .claude/skills/pdf/tests/test_md_to_pdf_fallback.sh covering four cases: successful conversion, absence of the stale --pdf-output-folder flag, absence of --dest-name, and custom output path resolution. All four pass locally against the current npm latest. Refs me2resh#404 Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(me2resh#403): /release-sync — main→dev sync after each release (me2resh#406) * feat(me2resh#403): /release-sync skill — main→dev sync after each release Introduces the /release-sync skill to address squash-merge divergence that accumulated across releases and produced 99 conflicts on the v2.0.0 release PR. After each release, /release-sync vX.Y.Z opens a sync PR that merges upstream/main into upstream/dev with -X ours (dev wins on conflicts), making the squash commit an ancestor of dev so future release PRs only show genuinely-new commits. - .claude/skills/release-sync/SKILL.md — new skill spec with pre-flight checks, idempotent no-op, edge-case table, and PR body template - .claude/skills/release/SKILL.md — adds Step 9 (mandatory invoke of /release-sync) and updates Related section - docs/agdr/AgDR-0052-release-sync-skill.md — records the design choice (explicit skill vs auto-invoke vs switch-to-merge-commit) and the merge-strategy direction reasoning (-X ours on a dev-based branch) - .claude/hooks/tests/test_release_sync.sh — 11 sandbox-based smoke tests covering already-in-sync no-op, diverged detection, branch name shape, -X ours direction, idempotence, post-sync state, and version argument validation; all 11 pass Refs me2resh#403 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(me2resh#403): refresh site skill-count (54→55) + 2 MD032 lint fixes Address red CI on Rex-approved release-sync PR: - site-counts drift: new /release-sync skill bumps total to 55. Update all 12 marketing-copy references across architecture.html, *.md.gen, llms.txt, llms-full.txt, skill.md (incl. 2 multiline / phrasing-variant references caught by the post-me2resh#377 cross-newline scanner). - markdownlint MD032: add blank lines around the bullet lists in release-sync SKILL.md (line 80) and AgDR-0052 (line 36). Refs me2resh#403 --------- Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * chore(me2resh#408): CHANGELOG v2.1.0 + site version pill bump - Append [2.1.0] section above [2.0.2] - Bump site/index.html version pill v2.0.2 → v2.1.0 - Last cherry-pick release; /release-sync now live for v2.2.x+ Refs me2resh#408 --------- Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Summary
/release-syncskill — after each squash-merge release, invoke/release-sync vX.Y.Zto open async/main-to-dev-after-vX.Y.Z → devPR that mergesupstream/mainintoupstream/devwith-X ours; this makes the release squash commit an ancestor ofdevso futuredev→mainrelease PRs only see genuinely-new commits instead of fighting accumulated SHA divergence/releaseStep 9 added — documents/release-syncas the mandatory final step of every release, with a note explaining why this step exists (v2.0.0 suffered 99 conflicts from skipped syncs)/release, vs switching to merge-commit releases) and documents the merge-strategy direction reasoning (-X oursmeans dev wins when we're on a dev-based branch merging main)test_release_sync.sh) — sandbox-based, cover already-in-sync no-op, diverged detection, branch name shape,-X oursconflict direction, idempotence, post-sync state, and version argument validation; all passTesting
The tests create synthetic git sandboxes under
mktempdirectories; they clean up after themselves and have no side effects on the actual repo.Closes #403
Glossary
main, the resulting commit has a different SHA than the equivalent dev-branch history;devstill carries the unsquashed commits, making futuredev→mainPRs conflict on all diffs the squash also touched-X oursmain, "ours" = dev, which is the correct winner because dev already has the un-squashed equivalentssync/main-to-dev-after-vX.Y.Zgit log upstream/dev..upstream/mainis already empty (main has nothing dev doesn't), the skill exits 0 without creating a PR