Skip to content

ci: reconcile dev by merge instead of rebase#2453

Merged
SkrubbySkrubInAShrub merged 3 commits into
devfrom
claude-hotfix-workflow-correction
Jun 2, 2026
Merged

ci: reconcile dev by merge instead of rebase#2453
SkrubbySkrubInAShrub merged 3 commits into
devfrom
claude-hotfix-workflow-correction

Conversation

@SkrubbySkrubInAShrub
Copy link
Copy Markdown
Collaborator

@SkrubbySkrubInAShrub SkrubbySkrubInAShrub commented Jun 1, 2026

Replace the destructive rebase-reconcile of dev after a hotfix
promotion with a non-destructive merge-at-promotion approach, so
main becomes an ancestor of dev without ever rewriting dev.

The old rebase-reconcile force-pushed dev (rewriting history and
forcing every open PR to rebase) and was incompatible with dev's
protection (force-push disabled), so it had never run successfully.

Changes to release-semantic.yaml:

  • dev->main (minor/major): if interim hotfixes diverged main, merge
    main into dev first (ancestry-only, fast-forward push, no force),
    resolving version-bump files to dev and hard-failing on any
    non-dev-sourced divergence; then retarget the FF to that merge commit.
  • hotfix-staging->main: no longer touches dev; it is reconciled at the
    next minor/major promotion via the merge above.
  • Relax dev-source validation (a diverged main is now expected).
  • Add a best-effort step that prunes already-shipped hotfix entries from
    the new release's draft notes.
  • Delete the rebase-reconcile step.

Docs:

  • CLAUDE.md: relaxed branch-lineage invariant, merge-at-promotion flow,
    and the App PR-bypass prerequisite for main and dev; drop the
    stale auto-rebase reference.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

Summary by CodeRabbit

  • Documentation
    • Updated internal release process documentation.

Summary by CodeRabbit

  • Documentation

    • Clarified release-process guidance: explains intentional main/dev divergence after hotfixes and updates how current-line hotfix promotions are targeted.
  • Chores

    • Updated release automation to enforce different promotion validations for dev vs hotfix paths, add a dev reconciliation merge step, and deduplicate interim hotfix notes in release drafts.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 1, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 952f0a63-43f2-4177-bc55-abb73c719973

📥 Commits

Reviewing files that changed from the base of the PR and between ae4339b and 593362d.

📒 Files selected for processing (1)
  • .github/workflows/release-semantic.yaml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/release-semantic.yaml

📝 Walkthrough

Walkthrough

Changes update release promotion validation and docs: ff_target selection for current-line hotfixes now uses the hotfix merge commit's second parent, a dev reconciliation merge path is added for dev-source promotions, the hotfix-staging rebase-reconcile step was removed, and release-note deduplication was added.

Changes

Release workflow and docs

Layer / File(s) Summary
Branch lineage invariant & documentation
.claude/CLAUDE.md
Rewrites branch-lineage guidance and updates current-line dispatch to use origin/hotfix/X.Y.x^2 (second parent of hotfix merge) as ff_target, and clarifies dev is left for the next promotion.
Validate ff_target per-source (promotion mode)
.github/workflows/release-semantic.yaml
Refactors validation to determine SOURCE then enforce that non-dev (hotfix-staging) ff_target must be a fast-forward of origin/main.
Reconcile dev (merge origin/main into dev, dev source only)
.github/workflows/release-semantic.yaml
Adds dev reconciliation step: merge origin/main into target dev SHA with allowlisted path resolution, verify resulting tree equals dev, fast-forward dev, and expose effective_target for main fast-forward.
Remove rebase-reconcile (hotfix-staging) & Dedup release notes
.github/workflows/release-semantic.yaml
Removes the rebase-reconcile step for hotfix-staging promotions and adds a best-effort Dedup release notes step that edits the draft release to strip interim hotfix note lines.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • doodlum
  • jiayev

Poem

🐰 I hopped through branches, careful and spry,
I pointed ff_target where secrets lie,
Merged main into dev with a tidy art,
Pruned duplicate notes to do my part,
Hop — the release dance has a cleaner sky.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title directly and concisely describes the main structural change: replacing a rebase-based reconciliation approach with a merge-based one in the CI workflow.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude-hotfix-workflow-correction

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 actionlint (1.7.12)
.github/workflows/release-semantic.yaml

could not read ".github/workflows/release-semantic.yaml": open .github/workflows/release-semantic.yaml: no such file or directory

🔧 zizmor (1.25.2)
.github/workflows/release-semantic.yaml

INFO zizmor: 🌈 zizmor v1.25.2
fatal: no audit was performed
invalid input: .github/workflows/release-semantic.yaml

🔧 YAMLlint (1.38.0)
.github/workflows/release-semantic.yaml

[Errno 2] No such file or directory: '.github/workflows/release-semantic.yaml'

🔧 Checkov (3.2.530)
.github/workflows/release-semantic.yaml

2026-06-02 13:53:23,735 [MainThread ] [ERROR] Template file not found: .github/workflows/release-semantic.yaml
2026-06-02 13:53:23,743 [MainThread ] [ERROR] Template file not found: .github/workflows/release-semantic.yaml
2026-06-02 13:53:23,766 [MainThread ] [ERROR] Template file not found: .github/workflows/release-semantic.yaml
2026-06-02 13:53:23,787 [MainThread ] [ERROR] Failed to invoke function /usr/local/lib/python3.11/dist-packages/checkov/common/runners/object_runner. with .github/workflows/release-semantic.yaml
Traceback (most recent call last):
File "/usr/local/lib/python3.11/dist-packages/checkov/common/parallelizer/parallel_runner.py", line 88, in func_wrapper
result = original_func(item)
^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/dist-packages/checkov/common/runners/object_runner.py", line 74, in
results = parallel_runner.run_function(lambda f: (f, self._parse_file(f)), files_to_load)

... [truncated 9250 characters] ...

ess file .github/workflows/release-semantic.yaml
2026-06-02 13:53:23,841 [MainThread ] [ERROR] Exception traceback:
Traceback (most recent call last):
File "/usr/local/lib/python3.11/dist-packages/checkov/main.py", line 647, in run
self.scan_reports = runner_registry.run(
^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/dist-packages/checkov/common/runners/runner_registry.py", line 177, in run
for result in parallel_runner_results:
File "/usr/local/lib/python3.11/dist-packages/checkov/common/parallelizer/parallel_runner.py", line 118, in _run_function_multiprocess_fork
raise v.internal_exception.with_traceback(v.internal_exception.traceback)
FileNotFoundError: [Errno 2] No such file or directory: '.github/workflows/release-semantic.yaml'


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@SkrubbySkrubInAShrub SkrubbySkrubInAShrub marked this pull request as draft June 1, 2026 22:38
@SkrubbySkrubInAShrub SkrubbySkrubInAShrub changed the title docs: correct AI instruction on hotfix workflow ci: reconcile dev by merge instead of rebase Jun 2, 2026
@SkrubbySkrubInAShrub SkrubbySkrubInAShrub marked this pull request as ready for review June 2, 2026 13:34
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/release-semantic.yaml (1)

110-134: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Require dev-source promotions to use the current origin/dev tip.

Any ancestor of origin/dev is accepted here as a dev-source ff_target, but the later git push --force-with-lease ... "${TARGET}:refs/heads/dev" will then rewrite dev to the reconciliation merge. If a newer commit lands on dev after the selected RC, that push drops those intervening commits and breaks the new "never rewrite dev" invariant.

Suggested fix
                   if [[ -z "${SOURCE}" ]]; then
                     echo "::error::ff_target ${FF_TARGET} is not an ancestor of dev or any origin/hotfix/* branch — refusing to promote an unreviewed SHA."
                     exit 1
                   fi
-                  # hotfix-staging sources must be a clean fast-forward of main
-                  # (no reconcile pre-step runs for them). dev sources may have a
-                  # diverged main; the reconcile step merges it in first.
-                  if [[ "${SOURCE}" != "dev" ]]; then
+                  # dev-source promotions must target the current dev tip; using
+                  # an older ancestor would rewrite dev during reconciliation.
+                  if [[ "${SOURCE}" == "dev" ]]; then
+                    CURRENT_DEV="$(git rev-parse origin/dev)"
+                    if [[ "${FF_TARGET}" != "${CURRENT_DEV}" ]]; then
+                      echo "::error::dev-source ff_target must equal the current origin/dev tip (${CURRENT_DEV}), not an older ancestor."
+                      exit 1
+                    fi
+                  else
                     if ! git merge-base --is-ancestor origin/main "${FF_TARGET}"; then
                       echo "::error::hotfix-staging ff_target ${FF_TARGET} is not a fast-forward of main."
                       exit 1
                     fi
                   fi

If you keep that guard, the later dev update can also be a plain git push so the server enforces the fast-forward invariant instead of relying on --force-with-lease.

Also applies to: 225-226

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-semantic.yaml around lines 110 - 134, The current
check accepts any ancestor of origin/dev as a dev-source, which allows pushing a
reconciliation merge that can rewrite newer dev commits; update the guard so
dev-source FF_TARGET must match the current origin/dev tip exactly: replace the
git merge-base --is-ancestor "${FF_TARGET}" origin/dev test with a direct
equality check using git rev-parse origin/dev (e.g. [ "$(git rev-parse
origin/dev)" = "${FF_TARGET}" ]), set SOURCE="dev" only when they match, and
apply the same exact-tip check to the other equivalent occurrence of the
dev-source guard in the workflow.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/workflows/release-semantic.yaml:
- Around line 110-134: The current check accepts any ancestor of origin/dev as a
dev-source, which allows pushing a reconciliation merge that can rewrite newer
dev commits; update the guard so dev-source FF_TARGET must match the current
origin/dev tip exactly: replace the git merge-base --is-ancestor "${FF_TARGET}"
origin/dev test with a direct equality check using git rev-parse origin/dev
(e.g. [ "$(git rev-parse origin/dev)" = "${FF_TARGET}" ]), set SOURCE="dev" only
when they match, and apply the same exact-tip check to the other equivalent
occurrence of the dev-source guard in the workflow.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a5a0b668-352b-47de-8445-03ddd6653d5c

📥 Commits

Reviewing files that changed from the base of the PR and between 018e1ac and ae4339b.

📒 Files selected for processing (2)
  • .claude/CLAUDE.md
  • .github/workflows/release-semantic.yaml

@SkrubbySkrubInAShrub SkrubbySkrubInAShrub merged commit 6e82454 into dev Jun 2, 2026
7 checks passed
@SkrubbySkrubInAShrub SkrubbySkrubInAShrub deleted the claude-hotfix-workflow-correction branch June 2, 2026 20:40
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.

2 participants