Skip to content

✨ Credit issue authors on clanker-opened PRs at merge time - #14585

Merged
hivecommons-hive[bot] merged 2 commits into
v5from
feat/merge-issue-author-credit
Oct 27, 2026
Merged

hivecommons-hive[bot] merged 2 commits into
v5from
feat/merge-issue-author-credit

Conversation

@clubanderson

Copy link
Copy Markdown
Member

Fixes #14581

What

Every hive-performed merge now credits the human authors of the issues a PR closes with Co-authored-by: <login> <id+login@users.noreply.github.com> trailers on the squash (or merge) commit, so a reporter whose issue was fixed by an external clanker lands on the contributor graph the way they already do when the hive opens the PR (RFC #6588 / #7208).

Where the trailer is injected

  • pkg/github/merge_credit.go — MergeCreditor.Prepare: parses Fixes|Closes|Resolves #N from the PR body (reuses ParseClaimedIssues), one cached GET /issues/{n} per newly referenced issue (WithRESTCaller(ctx, "hive:merge_credit")), skips bots/Apps (type=Bot, [bot]/-bot, github-actions*), the PR author, issues that are PRs; de-dupes against Co-authored-by lines already on the branch (noreply address or login).
  • pkg/github/automerge/automerge_merge_credit.go — Engine.mergeOptions, used by all four sweep Merge call sites (self-authored, trusted-author, queue, contributor lane).
  • pkg/github/pullrequest.go MergePRVia — hive-merge relay / forge path.
  • Squash body is rebuilt from the branch commits (subject/body/Signed-off-by preserved, merge-from-base commits skipped) with the trailers appended after a blank line; merge-method/merge → trailer on the merge commit; rebase → untouched. If commits cannot be read, GitHub's default message is kept.
  • Evidence: issue_authors= kv on the pr_merged audit entry and MergeEvent.IssueAuthors in review evidence.
  • Config: auto_merge.credit_issue_authors (default true), documented in operator-reference.md; attribution section in hive-merge.md.

Tests

pkg/github/merge_credit_test.go (trailer composition, dedupe, bot/self skip, multi-issue, cache, disabled, rebase, merge method, missing issue, commits error, MergePRVia on/off) and pkg/github/automerge/automerge_merge_credit_test.go (contributor-lane squash message with two preserved sign-offs, config off → no commit_message and zero issue/commit reads, self skip, hive-opened PR with existing trailer → no duplicate). No time.Sleep. Coverage: pkg/github 88.9%, automerge 90.0%, evidence 96.8%, config 90.5%.

Also fixed the scale-envelope.md line citation that moved with client.go.

Every hive-performed merge (self-authored, trusted-author, contributor-lane
and queue sweeps, hive-merge relay) now appends Co-authored-by trailers for
the human authors of the issues the PR closes to the squash (or merge)
commit message, so reporters land on the contributor graph when an external
clanker fixed their issue — not only when the hive opened the PR itself.

Bots/Apps, the PR author and logins already credited on the branch are
skipped; branch commit bodies and Signed-off-by lines are reproduced ahead
of the new trailers; the logins are recorded as issue_authors= on the merge
audit entry and in review-evidence merge.issue_authors. One cached
GET /issues/{n} per newly referenced issue, attributed hive:merge_credit.
Switch: auto_merge.credit_issue_authors (default on).

Fixes #14581

Signed-off-by: Andrew Anderson <andy@clubanderson.com>
@kubestellar-prow kubestellar-prow Bot added the dco-signoff: yes Indicates the PR's author has signed the DCO. label Oct 27, 2026
@kubestellar-prow

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign clubanderson for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@kubestellar-prow kubestellar-prow Bot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Oct 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Changelog fragment in the wrong directory

Fragments live in changelog.d/ at the repository root, not under src/. Files under src/changelog.d/ are never compiled into CHANGELOG.md, so the changelog-fragment-guard check fails. Move them and push:

git mv src/changelog.d/added-merge-issue-author-credit.md changelog.d/added-merge-issue-author-credit.md
git commit -s -m "changelog: move fragment to repo-root changelog.d/"

See changelog.d/README.md (#5675, #11919). This comment is removed automatically once nothing is misplaced.

@hivecommons-hive

Copy link
Copy Markdown
Contributor

@clubanderson is auto-promoted for contributor-lane merging on this PR: the last 5 merged PRs by this author in this hive's repositories have no revert or sentinel-alert evidence. CI, reviewer verdict, diff fences, soak, holds and branch protection still apply.

@hivecommons-hive hivecommons-hive Bot added author/human A person pushed this PR themselves dco All commits are DCO signed-off role/trusted Author is trusted for unattended merge (trusted-author role or registry/claim tier in require_tiers) stage/050-review-pending Review swarm requested; awaiting a verdict for the current head and removed role/trusted Author is trusted for unattended merge (trusted-author role or registry/claim tier in require_tiers) labels Oct 27, 2026
@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Open PR overlap check

Base branch: v5

Conflicts are checked with every PR merged onto the current tip of v5, so a PR that only needs a rebase is not reported as conflicting with its siblings.

PR Title Relation Files
#14595 ✨ feat: mark lanes unauthorized when the App lacks rights for the next step same files src/pkg/github/automerge/automerge_contributor_lane.go
src/pkg/github/automerge/automerge_contributor_lane_test.go
src/pkg/github/automerge/automerge_sweep.go
#14582 ✨ House-style section every kick opens with: repo HIVE_STYLE.md > hive default > built-in same files src/docs/operator-reference.md
src/pkg/config/config.go
src/pkg/dashboard/settings_parity_allowlist.txt
#14524 ✨ feat(hub,agent): Hub-coordinated live CLI session pool for multi-tenant runner capacity same files src/cmd/hive/main.go

@hivecommons-hive hivecommons-hive Bot added stage/071-needs-author Human-authored PR: CI red, changes requested or conflicting; diagnosis posted, the author must act and removed stage/050-review-pending Review swarm requested; awaiting a verdict for the current head labels Oct 27, 2026
@hivecommons-hive

Copy link
Copy Markdown
Contributor

@clubanderson this PR is held at stage/071-needs-author and the hive will not merge it yet.

Failing checks:

  • test (dashboard 2/4)
  • test (dashboard shuffle 2/3)

Next: the hive does not push to your branch. Push a new head (or reply here); CI and the review swarm re-run automatically and the PR returns to the normal path.

@hivecommons-hive hivecommons-hive Bot 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.

Read the core (merge_credit.go), all four sweep call sites, MergePRVia, and the audit/evidence hand-off at the PR head; go build of pkg/github, pkg/github/automerge, pkg/config, pkg/evidence is clean. Looks correct to me.

What I verified:

  • go-github's PullRequests.Merge(..., commitMessage, opts) maps the fifth argument to commit_message only; opts.CommitTitle stays unset in automerge_merge_credit.go:26 and pullrequest.go:434, so GitHub still writes its default <title> (#N) subject. Only the body is replaced.
  • squashCreditMessage (merge_credit.go:318-348) reproduces GitHub's COMMIT_MESSAGES squash body (single commit → body only; several → * subject + body each) and keeps every Signed-off-by in place. On a commit-list read error Prepare returns an empty message (merge_credit.go:196-203), so the DCO trail is never dropped for the trailer.
  • uncreditedAuthors (merge_credit.go:277-307) matches by noreply address and by login (both id+login and bare local part), so a hive-opened PR that already carries issue-coauthor.sh's trailer is not double-credited.
  • MergePRVia (pullrequest.go:421-451): the credit reuses the PR already fetched for forward-merge resolution; only a merge-method call fetches it fresh, and only when the switch is on. fetchedTried prevents a second GET after a failed one.
  • RecordPRMergedAudit consumes the note via takeMergeCredit (client.go:4386), so the stash cannot leak across merges of the same number.

Two notes, neither a defect:

  1. Documented assumption. The rebuilt body matches GitHub's default only when the target repo's squash_merge_commit_message is COMMIT_MESSAGES. I checked hive, rationguard and crux — all three are, so behaviour is unchanged for them. On a repo configured PR_BODY or BLANK, enabling this (default true) silently switches the squash body to the commit messages. Worth one sentence in the operator-reference.md:430 row so an operator on such a repo knows to set credit_issue_authors: false.
  2. MergeCreditor.Enabled reads m.enabled unlocked while SetCreditIssueAuthors (merge_credit.go:388-397) rewrites it on every review-config PUT (main.go:1644 → installReviewRelaySettings). This mirrors the existing SetReviewEvidence idiom (review_evidence.go:67), so it is not a regression — just noting the sweep can observe it concurrently.

— hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88

@github-actions

Copy link
Copy Markdown
Contributor

Changelog: this PR changes code but carries no changelog entry
(no changelog.d/ fragment and no CHANGELOG.md edit).

If it is user-visible — a feature, a fix an operator would notice, a
security change, a migration, a deprecation, or anything breaking —
please add a fragment file changelog.d/<category>-<pr-or-slug>.md
containing exactly your entry (see changelog.d/README.md; the
category is one of added/changed/deprecated/fixed/security). Please
do not append to CHANGELOG.md's ## Unreleased directly — that
shared section is the merge-conflict generator fragments replaced
(#5675). If it is a refactor, a test-only change, or dependency
churn, no entry is needed and you can ignore this.

This is a reminder, not a gate; it never blocks a merge.

The switch is yaml-only, like auto_merge.squash_only.

Signed-off-by: Andrew Anderson <andy@clubanderson.com>
@hivecommons-hive

Copy link
Copy Markdown
Contributor

@clubanderson this PR is held at stage/071-needs-author and the hive will not merge it yet.

Failing checks:

  • changelog-fragment-guard

Next: the hive does not push to your branch. Push a new head (or reply here); CI and the review swarm re-run automatically and the PR returns to the normal path.

@hivecommons-hive hivecommons-hive Bot added stage/050-review-pending Review swarm requested; awaiting a verdict for the current head and removed stage/071-needs-author Human-authored PR: CI red, changes requested or conflicting; diagnosis posted, the author must act labels Oct 27, 2026
@hivecommons-hive
hivecommons-hive Bot merged commit 4d1642c into v5 Oct 27, 2026
74 of 78 checks passed
@kubestellar-prow
kubestellar-prow Bot deleted the feat/merge-issue-author-credit branch October 27, 2026 15:45
@hivecommons-hive

Copy link
Copy Markdown
Contributor
Evidence bundle `#14585fb5eeec` sha256:a471dbb4b1db775c4ef7c657ade82781a5c7152f0a8082366793c68fd21261ea — download from the dashboard or `hivectl review evidence #14585`.

@hivecommons-hive

Copy link
Copy Markdown
Contributor

merged by Hive trusted-author auto-merge: author @clubanderson holds role owner and GitHub permission admin on repo; CI green at fb5eeec.

@hivecommons-hive hivecommons-hive Bot removed the role/trusted Author is trusted for unattended merge (trusted-author role or registry/claim tier in require_tiers) label Oct 27, 2026
@hivecommons-hive hivecommons-hive Bot removed the stage/050-review-pending Review swarm requested; awaiting a verdict for the current head label Oct 27, 2026

@hivecommons-hive hivecommons-hive Bot 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.

Read merge_credit.go, the four sweep call sites, MergePRVia, and RecordPRMergedAudit against the tree at fb5eeec; go build ./pkg/github/... ./pkg/config/ ./pkg/evidence/ passes. The credit logic looks correct to me: Prepare never fails the merge, rebase is skipped, merge-from-base commits are excluded from the rebuilt squash body (merge_credit.go:323), every commit message — Signed-off-by included — is kept verbatim, and uncreditedAuthors dedupes by id-prefixed address and by login so hive-opened PRs don't gain a second trailer. The takeMergeCredit hand-off into the audit/evidence path is consumed exactly once.

One blocker, and it is the red check — the changelog fragment is in the wrong directory.
src/changelog.d/added-merge-issue-author-credit.md should be changelog.d/added-merge-issue-author-credit.md. The guard treats src/changelog.d/ as misplaced and refuses to autofix it: .github/workflows/changelog-fragment-guard.yml:181-190 — "A fragment under src/changelog.d/ is never compiled … fail with the move instruction instead" → ::error … Run: git mv $m changelog.d/$(basename "$m") and exit 1. That is the changelog-fragment-guard FAILURE on this head; the PR will stay UNSTABLE until the file moves.

Open question (not a defect, I could not verify it from the tree): the squash body is rebuilt in GitHub's commit-messages format (* subject + body per commit, merge_credit.go:316-351). Nothing in pkg/ reads a repo's squash_merge_commit_message setting, so on a repo configured for "PR title and description" a credited merge would replace the PR-body squash message with commit bullets. The existing "Sign-off survives the squash" check implies the hive's repos already use the commit-messages default, so this is probably moot — flagging only so the operator doc (hive-merge.md attribution section) can say which setting is assumed.

— hive: agent=reviewer-2 backend=copilot model=claude-fable-5.1 copilot=1.0.88

@hivecommons-hive hivecommons-hive Bot 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.

Read merge_credit.go, automerge_merge_credit.go, the four sweep call sites and MergePRVia against v5 at merge-base 7d61076; checked the repo's merge settings (squash_merge_commit_message=COMMIT_MESSAGES, merge_commit_message=PR_TITLE), which is exactly the shape squashCreditMessage / mergeCommitCreditMessage rebuild. The mechanics look correct to me; one concrete fix is needed for the red check, and one open question.

Fix needed — the red changelog-fragment-guard. The fragment is at src/changelog.d/added-merge-issue-author-credit.md, but the convention is repo-root changelog.d/ (see changelog.d/README.md and the existing changelog.d/added-13290-relay-status.md style). .github/workflows/changelog-fragment-guard.yml:132 copies src/changelog.d/ fragments into the rejected set and :181 says "A fragment under src/changelog.d/ is never compiled". Move it to changelog.d/added-14585-merge-issue-author-credit.md and the check should go green.

Open question (not verified, so not a defect): when the hive squash-merges with GitHub's default message, GitHub generates Co-authored-by: trailers for branch commit authors who differ from the PR author. Once commit_message is supplied (automerge_merge_credit.go:37, pullrequest.go:449), the body is the one we send, and squashCreditMessage (merge_credit.go:300-335) rebuilds only from commit messages, not commit authors. If GitHub does not add those trailers to a supplied message, a mixed-author branch (e.g. a human pushing a fix onto a bot PR, or the reverse) would lose the auto co-author it gets today — every time the PR closes an issue with a human author. I could not confirm GitHub's behaviour from the docs; worth checking on one real mixed-author squash before relying on it, or carrying distinct commit authors into the trailer block as well.

What I verified as correct:

  • cachedPRRework-style caching in issueAuthor (merge_credit.go:220-247) is mutex-guarded; Enabled/Prepare/MergeCreditor() are nil-safe, so the MergePRVia path with no API client (pullrequest.go:442) and test transports lacking mergeCreditTransport merge exactly as before.
  • Rebase returns an empty credit (merge_credit.go:160); commits read failure keeps GitHub's default message (:190), so no path can drop a Signed-off-by.
  • uncreditedAuthors (:270-298) matches by both noreply address and login, so hive-opened PRs with issue-coauthor.sh trailers are not double-credited.
  • takeMergeCredit consumes the stash on the pr_merged audit (client.go recordMerge path), so issue_authors= only appears for merges that actually happened.

— hive: agent=reviewer backend=copilot model=claude-fable-5.1 copilot=1.0.88

@github-actions

Copy link
Copy Markdown
Contributor

Thank you for your contribution! Your PR has been merged.

We'd love to hear how your experience was: share feedback

clubanderson added a commit that referenced this pull request Oct 27, 2026
Second-round catch-up for #14340: the 7 v5 commits that landed after the
main forward-merge (#14585 credit issue authors, #14583, #14579 merge gate
follows live sentinel label / HumanApprover, #14580, #14571, #14427, #14428).

Hand-resolved (16 files):
- stagelabels/human.go: union of v6 Route.ManualMerge and v5 HumanApprover,
  ManualMergeRule, LaneReason.
- config: v5 auto_merge.credit_issue_authors applied in review_config.go
  (v6 moved AutoMergeConfig there).
- github/review_evidence*: v5 (blocked param, Notice = !blocked);
  sentinel_sweep.go keeps v6 adoption handling with the v5 one-line change.
- automerge: linked-issue gate (v6 #14184 fallout) now seeds the v5
  MergeCreditor's author cache so a merge-ready PR costs one issue GET;
  v5's lane-side decisionActions test dropped (v6 renders actions in
  stagelabels.DecisionActions).
- dashboard/stage_tracker.go: v5 #14579 stageTrackerSentinel supersedes v6
  #14053 (cleared label: alert off, findings still fill the tooltip).
- dashboard/server.go: v5 FleetRun + v6 AdmissionLabels; index.html: v5
  attention title + v6 "Hive end to end first" sort.
- docs: v5 text with v6-only sentences re-applied; api-reference citations
  regenerated.

Signed-off-by: Andrew Anderson <andy@clubanderson.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author/human A person pushed this PR themselves dco All commits are DCO signed-off dco-signoff: yes Indicates the PR's author has signed the DCO. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

✨ Credit issue authors on clanker-opened PRs at merge time

1 participant