Combined transition PR — does the full upptime → Gitea-native cron
swap in one place, vs two separate PRs that would land in interleaved
state.
Why upptime had to go
- All 5 upptime workflows call api.github.com for releases lookup,
issue management, and result commits.
- Post the 2026-05-06 GitHub org suspension, no token in our org
authenticates against api.github.com — every scheduled run fails
with HTTP 401 "Bad credentials". Run #70 is the most recent
example; the failure mode has been continuous since the suspension.
What this PR does
- Moves all 5 upptime workflows from .github/workflows/ to
.github/workflows-disabled/. Gitea Actions does not scan that
directory, so they stop scheduling immediately on merge.
- Adds .github/workflows-disabled/README.md explaining the move +
linking #2 + linking the replacement.
- Adds a single new .github/workflows/uptime-probe.yml that runs the
new Gitea-native probe (https://git.moleculesai.app/molecule-ai/
molecule-ai-uptime-probe) on a 5-minute cadence and commits per-site
JSONL history to history/.
Why a single new workflow vs the upptime decomposition
- Each upptime workflow ran a different command: argument
(graphs / response-time / static-site / summary / uptime). The
decomposition existed because each command produced a different
artifact in upptime's model.
- Our model: probe emits raw probe results only. Status page (Vercel,
separate PR) reads those JSONL files and renders graphs/summaries
itself. One concern per tool, one workflow.
History migration: out of scope. Existing history/ JSON files (one
per site) stay untouched; the new probe writes a new
history/<slug>.jsonl alongside. Whether to back-fill or archive the
old format is a separate decision tracked in the issue body.
Status page rebuild: out of scope. Vercel app reading JSONL is
follow-up — first we want to see real probe data flowing for ~24h.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Static Site CI was building the Sapper export successfully but had no
step to publish it — `gh-pages` branch never existed so GitHub Pages
couldn't serve anything. Matches the canonical Upptime template:
- static-site.yml: adds peaceiris/actions-gh-pages@v4 step publishing
site/status-page/__sapper__/export/ to gh-pages
- All 5 workflows: pin upptime/uptime-monitor to @v1.41.0 instead of
@master (reproducibility + matches upstream template expectations)
The Upptime action reads .upptimerc.yml from the current working
directory; without an explicit checkout step the runner starts in an
empty dir and every run fails with ENOENT. Adding actions/checkout@v4
with fetch-depth: 0 (full history required by the commit-back step)
as the first step of each workflow.
Observed on the initial-commit runs of uptime.yml + static-site.yml
which both failed with:
ERROR [Error: ENOENT: no such file or directory, open '.upptimerc.yml']
Seeds the Upptime-powered status page for Molecule AI. Zero-infra:
GitHub Actions cron every 5min checks each endpoint, commits the
result to history/, and rebuilds the static site into the gh-pages
branch. Incident detection auto-opens Issues in this repo.
- .upptimerc.yml — five sites monitored on first cut:
- molecule-cp /health + /legal/terms
- moleculesai.app / + /pricing + /legal/terms
Each has a display name that matches the status page UI.
- .github/workflows/uptime.yml — 5min uptime check
- .github/workflows/response-time.yml — hourly latency histogram
- .github/workflows/graphs.yml — daily long-term graphs
- .github/workflows/static-site.yml — hourly site rebuild
- .github/workflows/summary.yml — daily README badge refresh
- README.md — landing page with workflow status badges, Upptime
markers for auto-populated status section
- history/.gitkeep — placeholder so the workflows' first run has a
dir to commit into
- LICENSE — MIT
Next steps documented separately: enable GitHub Pages (Settings →
Pages → Source: gh-pages branch), add DNS CNAME record for
status.moleculesai.app → molecule-ai.github.io.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>