Skip to content

Honor GitHub approvals carried over a clean master merge#469

Merged
ianrohde merged 1 commit into
masterfrom
honor-carried-over-approval
Jun 19, 2026
Merged

Honor GitHub approvals carried over a clean master merge#469
ianrohde merged 1 commit into
masterfrom
honor-carried-over-approval

Conversation

@ianrohde

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #463. A GitHub native Approve review (now mapped to a CR signoff) carries over a clean master merge — GitHub only dismisses the review when the diff actually changes. Pulldasher dropped the CR anyway, so GitHub showed the PR approved while the Pulldasher CR bubble was empty.

Root cause

Two paths killed the carried-over approval:

  1. lib/git-manager.js — the full refresh marks any CR/QA whose timestamp predates the head commit inactive. An approval's submitted_at legitimately predates a later merge commit, so every refresh re-killed it.
  2. controllers/githubHooks.js (synchronize) — a master merge fires only synchronize, which blanket-invalidated CR/QA and never re-derived review state. With no periodic poll (only startup refresh.openPulls), the approval stayed dropped until restart.

Fix

  • Tag the synthesized approval CR with fromGithubApproval (models/signature.js), in-memory only — not persisted.
  • Exempt those signatures from the commit-date staleness check (lib/git-manager.js). GitHub is the source of truth: if the review is still APPROVED at refresh time, the approval is valid; if a commit should kill it, GitHub returns a non-APPROVED state and parseReview synthesizes no CR.
  • After the synchronize invalidate, run a full refresh.pull to re-derive review state (controllers/githubHooks.js). The immediate invalidate stays for snappy UI; the refresh refills only the still-valid approval.

Tradeoff

One extra full refresh per push per tracked PR. The ETag cache makes these mostly 304s, so no rate-limit hit.

Known edge (unchanged)

A reviewer who both approves natively and writes CR :emoji: → dedup keeps the emoji CR (not exempt), so it still invalidates on merge. Pre-existing dedup behavior, left as-is.

Test plan

  • npm test — asserts fromGithubApproval true for native approval, false for emoji CR
  • npm run lint
  • Manual: approve a PR on GitHub, merge master cleanly into the branch, confirm the CR bubble stays filled in Pulldasher
  • Manual: push a real code change after approval, confirm GitHub dismisses and the CR bubble drops

A GitHub native "Approve" review (mapped to a CR signoff in #463) carries
over a clean master merge — GitHub only dismisses the review when the diff
actually changes. Pulldasher dropped the CR anyway:

- git-manager marked any CR/QA whose timestamp predated the head commit
  inactive. An approval's `submitted_at` legitimately predates a later
  merge commit, so the full refresh re-killed it.
- the `synchronize` webhook blanket-invalidated CR/QA and never re-derived
  review state, and there is no periodic poll, so the approval stayed
  dropped until restart.

Tag approval-derived CR signatures (`fromGithubApproval`) and exempt them
from the commit-date staleness check — GitHub is the source of truth for
whether the approval is still valid. Follow the `synchronize` invalidate
with a full refresh so a carried-over approval is restored on the next
push. The immediate invalidate stays for snappy UI feedback.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ianrohde ianrohde marked this pull request as ready for review June 18, 2026 20:53

@jarstelfox jarstelfox 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.

CR 🌵

@ianrohde

Copy link
Copy Markdown
Contributor Author

QA 🟢

@ianrohde ianrohde merged commit 127d4fd into master Jun 19, 2026
1 check passed
@ianrohde ianrohde deleted the honor-carried-over-approval branch June 19, 2026 00:14
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