|
All checks were successful
PR build (required check) / changes (pull_request) Successful in 7s
secrets-guard / encrypted (pull_request) Successful in 6s
shell-lint / shellcheck (pull_request) Successful in 8s
PR build (required check) / build-frontend (pull_request) Has been skipped
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / build-backend (pull_request) Successful in 1m9s
PR build (required check) / gate (pull_request) Successful in 2s
geocode_nominatim referenced _REVGEO_LOCK, which was removed when reverse geocoding moved from a bare lock to the dedicated worker/queue design -- the forward-geocode function was never updated to match, so every call raised NameError, degrading to a 502 on the frontend. Live on prod, beta, dev, main, and release since the lock was removed (~30h): every comma-qualified name, postcode, and non-cities1000 place 502'd, while the local GeoNames index kept bare city names working, so the failure was invisible to simple smoke checks. The three existing tests covering this path all monkeypatch geocode_nominatim itself, so none of them ever executed the broken body. Fixed by routing forward-geocode jobs through the same worker/queue that already serializes reverse-geocode jobs, instead of reintroducing a second lock -- both job kinds are now drained by the one worker thread, so _revgeo_last still has exactly one writer and the shared ~1/sec Nominatim pacing the docstring always claimed is now actually enforced, not just asserted in a comment. Adds regression coverage that exercises the real queue/worker plumbing (not a monkeypatch of geocode_nominatim) plus a stubbed-HTTP test of _fetch_geocode_forward's own body, the function whose earlier version never once executed successfully. |
||
|---|---|---|
| .forgejo/workflows | ||
| backend | ||
| frontend | ||
| infra | ||
| observability | ||
| CLAUDE.md | ||
| CUTOVER-NOTES.md | ||
| README.md | ||
thermograph
The Thermograph monorepo — the split repos reunified (2026-07-22) with full history via subtree merges, while keeping everything the split was actually for: per-domain images, per-domain deploys, and an async FE/BE contract.
Domains
| Dir | What | CI |
|---|---|---|
backend/ |
FastAPI graded-climate API, accounts, notifications (Discord bot, push, mail), data pipeline | backend-build-push → image emi/thermograph/backend; backend-deploy[-prod|-dev] |
frontend/ |
Public client: static JS/CSS + SSR pages | frontend-* mirrors of the above; image emi/thermograph/frontend |
infra/ |
Compose, deploy scripts, terraform, SOPS secrets vault, ops cron | infra-sync (host checkout + secrets render), secrets-guard, ops-cron |
observability/ |
Loki + Grafana + Alloy stack | observability-validate |
thermograph-docs deliberately stays its own repo (ADRs + runbooks, no
build artifacts, different change cadence).
How CI stays decoupled
Every workflow in .forgejo/workflows/ is path-filtered to its domain: a
push touching only frontend/** builds/deploys nothing else. Images stay
separate (emi/thermograph/backend, emi/thermograph/frontend, each tagged
sha-<12hex>), deploys stay per-service (infra/deploy/deploy.sh SERVICE=backend|frontend|all), and the API version contract
(GET /api/version, PAYLOAD_VER) still lets FE and BE ship out of lockstep.
The one intentionally coupled piece is pr-build.yml: a single always-running
gate required check that builds only the domains a PR touches (a
path-filtered required check would deadlock auto-merge).
Branch model (unchanged from the split era): PRs → dev, main → beta,
release → prod; infra tracked via main on all hosts.
Before pointing anything live at this repo, read CUTOVER-NOTES.md.