{"record":{"id":"2340744739965b50","repo":"666ghj/MiroFish","slug":"stargazer-list-changed-or-was-incomplete-during-ba","errorCode":null,"errorMessage":"stargazer list changed or was incomplete during backfill","messagePattern":"stargazer list changed or was incomplete during backfill","errorType":"exception","errorClass":"StarHistoryError","httpStatus":null,"severity":"error","filePath":"scripts/star_history.py","lineNumber":609,"sourceCode":"            if edge.starred_at.date() < normalized_now.date():\n                daily_increments[edge.starred_at.date()] += 1\n\n        if page.end_cursor is not None:\n            if page.end_cursor in seen_page_cursors:\n                raise StarHistoryError(\"GitHub GraphQL repeated a page cursor\")\n            seen_page_cursors.add(page.end_cursor)\n        if not page.has_next_page:\n            break\n        if page.end_cursor is None:\n            raise StarHistoryError(\"GitHub GraphQL omitted the next page cursor\")\n        after = page.end_cursor\n        if page_number > 10_000:\n            raise StarHistoryError(\"GitHub GraphQL exceeded the page safety limit\")\n\n    if initial_total is None:\n        raise StarHistoryError(\"GitHub GraphQL returned no pages\")\n    if len(seen_edge_cursors) != initial_total:\n        raise StarHistoryError(\"stargazer list changed or was incomplete during backfill\")\n\n    running = 0\n    daily: list[dict[str, Any]] = []\n    for point_day in sorted(daily_increments):\n        running += daily_increments[point_day]\n        daily.append({\"date\": point_day.isoformat(), \"stars\": running})\n\n    state: dict[str, Any] = {\n        \"schema_version\": 1,\n        \"repository\": REPOSITORY,\n        \"timezone\": \"UTC\",\n        \"ongoing_interval_days\": INTERVAL_DAYS,\n        \"reconstruction\": {\n            \"method\": \"current_stargazers_starred_at\",\n            \"generated_at\": _format_state_timestamp(normalized_now),\n            \"daily\": daily,\n        },\n        \"snapshots\": [],","sourceCodeStart":591,"sourceCodeEnd":627,"githubUrl":"https://github.com/666ghj/MiroFish/blob/b5b53acc57189a4a42e44a23e149dc655c98fe82/scripts/star_history.py#L591-L627","documentation":"Raised at scripts/star_history.py:609 after the backfill completes. The script compares `len(seen_edge_cursors)` against the `totalCount` reported by the very first page (`initial_total`); a mismatch means the pages traversed did not cover exactly the stargazer set GitHub advertised, so the per-day star counts in `daily_increments` would be wrong (under- or over-counted). The state file is therefore not written.","triggerScenarios":"Stars added or removed between the first page fetch (which fixes `initial_total`) and the last page: every new star means an extra edge collected (len > total), every un-star means one missing (len < total). Also fires when GitHub's `totalCount` is eventually consistent with the edge stream on huge repositories.","commonSituations":"Backfilling an actively starred repository (e.g. trending on GitHub) where churn during a multi-minute pagination run is guaranteed; running the one-time maintainer backfill right after a publicity event; test gateways whose `total_count` field disagrees with the number of edges they emit across all pages.","solutions":["Re-run the backfill at a quieter time — churn-induced mismatch is by far the most common cause and a retry usually converges.","If it persists on a busy repo, retry a few times; small mismatches (±1–2) resolve as churn settles, and the check guarantees you never persist a wrong history.","In test doubles, make `total_count` exactly equal the total number of distinct edges the fake will return across all pages.","For very large repos, verify the star count with `gh api repos/{owner}/{repo} --jq .stargazers_count` before and after the run to confirm whether real churn explains the delta."],"exampleFix":"# test double: total_count must match the sum of edges over all pages\nTOTAL = 500\n# before: StargazerPage(total_count=999, ...)\n# after:\nreturn StargazerPage(\n    total_count=TOTAL,\n    edges=all_edges[page_index * 100:(page_index + 1) * 100],\n    has_next_page=(page_index + 1) * 100 < TOTAL,\n    end_cursor=f\"page-{page_index}\" if (page_index + 1) * 100 < TOTAL else None,\n    rate_remaining=5000,\n)","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"for attempt in range(3):\n    try:\n        state = run_backfill(gateway, clock)\n        break\n    except StarHistoryError as exc:\n        if \"changed or was incomplete\" not in str(exc) or attempt == 2:\n            raise\n        logger.info(\"stargazer churn during backfill (attempt %d); retrying\", attempt + 1)","preventionTips":["Schedule the backfill during low star-churn windows (check GitHub traffic insights first).","Do not extend the pagination loop with sleeps — longer runs increase churn exposure and burn rate limit.","If mismatches of exactly ±1 persist, compare `gh api repos/... --jq .stargazers_count` before and after the run to confirm real churn rather than a parsing bug.","Remember the guard protects you: a mismatched count would silently corrupt every daily total downstream."],"tags":["github-api","backfill","data-integrity","consistency-check"],"backgroundTag":null,"analyzedSha":"b5b53acc57189a4a42e44a23e149dc655c98fe82","analyzedAt":"2026-08-14T22:29:33.146Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}