Problem
The curriculum/Young incremental cache relies on downloading the previous run's github-pages artifact (.github/workflows/build.yml:33-62). But actions/upload-pages-artifact@v4 defaults retention-days to 1 (verified in the action's action.yml), so each artifact expires exactly 24h after upload. The daily cron (.github/workflows/build.yml:5, 0 0 * * *) actually starts with ±40 min scheduler jitter — observed starts range 01:06–01:46 UTC. Whenever run N+1 starts later than run N's upload time + 24h, the restore step finds the artifact expired and silently rebuilds everything: all 16 selected semesters, ~280 JW schedule-table/datum chunk POSTs, all catalog lesson/exam fetches.
Evidence this already happened
- Run
29463669719 (2026-07-16 01:15:33) logged at 01:15:50: Previous build artifact 29380812432 is unavailable. The 2026-07-15 artifact was created 01:12:49 and expired 01:12:43 — 3 minutes before the restore step ran.
- The currently published snapshot proves the full rebuild: every row in
upstream_fetches has fetched_at >= 2026-07-16T01:17:45 (checked https://static.life-ustc.tiankaima.dev/life-ustc-static.sqlite, SELECT MIN(fetched_at), MAX(fetched_at) FROM upstream_fetches → 2026-07-16T01:17:45 … 2026-07-18T01:17:11). With a working cache, ended semesters keep their original fetch rows.
gh api repos/Life-USTC/static/actions/artifacts shows every github-pages artifact with expires_at = created_at + 1 day.
A full rebuild is ~10× the normal upstream load against jw.ustc.edu.cn / catalog.ustc.edu.cn and makes a mid-run failure (no publish at all) much more likely. It also recurs unpredictably since GitHub does not guarantee scheduled-run start times.
Suggested fix
One line in the upload step (.github/workflows/build.yml:80-84):
- name: Upload static files as artifact
id: deployment
uses: actions/upload-pages-artifact@v4
with:
path: build/
retention-days: 7 # survive a failed/delayed day
Optionally also make the restore step fall back to older successful runs when the newest artifact is expired (currently it only tries .[0].databaseId and gives up), and log a loud warning (::warning::) when the cache is lost so the full rebuild is visible instead of silent.
Problem
The curriculum/Young incremental cache relies on downloading the previous run's
github-pagesartifact (.github/workflows/build.yml:33-62). Butactions/upload-pages-artifact@v4defaultsretention-daysto 1 (verified in the action'saction.yml), so each artifact expires exactly 24h after upload. The daily cron (.github/workflows/build.yml:5,0 0 * * *) actually starts with ±40 min scheduler jitter — observed starts range 01:06–01:46 UTC. Whenever run N+1 starts later than run N's upload time + 24h, the restore step finds the artifact expired and silently rebuilds everything: all 16 selected semesters, ~280 JWschedule-table/datumchunk POSTs, all catalog lesson/exam fetches.Evidence this already happened
29463669719(2026-07-16 01:15:33) logged at 01:15:50:Previous build artifact 29380812432 is unavailable. The 2026-07-15 artifact was created 01:12:49 and expired 01:12:43 — 3 minutes before the restore step ran.upstream_fetcheshasfetched_at >= 2026-07-16T01:17:45(checkedhttps://static.life-ustc.tiankaima.dev/life-ustc-static.sqlite,SELECT MIN(fetched_at), MAX(fetched_at) FROM upstream_fetches→2026-07-16T01:17:45 … 2026-07-18T01:17:11). With a working cache, ended semesters keep their original fetch rows.gh api repos/Life-USTC/static/actions/artifactsshows everygithub-pagesartifact withexpires_at = created_at + 1 day.A full rebuild is ~10× the normal upstream load against jw.ustc.edu.cn / catalog.ustc.edu.cn and makes a mid-run failure (no publish at all) much more likely. It also recurs unpredictably since GitHub does not guarantee scheduled-run start times.
Suggested fix
One line in the upload step (.github/workflows/build.yml:80-84):
Optionally also make the restore step fall back to older successful runs when the newest artifact is expired (currently it only tries
.[0].databaseIdand gives up), and log a loud warning (::warning::) when the cache is lost so the full rebuild is visible instead of silent.