Skip to content

0013: Publish documentation directly from GitHub Actions

Status: Superseded by ADR 0014.

Context

ADR 0012 used a scheduled importer to avoid Cloudflare credentials in GitHub. The maintainer now accepts a bucket-scoped R2 credential in GitHub Actions. Polling adds publication delay, repeated discovery requests, and a second release orchestrator. A production import also encountered a GitHub API 403; existing documentation stayed available.

Decision

GitHub Actions owns documentation publication. After publishing the package and attaching the validated CI archives to its GitHub release, the release workflow calls a shared publisher. Reviewed docs-only corrections use the same publisher. An explicit main-only workflow can retry or restore an existing archive without rebuilding it, modifying a package, or creating a release.

The publisher downloads the exact descriptor and bundle with GitHub's repository token, confirms the stable package exists on PyPI, and verifies the version, tagged package commit, reviewed docs commit, archive checksum, safe unique paths, file checksums, and completeness before writing anything. Existing bounds remain: v0.10.0 onward, 500 files, and 24 MiB compressed and expanded data. Files go under docs/<version>/<bundle-sha256>/; every upload carries a transport checksum. Only after all uploads succeed does an ETag-conditional write promote docs/catalog.json. Other versions and old snapshots remain available. The highest published version with a complete snapshot is current; uploading an older version's correction does not move current backward. A catalog conflict fails visibly for operator review.

Use an R2 Account API token with Object Read & Write scoped only to the usdata bucket. Store its Access Key ID and Secret Access Key as repository Actions secrets R2_ACCESS_KEY_ID and R2_SECRET_ACCESS_KEY. The endpoint and bucket name are non-secret configuration. No .env, general Cloudflare API token, webhook, publication branch, public R2 endpoint, or administrative HTTP handler is needed.

The docs Worker only serves the catalog and objects through its native R2 binding. Remove its scheduled handler and cron trigger. Workers Builds continues deploying homepage and serving code from main using its separate managed build token. The domains, URL layout, release ZIP attachments, source pinning, correction policy, and future dataset scope from ADR 0012 remain in effect.

Consequences

Publication happens in the release workflow instead of waiting for a timer, and failures appear in that workflow's logs. Partial uploads never become live. Retrying an already active revision is a no-op. Restore content by explicitly publishing a previously verified archived docs commit; retained snapshots are never deleted. Worker deployment and content publication remain independent.

The maintainer must retain and rotate the bucket-scoped Actions credentials. Normal serving no longer calls GitHub or PyPI and requires no credential secrets. The Python SDK gains no runtime dependency; boto3 belongs to deployment tooling.