You're right, two died. There's no limit in the workflow.
Added this logic to #195, as well.
18 votes · 16 up · 2 down
You're right, two died. There's no limit in the workflow.
Added this logic to #195, as well.
As far as I can see there's not actually an enforced cap as described above in the final merged code? Two PRs died today even though there are < 100 PRs currently.
The workflow uses pulls.list to fetch all open PRs, then checks pr.mergeable_state and pr.mergeable to detect conflicts. However, the pulls.list endpoint does not return these fields — they are only populated by the individual pulls.get endpoint, which computes mergeability on demand.
As a result, pr.mergeable_state and pr.mergeable are always undefined, and isUnmergeable is always false. The unmergeable penalty (5% base + 5x multiplier) has never applied to any PR.
Example: PR #84 currently has merge conflicts (mergeable: CONFLICTING, mergeable_state: dirty), but the workflow evaluated it with a 13.39% death chance instead of the ~50%+ it should have had.
Fix: Each PR needs an individual pulls.get call to retrieve mergeability info:
const { data: fullPr } = await github.rest.pulls.get({
owner, repo, pull_number: pr.number
});
const isUnmergeable =
fullPr.mergeable_state === 'dirty' ||
fullPr.mergeable === false;
Note that mergeable can be null while GitHub is still computing it, so a brief delay/retry may also be needed on first fetch.
Based on community feedback from @bigintersmind and @matthewmayer, I've added a death cap to prevent mass extinction events.
cap = max(1, floor(open_prs / 100))
When more PRs "die" than the cap allows, survivors are randomly selected from the condemned.
Raw% = probability before cap, Eff% = effective probability after cap, [!] = unmergeable
PR Age Int Raw% Eff% Risk Title
------ ---- ---- ----- ----- --------- --------
# 84 35d 5 90.2% 4.88% DANGER Add auto-refresh for PR data [!]
# 79 35d 8 84.8% 4.65% DANGER Show PR author stats [!]
# 82 35d 7 86.4% 4.45% DANGER Add emoji scoring and counts [!]
# 61 36d 21 76.5% 4.32% DANGER feat: chaotic website layout [!]
# 46 39d 27 84.2% 4.27% DANGER Make sure the title fizzbuzzes [!]
# 5 40d 61 76.8% 4.15% DANGER added informative video [!]
# 93 32d 8 74.1% 4.14% DANGER Add one big & one small PR rule [!]
# 12 40d 105 69.2% 4.01% DANGER Add 17 languages + snow [!]
# 92 32d 13 68.4% 4.00% DANGER Instant Override Merge [!]
# 15 40d 84 72.3% 3.86% DANGER Visibility boost to prev merge [!]
# 102 28d 3 70.7% 3.72% DANGER Bad Apple but it is openchaos [!]
# 87 34d 33 63.7% 3.41% DANGER Chore: adds Konami Code [!]
# 68 36d 53 64.4% 3.40% DANGER Implement asteroids [!]
# 123 26d 8 54.6% 2.90% DANGER Add Retro BSOD [!]
# 114 27d 20 47.5% 2.87% DANGER Adding DVD-Player [!]
# 125 26d 11 51.2% 2.62% DANGER add mad Chaos Points [!]
# 118 26d 13 49.4% 2.50% DANGER Add countdown to page title [!]
# 106 27d 20 47.5% 2.49% DANGER Replace eslint with Biome.js [!]
# 131 24d 10 46.4% 2.36% DANGER Add dynamic retro marquee [!]
# 104 27d 37 40.4% 2.34% DANGER Fix link to wrong repository [!]
# 141 20d 9 36.8% 2.17% DANGER IE6BrowserChrome.tsx [!]
# 140 21d 9 39.3% 2.08% DANGER add rick roll [!]
# 146 19d 9 34.3% 2.04% DANGER XP error dialogs + Start Menu [!]
# 117 26d 53 33.4% 1.77% AT RISK Random emoji swap midnight [!]
# 166 15d 6 28.9% 1.76% AT RISK reduce colors to 256 [!]
# 149 18d 11 30.0% 1.60% AT RISK allow owner's PRs in HoC [!]
# 147 18d 13 28.4% 1.58% AT RISK 69 > 67 [!]
# 157 16d 5 32.6% 1.55% AT RISK Create voting SSOT module [!]
# 152 16d 12 24.8% 1.46% AT RISK Pageview counter tracking [!]
# 180 12d 5 24.5% 1.44% AT RISK Chaos Button for Destruction [!]
# 164 15d 8 26.4% 1.41% AT RISK randomize visitor counter [!]
# 156 16d 7 29.7% 1.41% AT RISK RULES.md deprecated clarify [!]
# 165 15d 6 28.9% 1.38% AT RISK Make minimize button work [!]
# 170 14d 13 20.0% 1.11% AT RISK Replace "nothing" w/ secret [!]
# 158 16d 25 17.7% 0.84% AT RISK weekly workflow close oldest [!]
# 188 6d 5 15.5% 0.79% AT RISK rate limits bag of dickbutts [!]
# 167 15d 38 11.7% 0.74% AT RISK REWRITE IT IN RUST [!]
# 45 40d 30 12.3% 0.67% AT RISK F, At least I tried
# 70 36d 26 9.7% 0.54% AT RISK Banner has something to say
# 72 36d 33 9.1% 0.45% LOW devcontainer for malicious
# 94 32d 20 7.6% 0.42% LOW Revert "Rewrite it in rust"
# 95 32d 15 8.3% 0.40% LOW log Guy Fieri ASCII art
# 111 27d 8 6.5% 0.31% LOW set repo name to rustychaos
# 137 22d 6 4.2% 0.29% LOW Bringing back democracy
# 133 23d 14 3.0% 0.17% LOW fishies scatter from cursor
# 155 16d 5 1.5% 0.11% LOW Branch protection test
# 115 26d 18 4.1% 0.11% LOW Upgrade Midi Player GTA radio
# 160 16d 9 0.5% 0.03% LOW Add robots.txt
# 181 12d 3 0.7% 0.01% LOW daily automated PR review bot
# 161 16d 9 0.5% 0.01% LOW Fix auto-merge unmergeable
# 143 20d 22 0.5% 0.01% LOW random themes chaotic dreams
# 168 15d 9 0.1% 0.00% LOW Mergeability detection
# 193 0d 2 0.0% 0.00% SAFE chaos terminal
# 192 0d 1 0.0% 0.00% SAFE Make it go whrrr
# 191 0d 2 0.0% 0.00% SAFE bonzi scheme meme
# 190 2d 4 0.0% 0.00% SAFE konami meow
# 187 7d 10 0.0% 0.00% SAFE Cat and Scat
# 185 11d 28 0.0% 0.00% SAFE old-age death (this PR)
# 184 12d 15 0.0% 0.00% SAFE Vote integrity inspection
# 183 12d 8 0.0% 0.00% SAFE Decimate: Alea Iacta Est
# 182 12d 9 0.0% 0.00% SAFE RULES.md is optional
# 163 16d 22 0.0% 0.00% SAFE Web 2.0 ASCII
# 159 16d 18 0.0% 0.00% SAFE BOUNTY HUNT Random Upvoter
I agree with your suggestions to reduce the dirty multiplier and cap it at 1/day, @matthewmayer.
Regardless of multiplier settings, capping at 1 death/day turns it from mass extinction into a sustainable daily drama. In that vein, maybe it's worth immortalizing the culled PRs on the front page somehow?
Also, a grace period (ignoring dirty status for 24–48h after a daily merge) would help with the timezone fairness issue, but would add implementation complexity.
I really like the idea, but think we should tune it to be more fun than discouraging.
This seems way too aggressive at the moment then. It's pretty normal to need frequent rebasing to resolve conflicts after the daily merge. And agree it's going to be biased towards people whose time zone means they are awake after the daily merge. I would consider some combination of
I ran a Monte Carlo simulation (10,000 runs) against the current 64 open PRs to see how this workflow would play out.
The algorithm would kill ~17 PRs on its first run — over a quarter of all open PRs. The unmergeable + old PRs get hit hardest:
| PR | Age | Interactions | Death Chance |
|---|---|---|---|
| #84 | 32d | 5 | 79.3% |
| #46 | 37d | 27 | 76.8% |
| #82 | 32d | 7 | 75.6% |
| #79 | 32d | 8 | 74.1% |
| #5 | 38d | 61 | 69.5% |
| #12 | 38d | 105 | 62.1% |
Even #12 with 105 interactions still faces 62% death — the unmergeable 5x multiplier overwhelms the fitness protection.
| Day | Avg Deaths | Avg Alive |
|---|---|---|
| 1 | 17.2 | 46.8 |
| 2 | 9.5 | 37.3 |
| 3 | 5.8 | 31.5 |
| 4 | 4.0 | 27.5 |
| 5 | 2.9 | 24.6 |
| 6 | 2.2 | 22.4 |
| 7 | 1.7 | 20.7 |
After 7 days: ~21 survivors out of 64 (min 13, max 29 across simulations). Deaths front-load heavily as the high-risk PRs die first, then taper off.
dirty mergeable state is the dominant factor. The 5x unmergeable multiplier means any PR with merge conflicts and more than ~10 days of age is in serious danger, regardless of engagementdirty is the norm, not the exception. Since a PR merges daily, every other open PR touching the same files becomes conflicted. Authors may have less than 24 hours between the daily merge (09:00 UTC) and the old-age sweep (06:00 UTC) to rebase — and that window gets worse since the sweep runs before most people's working hours. In practice, the majority of PRs will carry the dirty state at any given time (39 of 64 currently do)behind) only has 10% daily risk. Same-aged dirty PRs face 60-80%dirtyThere is no per-day cap on deaths. In the worst simulated week, 51 of 64 PRs died. On day 1 alone, up to ~30 deaths are possible in an unlucky run. If the intent is gradual natural selection rather than a mass extinction event, a daily cap might be worth considering.
The Reaper comes with a fatal urge, Memento Mergi — remember to merge! But check #122 for one last time: To get this in, your title must rhyme!
I don't mind them opening a new PR with the same stuff :) I think that's great, but they would loose al votes ect. and I think it would clean it up in a fun and chaotic way!
i mean, you can reopen a closed PR (provided it hasnt been merged) and keep the existing votes
Fixed 💀
I don't mind them opening a new PR with the same stuff :) I think that's great, but they would loose al votes ect. and I think it would clean it up in a fun and chaotic way!
i mean, you can reopen a closed PR (provided it hasnt been merged) and keep the existing votes
The problem with these various attempts to auto-close old PRs is that nothing prevents the author from reopening them again. If you really want to prevent old PRs from being merged, you need a rule that excludes them.
🤖 OpenChaos Bot
Summary: This PR introduces a GitHub Action that automatically closes old and inactive pull requests based on an age and interaction-based "natural selection" algorithm. It calculates a "death probability" for each PR, and if the PR "dies", it's closed with a detailed comment explaining its demise.
Files changed: 1 (.github/workflows/old-age.yml)
Vibe: This PR is playing God with pull requests, deciding their fate with the cold, uncaring logic of an algorithm and a dash of morbid humor.
You're right, two died. There's no limit in the workflow.
Added this logic to #195, as well.
As far as I can see there's not actually an enforced cap as described above in the final merged code? Two PRs died today even though there are < 100 PRs currently.
The workflow uses pulls.list to fetch all open PRs, then checks pr.mergeable_state and pr.mergeable to detect conflicts. However, the pulls.list endpoint does not return these fields — they are only populated by the individual pulls.get endpoint, which computes mergeability on demand.
As a result, pr.mergeable_state and pr.mergeable are always undefined, and isUnmergeable is always false. The unmergeable penalty (5% base + 5x multiplier) has never applied to any PR.
Example: PR #84 currently has merge conflicts (mergeable: CONFLICTING, mergeable_state: dirty), but the workflow evaluated it with a 13.39% death chance instead of the ~50%+ it should have had.
Fix: Each PR needs an individual pulls.get call to retrieve mergeability info:
const { data: fullPr } = await github.rest.pulls.get({
owner, repo, pull_number: pr.number
});
const isUnmergeable =
fullPr.mergeable_state === 'dirty' ||
fullPr.mergeable === false;
Note that mergeable can be null while GitHub is still computing it, so a brief delay/retry may also be needed on first fetch.
Based on community feedback from @bigintersmind and @matthewmayer, I've added a death cap to prevent mass extinction events.
cap = max(1, floor(open_prs / 100))
When more PRs "die" than the cap allows, survivors are randomly selected from the condemned.
Raw% = probability before cap, Eff% = effective probability after cap, [!] = unmergeable
PR Age Int Raw% Eff% Risk Title
------ ---- ---- ----- ----- --------- --------
# 84 35d 5 90.2% 4.88% DANGER Add auto-refresh for PR data [!]
# 79 35d 8 84.8% 4.65% DANGER Show PR author stats [!]
# 82 35d 7 86.4% 4.45% DANGER Add emoji scoring and counts [!]
# 61 36d 21 76.5% 4.32% DANGER feat: chaotic website layout [!]
# 46 39d 27 84.2% 4.27% DANGER Make sure the title fizzbuzzes [!]
# 5 40d 61 76.8% 4.15% DANGER added informative video [!]
# 93 32d 8 74.1% 4.14% DANGER Add one big & one small PR rule [!]
# 12 40d 105 69.2% 4.01% DANGER Add 17 languages + snow [!]
# 92 32d 13 68.4% 4.00% DANGER Instant Override Merge [!]
# 15 40d 84 72.3% 3.86% DANGER Visibility boost to prev merge [!]
# 102 28d 3 70.7% 3.72% DANGER Bad Apple but it is openchaos [!]
# 87 34d 33 63.7% 3.41% DANGER Chore: adds Konami Code [!]
# 68 36d 53 64.4% 3.40% DANGER Implement asteroids [!]
# 123 26d 8 54.6% 2.90% DANGER Add Retro BSOD [!]
# 114 27d 20 47.5% 2.87% DANGER Adding DVD-Player [!]
# 125 26d 11 51.2% 2.62% DANGER add mad Chaos Points [!]
# 118 26d 13 49.4% 2.50% DANGER Add countdown to page title [!]
# 106 27d 20 47.5% 2.49% DANGER Replace eslint with Biome.js [!]
# 131 24d 10 46.4% 2.36% DANGER Add dynamic retro marquee [!]
# 104 27d 37 40.4% 2.34% DANGER Fix link to wrong repository [!]
# 141 20d 9 36.8% 2.17% DANGER IE6BrowserChrome.tsx [!]
# 140 21d 9 39.3% 2.08% DANGER add rick roll [!]
# 146 19d 9 34.3% 2.04% DANGER XP error dialogs + Start Menu [!]
# 117 26d 53 33.4% 1.77% AT RISK Random emoji swap midnight [!]
# 166 15d 6 28.9% 1.76% AT RISK reduce colors to 256 [!]
# 149 18d 11 30.0% 1.60% AT RISK allow owner's PRs in HoC [!]
# 147 18d 13 28.4% 1.58% AT RISK 69 > 67 [!]
# 157 16d 5 32.6% 1.55% AT RISK Create voting SSOT module [!]
# 152 16d 12 24.8% 1.46% AT RISK Pageview counter tracking [!]
# 180 12d 5 24.5% 1.44% AT RISK Chaos Button for Destruction [!]
# 164 15d 8 26.4% 1.41% AT RISK randomize visitor counter [!]
# 156 16d 7 29.7% 1.41% AT RISK RULES.md deprecated clarify [!]
# 165 15d 6 28.9% 1.38% AT RISK Make minimize button work [!]
# 170 14d 13 20.0% 1.11% AT RISK Replace "nothing" w/ secret [!]
# 158 16d 25 17.7% 0.84% AT RISK weekly workflow close oldest [!]
# 188 6d 5 15.5% 0.79% AT RISK rate limits bag of dickbutts [!]
# 167 15d 38 11.7% 0.74% AT RISK REWRITE IT IN RUST [!]
# 45 40d 30 12.3% 0.67% AT RISK F, At least I tried
# 70 36d 26 9.7% 0.54% AT RISK Banner has something to say
# 72 36d 33 9.1% 0.45% LOW devcontainer for malicious
# 94 32d 20 7.6% 0.42% LOW Revert "Rewrite it in rust"
# 95 32d 15 8.3% 0.40% LOW log Guy Fieri ASCII art
# 111 27d 8 6.5% 0.31% LOW set repo name to rustychaos
# 137 22d 6 4.2% 0.29% LOW Bringing back democracy
# 133 23d 14 3.0% 0.17% LOW fishies scatter from cursor
# 155 16d 5 1.5% 0.11% LOW Branch protection test
# 115 26d 18 4.1% 0.11% LOW Upgrade Midi Player GTA radio
# 160 16d 9 0.5% 0.03% LOW Add robots.txt
# 181 12d 3 0.7% 0.01% LOW daily automated PR review bot
# 161 16d 9 0.5% 0.01% LOW Fix auto-merge unmergeable
# 143 20d 22 0.5% 0.01% LOW random themes chaotic dreams
# 168 15d 9 0.1% 0.00% LOW Mergeability detection
# 193 0d 2 0.0% 0.00% SAFE chaos terminal
# 192 0d 1 0.0% 0.00% SAFE Make it go whrrr
# 191 0d 2 0.0% 0.00% SAFE bonzi scheme meme
# 190 2d 4 0.0% 0.00% SAFE konami meow
# 187 7d 10 0.0% 0.00% SAFE Cat and Scat
# 185 11d 28 0.0% 0.00% SAFE old-age death (this PR)
# 184 12d 15 0.0% 0.00% SAFE Vote integrity inspection
# 183 12d 8 0.0% 0.00% SAFE Decimate: Alea Iacta Est
# 182 12d 9 0.0% 0.00% SAFE RULES.md is optional
# 163 16d 22 0.0% 0.00% SAFE Web 2.0 ASCII
# 159 16d 18 0.0% 0.00% SAFE BOUNTY HUNT Random Upvoter
I agree with your suggestions to reduce the dirty multiplier and cap it at 1/day, @matthewmayer.
Regardless of multiplier settings, capping at 1 death/day turns it from mass extinction into a sustainable daily drama. In that vein, maybe it's worth immortalizing the culled PRs on the front page somehow?
Also, a grace period (ignoring dirty status for 24–48h after a daily merge) would help with the timezone fairness issue, but would add implementation complexity.
I really like the idea, but think we should tune it to be more fun than discouraging.
This seems way too aggressive at the moment then. It's pretty normal to need frequent rebasing to resolve conflicts after the daily merge. And agree it's going to be biased towards people whose time zone means they are awake after the daily merge. I would consider some combination of
I ran a Monte Carlo simulation (10,000 runs) against the current 64 open PRs to see how this workflow would play out.
The algorithm would kill ~17 PRs on its first run — over a quarter of all open PRs. The unmergeable + old PRs get hit hardest:
| PR | Age | Interactions | Death Chance |
|---|---|---|---|
| #84 | 32d | 5 | 79.3% |
| #46 | 37d | 27 | 76.8% |
| #82 | 32d | 7 | 75.6% |
| #79 | 32d | 8 | 74.1% |
| #5 | 38d | 61 | 69.5% |
| #12 | 38d | 105 | 62.1% |
Even #12 with 105 interactions still faces 62% death — the unmergeable 5x multiplier overwhelms the fitness protection.
| Day | Avg Deaths | Avg Alive |
|---|---|---|
| 1 | 17.2 | 46.8 |
| 2 | 9.5 | 37.3 |
| 3 | 5.8 | 31.5 |
| 4 | 4.0 | 27.5 |
| 5 | 2.9 | 24.6 |
| 6 | 2.2 | 22.4 |
| 7 | 1.7 | 20.7 |
After 7 days: ~21 survivors out of 64 (min 13, max 29 across simulations). Deaths front-load heavily as the high-risk PRs die first, then taper off.
dirty mergeable state is the dominant factor. The 5x unmergeable multiplier means any PR with merge conflicts and more than ~10 days of age is in serious danger, regardless of engagementdirty is the norm, not the exception. Since a PR merges daily, every other open PR touching the same files becomes conflicted. Authors may have less than 24 hours between the daily merge (09:00 UTC) and the old-age sweep (06:00 UTC) to rebase — and that window gets worse since the sweep runs before most people's working hours. In practice, the majority of PRs will carry the dirty state at any given time (39 of 64 currently do)behind) only has 10% daily risk. Same-aged dirty PRs face 60-80%dirtyThere is no per-day cap on deaths. In the worst simulated week, 51 of 64 PRs died. On day 1 alone, up to ~30 deaths are possible in an unlucky run. If the intent is gradual natural selection rather than a mass extinction event, a daily cap might be worth considering.
The Reaper comes with a fatal urge, Memento Mergi — remember to merge! But check #122 for one last time: To get this in, your title must rhyme!
I don't mind them opening a new PR with the same stuff :) I think that's great, but they would loose al votes ect. and I think it would clean it up in a fun and chaotic way!
i mean, you can reopen a closed PR (provided it hasnt been merged) and keep the existing votes
Fixed 💀
I don't mind them opening a new PR with the same stuff :) I think that's great, but they would loose al votes ect. and I think it would clean it up in a fun and chaotic way!
i mean, you can reopen a closed PR (provided it hasnt been merged) and keep the existing votes
The problem with these various attempts to auto-close old PRs is that nothing prevents the author from reopening them again. If you really want to prevent old PRs from being merged, you need a rule that excludes them.
🤖 OpenChaos Bot
Summary: This PR introduces a GitHub Action that automatically closes old and inactive pull requests based on an age and interaction-based "natural selection" algorithm. It calculates a "death probability" for each PR, and if the PR "dies", it's closed with a detailed comment explaining its demise.
Files changed: 1 (.github/workflows/old-age.yml)
Vibe: This PR is playing God with pull requests, deciding their fate with the cold, uncaring logic of an algorithm and a dash of morbid humor.