[migrate] Replace upptime with Gitea-native uptime probe (closes #2) #4

Open
claude-ceo-assistant wants to merge 3 commits from feat/uptime-probe-cron-issue2 into main

3 Commits

Author SHA1 Message Date
claude-ceo-assistant
514e8e103b fix(site): proxy gitea fetches via Vercel rewrites — work around Gitea raw-URL CORS
Gitea raw file responses do not send Access-Control-Allow-Origin, so
browser fetches from the Vercel-served status page were blocked
cross-origin. Add a Vercel rewrite that maps /data/(.*) ->
git.moleculesai.app/molecule-ai/molecule-ai-status/raw/branch/main/$1
so the browser only sees same-origin requests; Vercel handles the
upstream fetch server-side and returns the body to the browser.

Tradeoff
- Adds one network hop (browser -> Vercel edge -> Gitea -> Vercel ->
  browser). Vercel caches per the Cache-Control: public, max-age=60
  header on /data/, so steady-state is one upstream hit per minute
  per file. Acceptable.
- Decouples the page from Gitea CORS posture — if/when Gitea ships
  Access-Control-Allow-Origin headers (probably correct
  long-term), the page can be flipped back to direct fetch by
  removing the rewrite.

What did NOT change: probe binary, cron, file paths in history/,
.upptimerc.yml. The data flow is identical; only the URL the
browser uses changed.
2026-05-08 01:24:06 +00:00
claude-ceo-assistant
2371a319bb feat(site): static status page (closes #2 — page renderer)
Single-page status dashboard for Molecules AI services. Pure static
HTML+CSS+JS — zero build step, zero dependencies. Reads probe results
directly from public Gitea raw URLs at runtime.

Files:
- site/index.html: structure + embedded CSS (light/dark via prefers
  -color-scheme; ~110 lines styling)
- site/app.js: fetches .upptimerc.yml + per-site history JSONL,
  renders rows + summary + 24h-history sparkline, auto-refreshes
  every 5 min (matches probe cadence)
- site/vercel.json: static-site config + security headers

Why no framework
- Page must load fast and never lie. React/Vue would be cargo-cult
  at this scale (3 visible elements, 1 data source).
- Plain DOM + fetch removes the supply-chain surface a JS framework
  drags in. Zero npm deps, zero lockfile, zero CI build.

Slugify rule mirrors the probe binary's slugify() in
cmd/probe/main.go — both must agree on the file naming for
history/<slug>.jsonl to round-trip cleanly.

Out of scope (separate PRs / follow-ups)
- Vercel project configuration + deploy (next commit)
- Custom domain status.moleculesai.app
- Historical data migration from old upptime JSON format
- Alerting / RSS / status-as-API endpoints
2026-05-08 01:20:55 +00:00
claude-ceo-assistant
08066d3d67 feat(ci): replace upptime with Gitea-native uptime probe (closes #2)
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>
2026-05-08 01:14:48 +00:00