Skip to content

feat(stack): drop the Depends-On header once GitHub holds the stack - #1780

Merged
mergify[bot] merged 1 commit into
mainfrom
devs/jd/jd/mrgfy-8772-mergify-stack-push-stop-writing-depends-on-when-github/drop-depends-header-once-github-holds-stack--a15a76de
Aug 24, 2026
Merged

feat(stack): drop the Depends-On header once GitHub holds the stack#1780
mergify[bot] merged 1 commit into
mainfrom
devs/jd/jd/mrgfy-8772-mergify-stack-push-stop-writing-depends-on-when-github/drop-depends-header-once-github-holds-stack--a15a76de

Conversation

@jd

@jd jd commented Aug 20, 2026

Copy link
Copy Markdown
Member

With --github-native, mergify stack push registers the stack with
GitHub's Stacks API, and that registration is the dependency between
two pull requests. The <n> header the CLI writes on top
of it records the same edge a second time, in the copy users actually
read — so it is now left out.

Keyed off the registration, never off the flag. --github-native
degrades silently by design: native_stack::register returns None on
a 404 (old GHES, feature off for the repo), a chain with a hole in it,
or a stack below GitHub's 2-PR floor, and the push carries on as an
ordinary Mergify stack. Dropping the header on the flag alone would
leave those pushes with the edge recorded nowhere at all, and Mergify
reconstructs a stack from Depends-On chains
(engine/stacks/detection.py) — a mid-stack pull request would lose
the gate holding it behind its predecessor.

Registration happens after the bodies are written, so the removal is
optimistic and settled inside the same push: every header the upsert
skips is remembered, and pr_upsert::restore_depends_on writes it back
(body only, no base key) if the stack ends the push unregistered.
That path is fatal on failure — every other way this feature degrades
lands in the state a flag-off push produces, and a stack that is
neither registered nor chained would not.

Nothing writes Depends-On into a commit; it only ever existed in the
rendered PR description, so no commit message changes shape.

What still reads the header, checked against the engine rather than
assumed:

  • stacks/detection.py walks CLI stacks by branch chain and the
    marker; its native counterpart stacks/github_native.py walks the
    mirrored stack object instead, and get_stack_predecessor_state
    unions the two. The native half is behind
    GITHUB_STACK_QUEUE_FOR_ORGS, but an org without that flag cannot
    merge a registered stack at all — merge_helpers keeps it off the
    merge-async path and GitHub 403s the classic endpoint for every
    member — so the marker there gates a merge that cannot happen.
  • The queue's build_stack_groups and
    find_direct_open_successors_by_head_ref use head/base refs only.
  • The browser extension reads its own mergify-stack-data comment.
  • The stacks-analytics endpoint detects stack PRs by Change-Id (which
    we still write); only its bottom-vs-upper first-review split reads
    the marker, so native stacks will read as all-bottom there. Metrics
    skew on an opt-in flag, not a merge regression — worth its own fix.

MRGFY-8772

Copilot AI lite review requested due to automatic review settings August 20, 2026 11:17
@mergify
mergify Bot had a problem deploying to Mergify Merge Protections August 20, 2026 11:17 Failure
@jd
jd deployed to func-tests-live August 20, 2026 11:17 — with GitHub Actions Active
@mergify

mergify Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Merge Protections

🟢 All 6 merge protections satisfied — ready to merge.

Show 6 satisfied protections

🟢 🤖 Continuous Integration

  • all of:
    • check-success=ci-gate

🟢 👀 Review Requirements

  • any of:
    • #approved-reviews-by>=2
    • author = dependabot[bot]
    • author = mergify-ci-bot
    • author = renovate[bot]

🟢 Enforce conventional commit

Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/

  • title ~= ^(fix|feat|internal|docs|style|refactor|perf|test|build|ci|chore|revert|ui)(?:\(.+\))?!?:

🟢 🔎 Reviews

  • #changes-requested-reviews-by = 0
  • #review-requested = 0
  • #review-threads-unresolved = 0

🟢 📕 PR description

  • body ~= (?ms:.{48,})

🟢 🚦 Auto-queue

When all merge protections are satisfied, this pull request will be queued automatically.

Copilot AI left a comment

Copy link
Copy Markdown

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 updates mergify stack push --github-native so that when a stack is successfully registered with GitHub’s native Stacks API (i.e., GitHub itself holds the ordering), the CLI no longer writes the redundant Depends-On: header into PR descriptions; if registration ends up not happening, the same push restores the suppressed headers to preserve Mergify’s ordering signal.

Changes:

  • Suppress Depends-On: rendering during PR upsert when --github-native is enabled, and restore suppressed markers if the stack ends the push unregistered.
  • Add pr_upsert helpers to ensure restore renders from the same source used by the upsert (commit message vs existing PR body under --keep-pull-request-title-and-body).
  • Update CLI help/docs and extend end-to-end tests to cover header suppression vs restoration behavior.

Reviewed changes

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

Show a summary per file
File Description
skills/mergify-stack/SKILL.md Documents --github-native behavior change re: Depends-On: and restoration.
crates/mergify-stack/src/pr_upsert.rs Adds shared description source selection and a body-only PATCH helper to restore Depends-On:.
crates/mergify-stack/src/native_stack.rs Expands module docs to explain why ordering markers are suppressed for registered stacks.
crates/mergify-stack/src/commands/push.rs Implements suppression tracking and conditional restoration based on registration outcome.
crates/mergify-cli/tests/stack_push_github_native.rs Adds tests asserting marker presence/absence under registered vs unregistered outcomes.
crates/mergify-cli/src/snapshots/mergify__tests__cli_schema_golden.snap Updates CLI schema snapshot to reflect updated --github-native help text.
crates/mergify-cli/src/main.rs Updates --github-native flag help text to mention ordering + Depends-On: removal.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread crates/mergify-stack/src/commands/push.rs Outdated
Comment thread skills/mergify-stack/SKILL.md Outdated
Comment thread crates/mergify-stack/src/pr_upsert.rs Outdated
Comment thread crates/mergify-stack/src/pr_upsert.rs Outdated
@jd

jd commented Aug 20, 2026

Copy link
Copy Markdown
Member Author

Revision history

# Type Changes Reason Date
1 initial 393df6b 2026-08-20 12:33 UTC
2 content 393df6b → e0d7867 address review: correct the 're-rendered from the commit messages' claim for --keep-pull-request-title-and-body (module doc + SKILL.md), narrow description_source/restore_depends_on to pub(crate), an… 2026-08-20 12:33 UTC
3 rebase e0d7867 → 9ed18bb (rebase only) rebase onto main: picks up the h2 0.4.17 bump (#1778) that clears RUSTSEC-2026-0258, turning cargo-deny and ci-gate green. No change to this commit's own diff. 2026-08-21 20:07 UTC

@jd
jd force-pushed the devs/jd/jd/mrgfy-8772-mergify-stack-push-stop-writing-depends-on-when-github/drop-depends-header-once-github-holds-stack--a15a76de branch from 393df6b to e0d7867 Compare August 20, 2026 12:33
@jd
jd deployed to func-tests-live August 20, 2026 12:33 — with GitHub Actions Active
@mergify
mergify Bot had a problem deploying to Mergify Merge Protections August 20, 2026 12:34 Failure
@jd

jd commented Aug 20, 2026

Copy link
Copy Markdown
Member Author

Pushed the review round: 393db6b→e0d7867.

  • Docs claim corrected (module doc + SKILL.md). Both said bodies are "re-rendered from the commit messages every time", which --keep-pull-request-title-and-body contradicts. The conclusion that sentence supported still holds, but for a different reason: create_or_update_pr always renders through format_pull_description(description_source(&input), input.depends_on_number), which strips any existing Depends-On: and re-appends it from the resolved predecessor. The marker is recomputed from the stack every push rather than carried over from the source text, so a re-run settles a stack left neither registered nor chained whichever source the body came from. Both docs now say that and name both sources.
  • description_source and restore_depends_on are pub(crate). Only caller is the push orchestrator; nothing outside the crate links against mergify-stack but mergify-cli.
  • Renamed the two native-registration tests to depends_on_omitted_when_native_registration_succeeds and depends_on_restored_when_native_registration_does_not_happen. They already pinned both halves — no marker once GitHub holds the order, marker restored when registration did not happen — but under names that did not say so. The pair is the actual contract of this change, so the names now match.

cargo fmt --check, clippy --workspace --all-targets -D warnings, typos and the full workspace suite are green locally.

cargo-deny is red on RUSTSEC-2026-0258 (h2 unbounded empty DATA frames). That is inherited from main, not from this diff — no Cargo.lock, Cargo.toml or deny.toml change here — and #1778 fixes it. ci-gate is just the aggregate over it. Everything else is green.

@jd

jd commented Aug 21, 2026

Copy link
Copy Markdown
Member Author

The two red checks here are not from this diff. cargo-deny fails on RUSTSEC-2026-0258 (h2 0.4.14, pulled in transitively through hyper), which is the state of main right now — this branch does not touch Cargo.lock. ci-gate is just the aggregate going red behind it.

#1778 bumps h2 to 0.4.17 and is already green and approved; once it lands, a rebase here turns both green. I am deliberately not duplicating the bump in this branch — two PRs rewriting the same Cargo.lock entry only buys a conflict.

Everything this PR owns is done: 19/21 checks green (including rust and live-tests), all four review threads answered and resolved.

@jd
jd marked this pull request as ready for review August 21, 2026 06:44
With `--github-native`, `mergify stack push` registers the stack with
GitHub's Stacks API, and that registration *is* the dependency between
two pull requests. The `Depends-On: #<n>` header the CLI writes on top
of it records the same edge a second time, in the copy users actually
read — so it is now left out.

Keyed off the registration, never off the flag. `--github-native`
degrades silently by design: `native_stack::register` returns `None` on
a 404 (old GHES, feature off for the repo), a chain with a hole in it,
or a stack below GitHub's 2-PR floor, and the push carries on as an
ordinary Mergify stack. Dropping the header on the flag alone would
leave those pushes with the edge recorded nowhere at all, and Mergify
reconstructs a stack from `Depends-On` chains
(`engine/stacks/detection.py`) — a mid-stack pull request would lose
the gate holding it behind its predecessor.

Registration happens after the bodies are written, so the removal is
optimistic and settled inside the same push: every header the upsert
skips is remembered, and `pr_upsert::restore_depends_on` writes it back
(body only, no `base` key) if the stack ends the push unregistered.
That path is fatal on failure — every other way this feature degrades
lands in the state a flag-off push produces, and a stack that is
neither registered nor chained would not.

Nothing writes `Depends-On` into a commit; it only ever existed in the
rendered PR description, so no commit message changes shape.

What still reads the header, checked against the engine rather than
assumed:

- `stacks/detection.py` walks CLI stacks by branch chain **and** the
  marker; its native counterpart `stacks/github_native.py` walks the
  mirrored `stack` object instead, and `get_stack_predecessor_state`
  unions the two. The native half is behind
  `GITHUB_STACK_QUEUE_FOR_ORGS`, but an org without that flag cannot
  merge a registered stack at all — `merge_helpers` keeps it off the
  merge-async path and GitHub 403s the classic endpoint for every
  member — so the marker there gates a merge that cannot happen.
- The queue's `build_stack_groups` and
  `find_direct_open_successors_by_head_ref` use head/base refs only.
- The browser extension reads its own `mergify-stack-data` comment.
- The stacks-analytics endpoint detects stack PRs by `Change-Id` (which
  we still write); only its bottom-vs-upper first-review split reads
  the marker, so native stacks will read as all-bottom there. Metrics
  skew on an opt-in flag, not a merge regression — worth its own fix.

MRGFY-8772

Change-Id: Ia15a76dec74d7799bf891ab5c0d14211aba2bb9e
@jd
jd force-pushed the devs/jd/jd/mrgfy-8772-mergify-stack-push-stop-writing-depends-on-when-github/drop-depends-header-once-github-holds-stack--a15a76de branch from e0d7867 to 9ed18bb Compare August 21, 2026 20:07
@jd
jd deployed to func-tests-live August 21, 2026 20:08 — with GitHub Actions Active
@jd

jd commented Aug 21, 2026

Copy link
Copy Markdown
Member Author

Rebased onto main: e0d7867→9ed18bb.

#1778 landed, so Cargo.lock now carries h2 0.4.17 and RUSTSEC-2026-0258 is gone — that was the only thing cargo-deny was red on, and ci-gate was just the aggregate behind it. The diff this PR owns is unchanged; the rebase also pulls in #1775.

cargo test -p mergify-stack -p mergify-cli is green on the rebased tree.

@mergify
mergify Bot deployed to Mergify Merge Protections August 21, 2026 20:08 Active
@mergify
mergify Bot requested a review from a team August 21, 2026 20:13
@mergify
mergify Bot requested a review from a team August 24, 2026 08:42
@mergify

mergify Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

This pull request spent 7 minutes in the queue, including 6 minutes 39 seconds running CI.

Required conditions to merge

@mergify mergify Bot added the queued label Aug 24, 2026
@mergify
mergify Bot merged commit 832a02e into main Aug 24, 2026
22 checks passed
@mergify
mergify Bot deleted the devs/jd/jd/mrgfy-8772-mergify-stack-push-stop-writing-depends-on-when-github/drop-depends-header-once-github-holds-stack--a15a76de branch August 24, 2026 11:58
@mergify mergify Bot removed the queued label Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants