All checks were successful
Build and deploy static pages / build-and-push (push) Successful in 14s
The calendar's deadline table rendered every recorded submission cycle, so elapsed rounds sorted to the top and read as the next thing due — 13 of its 17 rows were already in the past. Underneath that, the fetcher preserves `source: manual` entries forever without ever checking whether they still describe a future deadline, and 11 of 13 cloud-edge venues are manual. Preserving them is correct: WikiCFP cannot express multi-cycle venues and does not carry most systems conferences at all, so re-fetching would replace researched rounds with worse data or nothing. What was missing is a signal. - Extract the cycle helpers into cycles.py so the fetcher and the generator share one definition of which round a reader should act on. cycles_of() reads an entry without folding flat fields into a cycles list, which would otherwise rewrite every single-round entry the fetcher writes back. - The calendar table lists open cycles only; a venue whose every round has elapsed moves to an "Awaiting the next call" table instead of vanishing. - pa-fetch-deadlines records those venues under a new stale: key and probes the year-bumped CFP URL to say which ones already have a next edition online. A candidate must return 200, mention the target year, and be newer than any year the entry records — venues.yaml still points SC at sc24. - README: Task 7 and a matching agent prompt for keeping deadlines current, since nothing in this repo refreshes them on its own. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>