fix(collect): single daily firing with full-backlog catch-up and traffic self-heal - #15
Conversation
…fic self-heal collect.yml's retry-window design (PR #11) had a real bug: it branched on github.event.schedule (which cron pattern matched) instead of wall-clock time, so a delayed firing wrote data under the wrong day, orphaning 2026-09-02 and mislabeling 2026-09-03 with ~55 minutes of partial data. Replaces the retry window entirely with a single daily firing (0030 UTC) that never collects the current, still-in-progress day -- only ever finalizes fully-elapsed days. The Gate step scans the last 7 days for every currently-missing snapshot, not just the oldest, and collects all of them in one firing -- a design that only checks the single oldest missing day can never actually close a backlog once behind, since a new day becomes due every day at the same rate as recovery. Also flags (via ::error::) any day about to age out of the 7-day window unrecovered, and warns (::warning::) when catching up more than one day at once. New scripts/refresh_traffic.py patches already-committed snapshot files' traffic fields in place, keeping them in sync with GitHub's rolling 14-day breakdown (which can lag or later revise a day's numbers) -- runs on every firing via if: always(), independent of whether Fetch metrics succeeded, so it's never silently skipped by an unrelated upstream failure. This keeps each day's own snapshot file the true, self-contained record for that day rather than requiring a separate file to reconstruct the real value. backfill_traffic.py goes back to being the one-time pre-launch historical seed only, not workflow-invoked. Also fixes a second, independent bug in build_site.py: latest_traffic checked views is not None instead of as_of_date is not None, so it always resolved to the newest snapshot regardless of whether that snapshot's traffic was actually valid (views defaults to 0, never None). Adds a short site disclaimer that traffic data can lag ~1 day and a missing/zero point isn't a real zero. Fixes #14. Supersedes #12 (no retry window left to calibrate).
Cursor reviewPR Review: #15 — fix(collect): single daily firing with full-backlog catch-up and traffic self-healReviewer: Cursor Cloud Agent SummaryThis PR replaces the hourly retry-window collector (#11) with a simpler model:
CI What works wellRoot-cause fix is correctThe old gate branched on Full-backlog catch-up is the right callCollecting only the oldest missing day per firing cannot close a backlog under steady daily load (1 recovered/day, 1 new/day). The multi-day loop in the Gate step fixes that. The Traffic self-heal is well integrated
Documentation is thorough
Data cleanupDeleting Issues & suggestions1. Minor — stale docstring in
|
| Area | Assessment |
|---|---|
.github/workflows/collect.yml |
Gate logic is clear; if: always() on Refresh/Commit is correct; commit message derived from staged files is an improvement |
scripts/refresh_traffic.py |
Small, focused; mirrors fetch_metrics API patterns; skips gracefully without token |
scripts/build_site.py |
Critical bugfix; comments explain the as_of_date vs views distinction well |
scripts/fetch_metrics.py |
Doc updates align with new collect behavior |
templates/index.html |
Disclaimer (Delayed ~1 day; gaps ≠ zero) is appropriate |
Test coverage gaps (for author awareness)
PR test plan is manual/simulation-based (no committed unit tests). That’s consistent with the repo (no test suite today). If the author wants hardening later:
- Gate bash logic as a small fixture-based test or documented simulation script in-repo
refresh_traffic.pywith mocked API responses- Regression test for
build_site.pyas_of_date is None→ skip behavior
Not blockers for this PR.
Post-merge checklist (from PR test plan)
- Next scheduled
0030 UTCrun collects2026-09-03(and any other gaps) -
refresh_traffic.pypatches2026-09-02once GitHub publishes that day’s traffic - Confirm no spurious empty commits when traffic values are unchanged
- Watch for
::warning::/::error::annotations in Actions if backlog or day-8 boundary occurs
Recommended action
Merge after optional docstring fix in backfill_traffic.py. Everything else can be follow-up if desired.
The PR correctly addresses #14, supersedes #12’s retry-window approach with a better model, and the build_site.py fix is independently valuable.
- Fix stale backfill_traffic.py docstring line still referencing collect.yml catch-up, contradicting its own "one-time seed" framing. - Add refresh_traffic.py to verify.yml so a broken script fails CI before merge instead of only surfacing in production collect.yml. - Catch-up scan now iterates oldest-to-newest (7 days ago -> yesterday) instead of newest-to-oldest, for more readable logs/commit messages.
|
Addressed in dac2418:
Left as-is, agreeing with your own "non-blocking"/"acceptable" calls:
Test coverage gaps noted -- no unit test suite exists in this repo today, consistent with everything else here; can revisit if it becomes a real pain point. |
mike-wendt
left a comment
There was a problem hiding this comment.
Reviewed changes and they match the plan
Summary
Closes #14. Closes #12 (superseded -- see comment on that issue).
collect.yml's retry-window design (#11) had a real bug: it branched ongithub.event.schedule(which cron pattern matched) instead of wall-clock time, so a delayed firing wrote data under the wrong day -- orphaning2026-09-02and mislabeling2026-09-03with ~55 minutes of partial data. Working through the fix surfaced a deeper design problem and two explicit data-durability goals for this repo (never lose data; keep each day's snapshot self-contained enough to build on), which this PR is designed around rather than just patching the one bug.0030 UTC), no retry window.collect.ymlnever collects the current, still-in-progress day -- only ever finalizes fully-elapsed days.::warning::when catching up more than one day at once,::error::naming any day about to age out of the 7-day window unrecovered (pointing atBOOTSTRAP.md's manual recovery path).scripts/refresh_traffic.py(new) patches already-committed snapshot files' traffic fields in place, keeping them in sync with GitHub's rolling 14-day breakdown -- which can lag or later revise a day's numbers -- runs on every firing viaif: always()so it's never silently skipped by an unrelated upstream failure. This keeps each snapshot the true, self-contained record for its day instead of requiring a separate file to reconstruct the real value.backfill_traffic.pygoes back to being the one-time pre-launch historical seed only, not workflow-invoked.build_site.py:latest_trafficcheckedviews is not Noneinstead ofas_of_date is not None, so it always resolved to the newest snapshot regardless of whether that snapshot's traffic was actually valid (viewsdefaults to0, neverNone).repo/labelsfields reflect collection time, not each day's real state -- onlyactivity/trafficare genuinely accurate for a backfilled day. This is the same point-in-time limitation the project already had for a single missed day; multi-day catch-up just makes it more visible when it happens.Review process
This design went through two independent adversarial agent reviews before implementation (one on resilience/correctness, one on alignment with stated goals and scope). Findings and how each was addressed:
repo/labelsvalues onto every backfilled day -- addressed via explicit::warning::+ docs, not silently implied full recovery.::error::annotation for the day-8 boundary case.Refresh traffic/Commitsteps would be silently skipped by GitHub Actions' defaultif: success()wheneverFetch metricsfails. Fixed: both getif: always().Commitstep, always last, always covers everything from that firing.workflow_dispatchwould lose the ability to force a same-day/specific check once caught up. Fixed: added an optionaldateinput as an explicit escape hatch.refresh_traffic.pyinitially only patchednulltraffic, missing GitHub's later revisions to already-published numbers. Fixed: refreshes any date still within GitHub's current 14-day window, not just previously-null ones.Test plan
uv run scripts/build_site.pyexits cleanly against current on-disk snapshotsbash -n)python3 -m py_compileon all modified/new scriptssite/index.htmlVerify pipeline / verifypasses on this PR2026-09-03and any other missing days, and thatrefresh_traffic.pypicks up2026-09-02's traffic once GitHub publishes it🤖 Generated with Claude Code