Re-read pulls updated in the last 20 minutes - #503
probablyian wants to merge 3 commits into
Conversation
QA and CR stamps go missing from the board when a webhook never arrives, and GitHub doesn't resend it. Until now only a restart or the card's refresh button re-read the pull, and a restart only covers repos listed in config.repos. #502 has the pulls the board missed on 2026-09-29, including 8 in repos the config leaves out. Every 20 minutes the server now searches each owner in config.repos for pulls updated since the previous sweep started, open or closed: user:ifixit is:pr updated:>=2026-09-29T22:37:07Z and refreshes each hit through refresh.pull, one at a time. Searching by owner reaches every repo that owner holds, configured or not. Search returns closed pulls too, so a dropped close webhook heals within one sweep. Each window starts 5 minutes before the previous sweep started, since GitHub doesn't document how long search indexing takes. The first sweep runs 20 minutes after startup and reaches back to 25 minutes before startup, so it also covers a restart shorter than that. A failed search keeps its window for the next sweep. A pull that fails to refresh is logged by refresh.pull and waits for its next update. The issue suggested 10 minutes; this uses 20. That's 3 search calls an hour plus the re-reads, 8 to 15 REST calls per pull by #502's count. It runs one search per owner instead of joining the qualifiers. With advanced_search=true, "user:iFixit user:octocat" is an AND: it found 0 pulls where the default search found 38. Verified against the live API with the new searchUpdatedPulls: a search since 2026-09-26 00:00Z paged through all 234 pulls GitHub counted, and a first sweep refreshed the same 6 pulls gh's search returned. Note: every hit is re-read, including old closed pulls that get a late comment or label. In that 234-pull sample, 9 were closed more than 25 minutes before their last update. A bulk edit of many old pulls would re-read every one of them in a single sweep. Connects to #502 Claude-Session: https://claude.ai/code/session_01Loy5Y4CXz9jacGkTPFENdw
The first sweep after a restart only reached back to 25 minutes before startup. Events dropped during a longer outage stayed lost in repos the startup refresh skips. Closes from the morning before cominor was rebuilt on 2026-08-28 (ops#765 at 03:38Z, DocHarvestor#242 at 03:53Z, host booted at 16:46Z) are still open on the board. At boot the server now reads MAX(pulls.date_updated) before any webhook or the startup refresh saves a pull. That is about when the previous run last saved a pull. The first sweep's window starts 5 minutes before it instead of 25 minutes before startup, but never more than 24 hours back. When the newest update is less than 20 minutes old, nothing changes. #502 counted 111 org pulls changed in 24 hours, so a full day of catch-up is 900 to 1,700 REST calls at 8 to 15 per pull, inside the 5,000 an hour quota. An outage the process stays up through was already covered. A failed search keeps its window, so the first sweep once the network is back reaches back to the last sweep that worked. That was the 2026-09-29 case, when cominor lost its network from about 10:50Z to 14:55Z. Note: date_updated is only written when pulldasher saves the pull row, not for a comment, so MAX can be older than the last event handled. That makes the window longer, never shorter. Connects to #502 Claude-Session: https://claude.ai/code/session_016ZaR6H662c518wQxrq7kBC
GitHub search can find an update late. Its results show a pull's current updated_at, but the updated: filter runs on an index that can lag behind it. At 00:36Z on 2026-09-30, 2 of 17 org pulls updated in the previous 30 minutes weren't findable by their own updated_at. Both had a comment as their newest event, which is how a QA or CR stamp arrives: iFixit/ops#1119 updated 00:22:23Z, findable about 15 min later iFixit/ifixit#64954 updated 00:07:59Z, not findable 33 min later With a 20-minute interval and a 5-minute overlap, an update that shows up L minutes late is caught only if the next sweep starts within 25 minutes of it. L = 15 is a coin flip, and L >= 25 is never caught. A dropped comment webhook in that gap stayed dropped. The overlap is now 60 minutes. Each sweep remembers the updated_at every pull had when it re-read it, and skips a hit with the same updated_at. The wider window costs search results, not REST calls. A 25-minute window at 00:31Z held 14 pulls, so an 80-minute one should still fit in one page of 100. A pull whose refresh fails isn't marked as re-read, so the next sweep that finds it tries again. Solutions considered: - Widen the overlap alone: every changed pull would be re-read up to 4 times, at 8 to 15 REST calls each. - Skip search and list recently updated pulls per repo: #502 option 4, which misses repos not in config.repos. Connects to #502 Claude-Session: https://claude.ai/code/session_016ZaR6H662c518wQxrq7kBC
|
QA 🟢 The tests pass, and live sweeps found every pull a per-repo scan found. The deploy steps haven't run:
How the sweeps ran
iFixit/ops#1119 was updated at 00:22:23Z and became findable by that time about 15 minutes later. iFixit/ifixit#64954 was updated at 00:07:59Z and still wasn't findable by it at 00:47Z. The sweep found it anyway, because its window also covers the pull's previous indexed time, 23:56Z. The sweep's 26th pull, iFixit/ops#1120, changed again after it ran, so the scan dated it outside the window. Stale rows the deploy won't clear70 of the 316 open rows on the board are closed on GitHub or show an older head. A restart fixes the 2 in configured repos, iFixit/ifixit#64895 and iFixit/ifixit#64885. The other 68 stay, because The 68 rows by repo, and clearing themRedelivering the failed 2026-09-29 deliveries would clear 10 of them, and
Post-deploy QA Steps
|
Connects to #502
Some QA and CR stamps never show up on the board. The webhook carrying them never arrived, and GitHub doesn't resend it. Until now only a restart or the card's refresh button fixed that, and a restart skips repos missing from the config. This is option 6 from #502, run every 20 minutes instead of 10.
Summary
updated_at.user:ifixit), so fixbot, expo, DocHarvestor and the rest get re-read too.It costs 3 search calls an hour plus 8 to 15 REST calls per changed pull. 234 pulls changed from 2026-09-26 00:00Z through 2026-09-29. No config change is needed.
pulldasher-dev and the shared quota
pulldasher-dev will run its own sweep once someone deploys this there with
update-pulldasher-dev. Its config has a different GitHub token from production's, but GitHub counts the quota per account, not per token. If both tokens belong to the same account, dev's re-reads come out of production's 5,000 calls an hour. I haven't checked who owns each token.QA
npm teston Node 24 and confirmtest/recent-pulls-sweep.test.jspasses. CI only runs lint and build.SELECT MAX(date_updated) FROM pulls(epoch seconds).refreshing N of M pulls updated since <time>.<time>is an hour before that value, or 80 minutes before the restart if that is earlier.Failed to search for pulls updated sinceline.https://claude.ai/code/session_01Loy5Y4CXz9jacGkTPFENdw