SRE-588: own stale approval logic and detect manual conflict resolutions#8577
SRE-588: own stale approval logic and detect manual conflict resolutions#8577
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This stack of pull requests is managed by Graphite. Learn more about stacking. |
PR SummaryMedium Risk Overview The action now persists previous run SHAs via artifacts to keep Updates the workflow to run the real dismissal only on Written by Cursor Bugbot for commit 1c9ff7e. This will update automatically on new commits. Configure here. |
🤖 Augment PR SummarySummary: Moves stale-approval dismissal logic in-repo and expands it to detect manual merge-conflict resolutions that can change code after an approval. Changes:
Technical Notes: Includes a bash self-test harness and a new 🤖 Was this summary useful? React with 👍 or 👎 |
.github/actions/dismiss-stale-approvals/check-manual-merge-resolutions.sh
Outdated
Show resolved
Hide resolved
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #8577 +/- ##
=======================================
Coverage 62.49% 62.49%
=======================================
Files 1318 1318
Lines 134209 134209
Branches 5517 5517
=======================================
+ Hits 83876 83880 +4
+ Misses 49418 49414 -4
Partials 915 915 Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
@TimDiekmann after thinking about this vendorizing approach, it turns out there's withgraphite/dismiss-stale-approvals, which might be a better option |
There was a problem hiding this comment.
Conceptually, this looks all good, thank you!
I have a few mechanical things, which should be quick to fix.
it turns out there's withgraphite/dismiss-stale-approvals, which might be a better option
We currently use a fork of that which has lead to this ticket. In particular withgraphite/dismiss-stale-approvals#8 is not getting any attention and the workflow does not properly detect merge-commit changes.
|
Ah... OK then no. Codex agrees anyway, with the following reasons stated:
|
|
@TimDiekmann thanks for the very careful review, I think all points are now addressed |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 3 total unresolved issues (including 2 from previous reviews).
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Benchmark results
|
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 2002 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 1001 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: high, policies: 3314 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: medium, policies: 1526 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 2078 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 1033 | Flame Graph |
policy_resolution_medium
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 102 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 51 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: high, policies: 269 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: medium, policies: 107 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 133 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 63 | Flame Graph |
policy_resolution_none
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 2 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 8 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 3 | Flame Graph |
policy_resolution_small
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| resolve_policies_for_actor | user: empty, selectivity: high, policies: 52 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: empty, selectivity: medium, policies: 25 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: high, policies: 94 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: seeded, selectivity: medium, policies: 26 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: high, policies: 66 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: low, policies: 1 | Flame Graph | |
| resolve_policies_for_actor | user: system, selectivity: medium, policies: 29 | Flame Graph |
read_scaling_complete
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_id;one_depth | 1 entities | Flame Graph | |
| entity_by_id;one_depth | 10 entities | Flame Graph | |
| entity_by_id;one_depth | 25 entities | Flame Graph | |
| entity_by_id;one_depth | 5 entities | Flame Graph | |
| entity_by_id;one_depth | 50 entities | Flame Graph | |
| entity_by_id;two_depth | 1 entities | Flame Graph | |
| entity_by_id;two_depth | 10 entities | Flame Graph | |
| entity_by_id;two_depth | 25 entities | Flame Graph | |
| entity_by_id;two_depth | 5 entities | Flame Graph | |
| entity_by_id;two_depth | 50 entities | Flame Graph | |
| entity_by_id;zero_depth | 1 entities | Flame Graph | |
| entity_by_id;zero_depth | 10 entities | Flame Graph | |
| entity_by_id;zero_depth | 25 entities | Flame Graph | |
| entity_by_id;zero_depth | 5 entities | Flame Graph | |
| entity_by_id;zero_depth | 50 entities | Flame Graph |
read_scaling_linkless
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_id | 1 entities | Flame Graph | |
| entity_by_id | 10 entities | Flame Graph | |
| entity_by_id | 100 entities | Flame Graph | |
| entity_by_id | 1000 entities | Flame Graph | |
| entity_by_id | 10000 entities | Flame Graph |
representative_read_entity
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/block/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1
|
Flame Graph | |
| entity_by_id | entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1
|
Flame Graph |
representative_read_entity_type
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| get_entity_type_by_id | Account ID: bf5a9ef5-dc3b-43cf-a291-6210c0321eba
|
Flame Graph |
representative_read_multiple_entities
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| entity_by_property | traversal_paths=0 | 0 | |
| entity_by_property | traversal_paths=255 | 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true | |
| entity_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true | |
| link_by_source_by_property | traversal_paths=0 | 0 | |
| link_by_source_by_property | traversal_paths=255 | 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true | |
| link_by_source_by_property | traversal_paths=2 | 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true |
scenarios
| Function | Value | Mean | Flame graphs |
|---|---|---|---|
| full_test | query-limited | Flame Graph | |
| full_test | query-unlimited | Flame Graph | |
| linked_queries | query-limited | Flame Graph | |
| linked_queries | query-unlimited | Flame Graph |


🌟 What is the purpose of this PR?
This PR closes the stale-approval gap described in SRE-588 by moving the workflow logic into this repo and teaching it to treat manual merge-conflict resolutions as approval-invalidating changes.
The original workflow depended on a forked action that only compared feature-commit ranges with
git range-diff, so merge commits with hand-resolved conflicts could change code after approval without dismissing reviews. This version keeps the existingrange-diffbehavior for stacked-PR safety, adds agit merge-treecheck for merge commits after the latest approval, and now fails safe if artifact lookup, approval lookup, or merge-resolution checking itself errors.🔗 Related links
🚫 Blocked by
🔍 What does this change?
turnage/dismiss-stale-approvalsdependency with a repo-owned composite action under.github/actions/dismiss-stale-approvalsgit range-diffdismissal behavior is preserved, while selecting the newest matching artifact deterministicallygit merge-treeto detect manual conflict resolutiondry-runbehavior by commenting on the PR instead of only logging locallyrange-diffstale parser between the action and self-test so the harness no longer reimplements that rule separatelygit range-diff-only check and does not address post-approval merge-commit conflict-resolution changesPre-Merge Checklist 🚀
🚢 Has this modified a publishable library?
This PR:
📜 Does this require a change to the docs?
The changes in this PR:
🕸️ Does this require a change to the Turbo Graph?
The changes in this PR:
action.ymltext directly rather than executing those paths through a runtime harness. That is a test-maintainability risk more than a stale-approval logic risk, and I wanted to leave it visible for reviewer judgment instead of widening this PR further without feedback.🐾 Next steps
self-test.shwith a more executable harness for action wiring🛡 What tests cover this?
npm run test:stale-approvalsbash .github/actions/dismiss-stale-approvals/self-test.shbash -n .github/actions/dismiss-stale-approvals/self-test.sh .github/actions/dismiss-stale-approvals/decide_stale_approvals.sh .github/actions/dismiss-stale-approvals/latest_approval_sha.sh .github/actions/dismiss-stale-approvals/check-manual-merge-resolutions.sh .github/actions/dismiss-stale-approvals/latest_artifact.sh .github/actions/dismiss-stale-approvals/dismiss-reviews.sh .github/actions/dismiss-stale-approvals/range_diff_stale.shshellcheck .github/actions/dismiss-stale-approvals/self-test.sh .github/actions/dismiss-stale-approvals/decide_stale_approvals.sh .github/actions/dismiss-stale-approvals/latest_approval_sha.sh .github/actions/dismiss-stale-approvals/check-manual-merge-resolutions.sh .github/actions/dismiss-stale-approvals/latest_artifact.sh .github/actions/dismiss-stale-approvals/dismiss-reviews.sh .github/actions/dismiss-stale-approvals/range_diff_stale.shyq '.' .github/workflows/dismiss-stale-approvals.yml >/dev/null && yq '.' .github/actions/dismiss-stale-approvals/action.yml >/dev/nullgit diff --check❓ How to test this?
.github/workflows/dismiss-stale-approvals.ymland confirm it uses./.github/actions/dismiss-stale-approvalsnpm run test:stale-approvalsrange-diffparsingbash .github/actions/dismiss-stale-approvals/self-test.shdirectly to confirm the package script is only a repo-visible entrypoint for the same harness.github/actions/dismiss-stale-approvals/to confirm the policy is repo-owned and split into focused helpers rather than an external forked action📹 Demo