Skip to content

docs: self-host the star history chart - #717

Merged
av1155 merged 2 commits into
mainfrom
docs/restore-star-history-chart
Aug 6, 2026
Merged

docs: self-host the star history chart#717
av1155 merged 2 commits into
mainfrom
docs/restore-star-history-chart

Conversation

@av1155

@av1155 av1155 commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Summary

Renders the README star history chart from a scheduled workflow instead of a
hosted embed, so it no longer depends on a GitHub credential living in a
public README.

The previous embed returns HTTP 403: GitHub restricted the stargazers API to a
repository's admins and collaborators in June 2026, and the sealed token wraps
a credential that no longer clears that check. Regenerating it is possible, but
the permission GitHub accepts is Contents: Read and write, which means a
credential that can push to this repo, sitting in a public README and decrypted
by a third party on every view. The per-run Actions token holds the same
permission and expires with the job.

Closes #716

Changes

  • Add scripts/star_history.py, a stdlib-only renderer that reads
    starred_at timestamps on stdin and writes light and dark SVGs. Colours
    come from website/src/css/tokens.css so the chart matches the docs site.
  • Add the Star History workflow, running daily at 07:23 UTC and on demand.
    It reads stargazers with the per-run Actions token and publishes to the
    orphan assets branch, amending rather than appending so the branch stays
    at one commit. Identical input renders byte-identical output, so a day with
    no chart movement produces no commit at all.
  • The fetch step refuses to publish on an empty or truncated response. A 200
    carrying an empty array is a success to gh, and rendering one would put a
    "No stars yet" placeholder over the real chart unattended.
  • Point the README at the raw URLs on assets and remove the sealed token.
  • Drop the api.star-history.com lychee exclusion, now unreferenced.

The chart lives on a separate branch because main requires pull requests,
and a daily refresh is not worth a daily PR.

Testing

tests/test_star_history.py covers the pure functions: integer-only star
ticks, unique date labels across a year boundary, downsample endpoint
preservation, and well-formed XML for empty, single-star, same-instant, and
large inputs. Four of these fail against the first revision of the renderer.

Rendered against the live stargazer data (262 stars) and checked both themes.
Both raw URLs return 200 with image/svg+xml. Full suite is 2803 passing,
actionlint is clean on the new workflow, and lychee extracts and checks all
three chart URLs rather than skipping the host.

The workflow itself cannot run until it is on the default branch, so it wants
a manual dispatch after merge to confirm the fetch step in a real run.

Type of Change

  • Bug fix (fix:)
  • New feature (feat:)
  • Refactoring (refactor:)
  • Documentation (docs:)
  • CI/CD (ci:)
  • Chore (chore:)

Checklist

  • Issue exists and is linked above with Closes #N
  • Linked issue has exactly one type:* and one priority:* label
  • Linked issue has at most one phase:* label (or none when not roadmap work)
  • Branch name matches issue scope (feat/<slug>, fix/<slug>, etc.)
  • Tests added/updated for all changes
  • Type check passes (mypy src/; the new script is also clean under it)
  • Lint passes (ruff check .)
  • Format passes (ruff format --check .)
  • Documentation updated (if applicable)
  • No secrets or sensitive data committed
  • Scope check: This change helps search for missing or cutoff-unmet
    media in a controlled way — N/A, README only

The README embed pointed at api.star-history.com with a sealed token.
That endpoint now returns 403 for this repo: GitHub restricted the
stargazers API to a repository's admins and collaborators in June 2026,
and the wrapped credential no longer clears that bar.

Regenerating the token would work, but the permission GitHub accepts is
Contents: Read and write. That is a credential which can push to this
repo, decrypted by a third party on every README view, while any v* tag
publishes ghcr.io latest. Render the chart from a scheduled workflow
instead: the per-run Actions token holds the same permission but expires
with the job and never leaves GitHub.

Charts are committed to the orphan `assets` branch because `main`
requires pull requests and a daily refresh is not worth a daily PR.
@av1155 av1155 mentioned this pull request Aug 6, 2026
17 tasks
Review of the initial commit surfaced four renderer defects and two
workflow gaps.

Renderer: the y axis produced fractional gridlines at low counts (10
stars rendered 0/2.5/5/7.5/10), day-and-month x ticks repeated the same
label once the window crossed a year (Dec 31 twice at a 729 day span),
downsample divided by zero at a limit below two, and the tick format
switched to scientific notation past a million. nice_step is now floored
at 1 with integer factors, the axis falls back to month-and-year when
the window spans two calendar years, and mypy strict passes on the file.

Workflow: a 200 carrying an empty or truncated array is a success to gh,
so set -e let it through and the renderer published a "No stars yet"
placeholder over a good chart, unattended, on a public README. The fetch
step now refuses to publish on zero rows or on a count that has halved
against the published chart. Runs are pinned to this repository so a
fork dispatch cannot fail on the missing assets branch, and the publish
step amends rather than appends so the orphan branch stays one commit
instead of accruing megabytes of unread history.

Adds tests covering the pure functions; all four renderer defects fail
against the previous revision.
@av1155
av1155 merged commit f0dd985 into main Aug 6, 2026
0 of 3 checks passed
@av1155
av1155 deleted the docs/restore-star-history-chart branch August 6, 2026 18:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs: restore the star history chart in the README

1 participant