Commit graph

516 commits

Author SHA1 Message Date
emi
4f21e47750 Merge pull request 'promote: dev → main (location bookmarks)' (#119) from dev into main
All checks were successful
secrets-guard / encrypted (push) Successful in 13s
shell-lint / shellcheck (push) Successful in 15s
Build + push images (Forgejo registry) / build-push (backend) (push) Successful in 1m7s
Build + push images (Forgejo registry) / build-push (frontend) (push) Successful in 1m5s
Deploy / deploy (backend) (push) Successful in 1m16s
Deploy / deploy (frontend) (push) Successful in 1m29s
2026-07-26 18:46:01 +00:00
emi
1c6ecc2a6f bookmarks: map + account UI for saved locations
All checks were successful
secrets-guard / encrypted (push) Successful in 18s
shell-lint / shellcheck (push) Successful in 17s
Build + push images (Forgejo registry) / build-push (frontend) (push) Successful in 1m17s
Build + push images (Forgejo registry) / build-push (backend) (push) Successful in 1m23s
Deploy / deploy (backend) (push) Successful in 1m40s
Deploy / deploy (frontend) (push) Successful in 1m48s
PR build (required check) / changes (pull_request) Successful in 6s
secrets-guard / encrypted (pull_request) Successful in 5s
shell-lint / shellcheck (pull_request) Successful in 7s
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Successful in 54s
PR build (required check) / build-backend (pull_request) Successful in 1m11s
PR build (required check) / gate (pull_request) Successful in 1s
2026-07-26 18:36:43 +00:00
emi
17cc14b48b bookmarks: map + account UI for saved locations
All checks were successful
secrets-guard / encrypted (pull_request) Successful in 20s
PR build (required check) / changes (pull_request) Successful in 22s
shell-lint / shellcheck (pull_request) Successful in 19s
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Successful in 2m27s
PR build (required check) / build-backend (pull_request) Successful in 2m51s
PR build (required check) / gate (pull_request) Successful in 3s
2026-07-26 18:36:39 +00:00
emi
d6ead56971 bookmarks: map + account UI for saved locations
All checks were successful
secrets-guard / encrypted (pull_request) Successful in 10s
PR build (required check) / changes (pull_request) Successful in 16s
shell-lint / shellcheck (pull_request) Successful in 12s
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Successful in 2m24s
PR build (required check) / build-backend (pull_request) Successful in 2m51s
PR build (required check) / gate (pull_request) Successful in 3s
2026-07-26 18:36:34 +00:00
emi
4e1c4a4197 bookmarks: map + account UI for saved locations 2026-07-26 18:36:31 +00:00
emi
41858f3e4b bookmarks: account-synced saved locations API
All checks were successful
PR build (required check) / changes (pull_request) Successful in 6s
secrets-guard / encrypted (pull_request) Successful in 5s
shell-lint / shellcheck (pull_request) Successful in 7s
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 1m0s
PR build (required check) / gate (pull_request) Successful in 2s
2026-07-26 18:27:45 +00:00
emi
58e3a8d625 bookmarks: account-synced saved locations API 2026-07-26 18:27:44 +00:00
emi
53fd5d9225 bookmarks: account-synced saved locations API 2026-07-26 18:27:43 +00:00
emi
3fafd67600 bookmarks: account-synced saved locations API 2026-07-26 18:27:41 +00:00
emi
67284dfe2e bookmarks: account-synced saved locations API 2026-07-26 18:27:40 +00:00
emi
efcf32defc Merge pull request 'promote: dev → main (sign in with Discord)' (#116) from dev into main
All checks were successful
Sync infra to hosts / sync-dev (push) Has been skipped
Sync infra to hosts / sync-beta (push) Successful in 17s
Sync infra to hosts / sync-prod (push) Successful in 15s
secrets-guard / encrypted (push) Successful in 13s
shell-lint / shellcheck (push) Successful in 13s
Build + push images (Forgejo registry) / build-push (backend) (push) Successful in 1m23s
Build + push images (Forgejo registry) / build-push (frontend) (push) Successful in 1m21s
Deploy / deploy (backend) (push) Successful in 1m25s
Deploy / deploy (frontend) (push) Successful in 1m37s
2026-07-26 18:22:03 +00:00
emi
8572c4aa6d accounts: sign in with Discord, sharing the existing link callback (#115)
All checks were successful
Sync infra to hosts / sync-beta (push) Has been skipped
Sync infra to hosts / sync-prod (push) Has been skipped
Sync infra to hosts / sync-dev (push) Successful in 11s
secrets-guard / encrypted (push) Successful in 6s
shell-lint / shellcheck (push) Successful in 7s
Build + push images (Forgejo registry) / build-push (backend) (push) Successful in 1m21s
Build + push images (Forgejo registry) / build-push (frontend) (push) Successful in 1m19s
Deploy / deploy (frontend) (push) Successful in 1m27s
Deploy / deploy (backend) (push) Successful in 1m49s
secrets-guard / encrypted (pull_request) Successful in 5s
PR build (required check) / changes (pull_request) Successful in 7s
shell-lint / shellcheck (pull_request) Successful in 6s
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Successful in 1m16s
PR build (required check) / build-backend (pull_request) Successful in 1m36s
PR build (required check) / gate (pull_request) Successful in 1s
2026-07-26 18:16:55 +00:00
emi
c1ab9410d3 Merge pull request 'promote: dev → main' (#114) from dev into main
All checks were successful
Sync infra to hosts / sync-dev (push) Has been skipped
Sync infra to hosts / sync-beta (push) Successful in 6s
Sync infra to hosts / sync-prod (push) Successful in 4s
secrets-guard / encrypted (push) Successful in 4s
shell-lint / shellcheck (push) Successful in 8s
2026-07-26 08:29:19 +00:00
emi
801c767115 dev: leave /healthz outside the basic-auth boundary (#113)
All checks were successful
Sync infra to hosts / sync-beta (push) Has been skipped
shell-lint / shellcheck (push) Successful in 10s
PR build (required check) / build-backend (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Has been skipped
PR build (required check) / gate (pull_request) Successful in 1s
Sync infra to hosts / sync-prod (push) Has been skipped
Sync infra to hosts / sync-dev (push) Successful in 6s
secrets-guard / encrypted (push) Successful in 6s
PR build (required check) / changes (pull_request) Successful in 5s
secrets-guard / encrypted (pull_request) Successful in 5s
shell-lint / shellcheck (pull_request) Successful in 8s
PR build (required check) / validate-observability (pull_request) Has been skipped
2026-07-26 08:28:18 +00:00
emi
c86489b207 Merge pull request 'promote: dev → main (dev behind basic auth at dev.thermograph.org)' (#112) from dev into main
All checks were successful
Sync infra to hosts / sync-dev (push) Has been skipped
Sync infra to hosts / sync-beta (push) Successful in 6s
Sync infra to hosts / sync-prod (push) Successful in 5s
secrets-guard / encrypted (push) Successful in 10s
shell-lint / shellcheck (push) Successful in 9s
2026-07-26 08:06:32 +00:00
emi
4122f4353b dev: serve at dev.thermograph.org behind basic auth, bound to loopback (#111)
Some checks failed
Sync infra to hosts / sync-beta (push) Has been skipped
Sync infra to hosts / sync-prod (push) Has been skipped
Sync infra to hosts / sync-dev (push) Failing after 5s
secrets-guard / encrypted (push) Successful in 6s
shell-lint / shellcheck (push) Successful in 16s
PR build (required check) / changes (pull_request) Successful in 14s
secrets-guard / encrypted (pull_request) Successful in 13s
shell-lint / shellcheck (pull_request) Successful in 11s
PR build (required check) / build-backend (pull_request) Has been skipped
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) / gate (pull_request) Successful in 1s
2026-07-26 07:49:43 +00:00
emi
e6d9b36742 Merge pull request 'promote: dev → main (cutover fixes: sync-dev guard, owner-db hardening, post-deploy gate)' (#110) from dev into main
All checks were successful
Sync infra to hosts / sync-dev (push) Has been skipped
shell-lint / shellcheck (push) Successful in 9s
Sync infra to hosts / sync-beta (push) Successful in 7s
Sync infra to hosts / sync-prod (push) Successful in 5s
secrets-guard / encrypted (push) Successful in 4s
2026-07-26 07:29:33 +00:00
emi
64986189e1 deploy.sh: honour TG_POST_DEPLOY on the compose path too (#109)
All checks were successful
Sync infra to hosts / sync-beta (push) Has been skipped
Sync infra to hosts / sync-dev (push) Successful in 5s
secrets-guard / encrypted (push) Successful in 5s
shell-lint / shellcheck (push) Successful in 7s
PR build (required check) / changes (pull_request) Successful in 7s
PR build (required check) / build-frontend (pull_request) Has been skipped
shell-lint / shellcheck (pull_request) Successful in 9s
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / gate (pull_request) Successful in 1s
Sync infra to hosts / sync-prod (push) Has been skipped
secrets-guard / encrypted (pull_request) Successful in 6s
PR build (required check) / build-backend (pull_request) Has been skipped
2026-07-26 07:28:43 +00:00
emi
5c41ee4dad provision-env-db: revoke PUBLIC connect on the owner database too (#108)
All checks were successful
Sync infra to hosts / sync-beta (push) Has been skipped
Sync infra to hosts / sync-prod (push) Has been skipped
Sync infra to hosts / sync-dev (push) Successful in 7s
secrets-guard / encrypted (push) Successful in 5s
shell-lint / shellcheck (push) Successful in 7s
2026-07-26 07:17:20 +00:00
emi
d5357d0670 Merge pull request 'promote: dev → main (vps1/vps2 estate split)' (#106) from dev into main
All checks were successful
Sync infra to hosts / sync-dev (push) Has been skipped
Sync infra to hosts / sync-beta (push) Successful in 6s
Sync infra to hosts / sync-prod (push) Successful in 4s
secrets-guard / encrypted (push) Successful in 5s
Validate observability stack / validate (push) Successful in 12s
shell-lint / shellcheck (push) Successful in 13s
2026-07-26 07:07:28 +00:00
emi
7583258509 infra-sync: refuse to render dev's vault onto a host that is not dev (#107)
Some checks failed
Sync infra to hosts / sync-beta (push) Has been skipped
Sync infra to hosts / sync-prod (push) Has been skipped
Sync infra to hosts / sync-dev (push) Failing after 5s
secrets-guard / encrypted (push) Successful in 5s
shell-lint / shellcheck (push) Successful in 8s
PR build (required check) / changes (pull_request) Successful in 7s
secrets-guard / encrypted (pull_request) Successful in 7s
PR build (required check) / build-backend (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Has been skipped
shell-lint / shellcheck (pull_request) Successful in 11s
PR build (required check) / validate-observability (pull_request) Successful in 21s
PR build (required check) / gate (pull_request) Successful in 2s
2026-07-26 07:05:09 +00:00
emi
d138f00a20 infra: split the estate into vps1/vps2 — beta joins prod, dev gets a home (#103)
Some checks failed
Sync infra to hosts / sync-beta (push) Has been skipped
Sync infra to hosts / sync-prod (push) Has been skipped
Sync infra to hosts / sync-dev (push) Failing after 6s
secrets-guard / encrypted (push) Successful in 6s
shell-lint / shellcheck (push) Successful in 13s
Validate observability stack / validate (push) Successful in 17s
PR build (required check) / changes (pull_request) Successful in 6s
secrets-guard / encrypted (pull_request) Successful in 5s
PR build (required check) / build-backend (pull_request) Has been skipped
shell-lint / shellcheck (pull_request) Successful in 6s
PR build (required check) / build-frontend (pull_request) Has been skipped
PR build (required check) / validate-observability (pull_request) Successful in 18s
PR build (required check) / gate (pull_request) Successful in 2s
2026-07-26 06:56:38 +00:00
emi
4d6ce5b70b Merge pull request 'promote: dev → main (Weekly UTC-today date fix)' (#105) from dev into main
All checks were successful
Build + push images (Forgejo registry) / build-push (backend) (push) Successful in 6s
Deploy / deploy (backend) (push) Successful in 6s
secrets-guard / encrypted (push) Successful in 5s
shell-lint / shellcheck (push) Successful in 14s
Deploy / deploy (frontend) (push) Successful in 21s
Build + push images (Forgejo registry) / build-push (frontend) (push) Successful in 46s
2026-07-26 06:22:09 +00:00
emi
5b7e30dad9 fix(frontend): Weekly view must always send an explicit date to /grade
All checks were successful
Build + push images (Forgejo registry) / build-push (backend) (push) Successful in 6s
secrets-guard / encrypted (push) Successful in 6s
shell-lint / shellcheck (push) Successful in 9s
secrets-guard / encrypted (pull_request) Successful in 17s
shell-lint / shellcheck (pull_request) Successful in 16s
PR build (required check) / changes (pull_request) Successful in 20s
PR build (required check) / build-backend (pull_request) Has been skipped
PR build (required check) / validate-observability (pull_request) Has been skipped
Build + push images (Forgejo registry) / build-push (frontend) (push) Successful in 59s
PR build (required check) / build-frontend (pull_request) Successful in 35s
PR build (required check) / gate (pull_request) Successful in 2s
2026-07-26 06:20:19 +00:00
emi
ba1085bf39 Merge pull request 'promote: dev → main' (#100) from dev into main
All checks were successful
secrets-guard / encrypted (push) Successful in 8s
shell-lint / shellcheck (push) Successful in 10s
Deploy / deploy (backend) (push) Successful in 52s
Build + push images (Forgejo registry) / build-push (backend) (push) Successful in 55s
Build + push images (Forgejo registry) / build-push (frontend) (push) Successful in 59s
Deploy / deploy (frontend) (push) Successful in 58s
secrets-guard / encrypted (pull_request) Successful in 6s
shell-lint / shellcheck (pull_request) Successful in 9s
2026-07-25 21:14:22 +00:00
emi
5f20fba9f5 frontend: fix the three inconsistencies the onboarding guide found (#99)
All checks were successful
secrets-guard / encrypted (push) Successful in 5s
shell-lint / shellcheck (push) Successful in 8s
secrets-guard / encrypted (pull_request) Successful in 18s
PR build (required check) / changes (pull_request) Successful in 22s
shell-lint / shellcheck (pull_request) Successful in 19s
Build + push images (Forgejo registry) / build-push (frontend) (push) Successful in 1m11s
Build + push images (Forgejo registry) / build-push (backend) (push) Successful in 1m14s
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Successful in 1m1s
PR build (required check) / build-backend (pull_request) Successful in 1m21s
PR build (required check) / gate (pull_request) Successful in 2s
2026-07-25 21:11:32 +00:00
Emi Griffith
12441be0c1 docs: add a developer onboarding guide for the monorepo
All checks were successful
secrets-guard / encrypted (push) Successful in 5s
shell-lint / shellcheck (push) Successful in 6s
Twelve documents under docs/onboarding/ covering orientation, local setup,
the repo map, per-domain deep dives, the cross-service contracts, CI and the
release flow, infra and secrets, observability, task recipes, and a list of
which docs in this tree are currently stale.

Every command in the setup guide was run against this checkout: the backend
suite (429 passed, 8 skipped), the frontend Go suite, a venv boot of the
backend, and a build+boot of the Go frontend.

Two findings recorded along the way:

- static/units.js's F_REGIONS is guarded by no test, despite three source
  comments claiming "a test asserts all three stay identical". The Go test
  only cross-checks the Go copy against the backend's Python. All four copies
  are currently identical.
- backend/ and frontend/docker-compose.test.yml still default to the retired
  emi/thermograph-backend/app image path, and the frontend harness pins the
  split-era v0.0.2-split-ci tag.

Claude-Session: https://claude.ai/code/session_01AfXqHrxCJLs2D7hpQkiUiJ
2026-07-25 18:34:44 +00:00
emi
0766fd6bcb Merge pull request 'promote: dev → main (alert template: omit empty value line)' (#97) from dev into main
All checks were successful
secrets-guard / encrypted (push) Successful in 10s
shell-lint / shellcheck (push) Successful in 16s
Validate observability stack / validate (push) Successful in 20s
2026-07-25 18:19:09 +00:00
emi
b32b5841f3 alerting: don't print a bare "value:" when ValueString is empty (#96)
All checks were successful
secrets-guard / encrypted (push) Successful in 14s
Validate observability stack / validate (push) Successful in 17s
shell-lint / shellcheck (push) Successful in 14s
secrets-guard / encrypted (pull_request) Successful in 5s
PR build (required check) / changes (pull_request) Successful in 8s
shell-lint / shellcheck (pull_request) Successful in 6s
PR build (required check) / build-backend (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Has been skipped
PR build (required check) / validate-observability (pull_request) Successful in 20s
PR build (required check) / gate (pull_request) Successful in 2s
2026-07-25 18:17:37 +00:00
emi
c67d22b152 Merge pull request 'promote: dev → main (alerting liveness rules onto the app heartbeat)' (#95) from dev into main
All checks were successful
secrets-guard / encrypted (push) Successful in 6s
Validate observability stack / validate (push) Successful in 19s
shell-lint / shellcheck (push) Successful in 15s
2026-07-25 17:53:31 +00:00
emi
1a56a63800 alerting: base web/worker liveness on the app heartbeat, not container stdout (#94)
All checks were successful
secrets-guard / encrypted (push) Successful in 5s
shell-lint / shellcheck (push) Successful in 7s
Validate observability stack / validate (push) Successful in 12s
PR build (required check) / changes (pull_request) Successful in 8s
secrets-guard / encrypted (pull_request) Successful in 7s
shell-lint / shellcheck (pull_request) Successful in 8s
PR build (required check) / build-backend (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Has been skipped
PR build (required check) / validate-observability (pull_request) Successful in 18s
PR build (required check) / gate (pull_request) Successful in 2s
2026-07-25 17:51:42 +00:00
emi
aa4ee7f4c4 Merge pull request 'promote: dev → main (CI consolidation, 15 workflows → 9)' (#90) from dev into main
All checks were successful
Build + push images (Forgejo registry) / build-push (frontend) (push) Successful in 6s
Deploy / deploy (frontend) (push) Successful in 12s
Sync infra to hosts / sync-prod (push) Successful in 9s
Sync infra to hosts / sync-beta (push) Successful in 12s
secrets-guard / encrypted (push) Successful in 13s
shell-lint / shellcheck (push) Successful in 14s
Build + push images (Forgejo registry) / build-push (backend) (push) Successful in 46s
Deploy / deploy (backend) (push) Successful in 50s
secrets-guard / encrypted (pull_request) Successful in 7s
shell-lint / shellcheck (pull_request) Successful in 9s
2026-07-25 16:58:11 +00:00
emi
d4a00099f2 climate: stop dropping the current day from the Open-Meteo bundle (#92)
All checks were successful
secrets-guard / encrypted (push) Successful in 10s
Build + push images (Forgejo registry) / build-push (frontend) (push) Successful in 12s
shell-lint / shellcheck (push) Successful in 9s
secrets-guard / encrypted (pull_request) Successful in 13s
PR build (required check) / changes (pull_request) Successful in 19s
shell-lint / shellcheck (pull_request) Successful in 15s
PR build (required check) / build-frontend (pull_request) Has been skipped
PR build (required check) / validate-observability (pull_request) Has been skipped
Build + push images (Forgejo registry) / build-push (backend) (push) Successful in 1m13s
PR build (required check) / build-backend (pull_request) Successful in 1m6s
PR build (required check) / gate (pull_request) Successful in 1s
2026-07-25 16:56:21 +00:00
emi
52cfe5b77a Merge pull request 'Merge main back into dev to reconcile the squash-promotion divergence' (#91) from sync/main-into-dev into dev
All checks were successful
secrets-guard / encrypted (push) Successful in 6s
PR build (required check) / changes (pull_request) Successful in 11s
shell-lint / shellcheck (push) Successful in 13s
secrets-guard / encrypted (pull_request) Successful in 9s
PR build (required check) / build-backend (pull_request) Has been skipped
shell-lint / shellcheck (pull_request) Successful in 11s
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) / gate (pull_request) Successful in 1s
2026-07-25 08:45:51 +00:00
Emi Griffith
be4aa940d9 Merge main back into dev to reconcile the squash-promotion divergence
All checks were successful
secrets-guard / encrypted (pull_request) Successful in 5s
PR build (required check) / changes (pull_request) Successful in 11s
shell-lint / shellcheck (pull_request) Successful in 7s
PR build (required check) / build-backend (pull_request) Has been skipped
PR build (required check) / gate (pull_request) Successful in 1s
PR build (required check) / build-frontend (pull_request) Has been skipped
PR build (required check) / validate-observability (pull_request) Has been skipped
The dev → main promotion could not merge: `main` sat 22 commits ahead of `dev`
with content dev had never seen, and git found genuine conflicts in CLAUDE.md
and README.md plus modify/delete on the eight workflow files #87 removed.

The cause is that recent promotions were merged with squash rather than "Create
merge commit". A squash replays dev's commits onto main under new SHAs, so the
two branches share content but not history — main appears to have independently
edited the same files, and every subsequent promotion inherits the divergence.
`promote` warns about exactly this.

Resolution: both conflicts take dev's side, not as a default but because main's
side describes workflows that no longer exist (`*-deploy-dev.yml`,
`backend-build-push` and friends). Keeping it would reintroduce the class of
staleness the root CLAUDE.md now forbids — statements naming files that are not
there. The eight deleted workflows stay deleted; the merge result carries the
nine that #87 left behind.

Verified after resolution: no conflict markers anywhere, no unmerged paths, no
document naming a deleted workflow, all nine workflow files parse, and
shellcheck is clean across the tree.

Promotions from here should use "Create merge commit" so this does not recur.
2026-07-25 01:44:54 -07:00
emi
d42a57a011 ci: collapse the eight deploy and build-push workflows into two (#87)
All checks were successful
secrets-guard / encrypted (push) Successful in 5s
shell-lint / shellcheck (push) Successful in 6s
PR build (required check) / changes (pull_request) Successful in 6s
secrets-guard / encrypted (pull_request) Successful in 6s
PR build (required check) / build-backend (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Has been skipped
shell-lint / shellcheck (pull_request) Successful in 9s
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / gate (pull_request) Successful in 2s
2026-07-25 07:48:49 +00:00
emi
dde2cdd6e2 infra: mirror LAN dev secrets under $HOME for snap-confined Docker (#85)
Some checks failed
Sync infra to hosts / sync-beta (push) Failing after 13s
Sync infra to hosts / sync-prod (push) Successful in 25s
secrets-guard / encrypted (push) Successful in 22s
Validate observability stack / validate (push) Successful in 27s
shell-lint / shellcheck (push) Successful in 21s
Build + push backend image (Forgejo registry) / build-push (push) Successful in 1m24s
Build + push frontend image (Forgejo registry) / build-push (push) Successful in 1m21s
Deploy backend to beta VPS / deploy (push) Successful in 2m4s
Deploy frontend to beta VPS / deploy (push) Successful in 2m12s
2026-07-25 07:19:18 +00:00
emi
7307a7aadc guardrails: enforce live-host and secrets policy with hooks (#82) 2026-07-25 07:19:18 +00:00
emi
1acf8414ff docs: rewrite the agent context layer to match the live system (#81) 2026-07-25 07:19:18 +00:00
emi
bee5b21587 infra/forgejo: give the LAN runner's PATH ~/.local/bin (#84) 2026-07-25 07:19:18 +00:00
emi
9b6b12a5da infra: mirror LAN dev secrets under $HOME for snap-confined Docker (#85)
All checks were successful
secrets-guard / encrypted (push) Successful in 6s
shell-lint / shellcheck (push) Successful in 7s
PR build (required check) / changes (pull_request) Successful in 6s
secrets-guard / encrypted (pull_request) Successful in 6s
shell-lint / shellcheck (pull_request) Successful in 7s
PR build (required check) / validate-observability (pull_request) Successful in 38s
PR build (required check) / build-frontend (pull_request) Successful in 1m6s
PR build (required check) / build-backend (pull_request) Successful in 1m25s
PR build (required check) / gate (pull_request) Successful in 2s
2026-07-25 07:16:08 +00:00
emi
fbdfebf873 guardrails: enforce live-host and secrets policy with hooks (#82)
All checks were successful
shell-lint / shellcheck (push) Successful in 14s
secrets-guard / encrypted (push) Successful in 15s
PR build (required check) / changes (pull_request) Successful in 18s
secrets-guard / encrypted (pull_request) Successful in 15s
shell-lint / shellcheck (pull_request) Successful in 18s
PR build (required check) / validate-observability (pull_request) Successful in 37s
PR build (required check) / build-frontend (pull_request) Successful in 3m1s
PR build (required check) / build-backend (pull_request) Successful in 3m32s
PR build (required check) / gate (pull_request) Successful in 4s
2026-07-25 07:09:11 +00:00
emi
e84b1f7937 docs: rewrite the agent context layer to match the live system (#81)
Some checks failed
shell-lint / shellcheck (push) Has been cancelled
secrets-guard / encrypted (push) Has been cancelled
Validate observability stack / validate (push) Successful in 33s
Build + push backend image (Forgejo registry) / build-push (push) Successful in 3m5s
Deploy frontend to LAN dev server / build (push) Successful in 3m21s
Build + push frontend image (Forgejo registry) / build-push (push) Successful in 3m27s
Deploy backend to LAN dev server / build (push) Successful in 4m16s
Deploy frontend to LAN dev server / deploy (push) Successful in 31s
Deploy backend to LAN dev server / deploy (push) Successful in 1m19s
2026-07-25 07:08:54 +00:00
emi
2c7ceefab4 infra/forgejo: give the LAN runner's PATH ~/.local/bin (#84)
All checks were successful
secrets-guard / encrypted (push) Successful in 5s
shell-lint / shellcheck (push) Successful in 6s
2026-07-25 06:59:21 +00:00
emi
be88987d95 Merge pull request 'promote: dev → main' (#83) from dev into main
All checks were successful
secrets-guard / encrypted (push) Successful in 8s
shell-lint / shellcheck (push) Successful in 7s
Build + push backend image (Forgejo registry) / build-push (push) Successful in 44s
Deploy backend to beta VPS / deploy (push) Successful in 48s
2026-07-25 06:06:09 +00:00
emi
a4ecb51401 web/worker: add a process-level liveness heartbeat (#80)
Some checks failed
secrets-guard / encrypted (push) Successful in 24s
shell-lint / shellcheck (push) Successful in 26s
Deploy frontend to LAN dev server / build (push) Successful in 2m11s
Build + push frontend image (Forgejo registry) / build-push (push) Successful in 2m20s
Build + push backend image (Forgejo registry) / build-push (push) Successful in 2m28s
Deploy backend to LAN dev server / build (push) Successful in 2m45s
PR build (required check) / changes (pull_request) Successful in 16s
secrets-guard / encrypted (pull_request) Successful in 16s
shell-lint / shellcheck (pull_request) Successful in 15s
PR build (required check) / build-frontend (pull_request) Has been skipped
PR build (required check) / validate-observability (pull_request) Has been skipped
Deploy frontend to LAN dev server / deploy (push) Successful in 39s
PR build (required check) / build-backend (pull_request) Successful in 1m21s
PR build (required check) / gate (pull_request) Successful in 3s
Deploy backend to LAN dev server / deploy (push) Failing after 2m31s
2026-07-25 04:13:47 +00:00
emi
6c6842ab9e Merge pull request 'Promote dev to main: dev + Centralis vaults' (#78) from dev into main
All checks were successful
Sync infra to hosts / sync-prod (push) Successful in 5s
secrets-guard / encrypted (push) Successful in 7s
shell-lint / shellcheck (push) Successful in 9s
Sync infra to hosts / sync-beta (push) Successful in 7s
secrets-guard / encrypted (pull_request) Successful in 6s
shell-lint / shellcheck (pull_request) Successful in 8s
2026-07-25 01:16:04 +00:00
emi
72ad6f300f Merge pull request 'secrets: vault dev and Centralis; render dev without common.yaml' (#77) from feat/centralis-vault into dev
All checks were successful
secrets-guard / encrypted (push) Successful in 5s
shell-lint / shellcheck (push) Successful in 8s
PR build (required check) / changes (pull_request) Successful in 6s
secrets-guard / encrypted (pull_request) Successful in 5s
shell-lint / shellcheck (pull_request) Successful in 6s
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Successful in 54s
PR build (required check) / build-backend (pull_request) Successful in 1m8s
PR build (required check) / gate (pull_request) Successful in 2s
2026-07-25 01:14:05 +00:00
Emi Griffith
33cd69e44e secrets: silence two SC2016s that are the intended behaviour
All checks were successful
PR build (required check) / changes (pull_request) Successful in 8s
secrets-guard / encrypted (pull_request) Successful in 6s
shell-lint / shellcheck (pull_request) Successful in 6s
PR build (required check) / build-backend (pull_request) Has been skipped
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) / gate (pull_request) Successful in 2s
shell-lint failed on two single-quoted strings. Both are deliberate and
double-quoting either one would break it silently rather than loudly.

In render_centralis_secrets, the verification step runs `bash -c 'set -a; . "$1"'`
with the rendered file passed as an argument. The "$1" must be expanded by that
inner shell. Double-quoted, it would interpolate the OUTER $1 — the function's
own first argument, the repo root — so the check would source the wrong path and
still report success. That check exists precisely to catch a bad render, so a
false pass there is worse than no check.

In verify-centralis-render.sh, the string is executed by the REMOTE shell over
ssh. Double-quoted, mktemp would run locally and the script would send the host
a path that does not exist there.

Suppressed with the reason at each site rather than loosened globally.

Claude-Session: https://claude.ai/code/session_0182KTMrsTHJc3TcewCatJFY
2026-07-24 18:13:08 -07:00
Emi Griffith
43c9e2052a secrets: vault dev and Centralis; render dev without common.yaml
Some checks failed
PR build (required check) / changes (pull_request) Successful in 7s
secrets-guard / encrypted (pull_request) Successful in 5s
PR build (required check) / build-backend (pull_request) Has been skipped
PR build (required check) / build-frontend (pull_request) Has been skipped
shell-lint / shellcheck (pull_request) Failing after 9s
PR build (required check) / validate-observability (pull_request) Has been skipped
PR build (required check) / gate (pull_request) Successful in 2s
Brings the last two credential stores under SOPS, so all three environments and
the control plane are managed the same way.

dev.yaml — dev was not "intentionally not wired in", it was broken

The vault README claimed dev had no real secrets. Both halves were false.

Dev needed secrets it did not have: thermograph-dev-daemon-1 has been in a crash
loop, restarting every ~60s with "neither THERMOGRAPH_INTERNAL_TOKEN nor
THERMOGRAPH_AUTH_SECRET is set; refusing to start" — so dev has had no Discord
gateway and no job timers. With THERMOGRAPH_BASE_URL unset the app also falls
back to https://thermograph.org, so dev's IndexNow pings and verification links
claimed to be prod. dev.yaml gives it its own generated AUTH_SECRET and a real
base URL, and 12 values total.

And dev already held production credentials: backend-deploy-dev.yml injects
S3_ACCESS_KEY/S3_SECRET_KEY into every dev deploy, and the only provisioned
keypair for that bucket is read-write — on the bucket holding prod's backups.
Dev does not need them; without bucket creds the lake service 503s and history
falls through to the archive. Those workflow lines still need removing.

dev renders dev.yaml ALONE, via THERMOGRAPH_SECRETS_SKIP_COMMON=1. Eleven of
common.yaml's sixteen values are live production credentials, the render is a
plaintext concatenation consumed through env_file:, and dev is the operator's
desktop AND the Forgejo runner executing unreviewed dev-branch code with the
docker socket mounted. An override in dev.yaml would not help — last-wins
governs consumers, but prod's value is still physically a line in the file.
Verified: current renderer leaks 28 lines onto dev including both S3 keypairs
and the VAPID private key; patched gives exactly 12 keys and no prod credential.
Beta's render is byte-identical either way.

centralis.prod.yaml — its own file, its own renderer

/etc/centralis.env was hand-edited, which is how a JSON registry got written
unquoted into a shell-sourced file tonight and silently collapsed three
identities to one. The renderer now owns the file.

It is service- AND environment-scoped, not folded into prod.yaml, because
/etc/thermograph.env is loaded into every container in the app stack. Folding
these in would put CENTRALIS_AUTH_TOKEN and CENTRALIS_TOKENS — which
authenticate an endpoint carrying run_on_host and sql_query(write) — into the
web backend's environment, turning a read-anything bug in the app into a
foothold on the control plane.

Quoting is guaranteed three ways rather than assumed. Critically, `sops -d
--output-type dotenv` emits values verbatim, so reusing the existing render path
would have reproduced tonight's bug exactly. The new function decrypts to JSON
and emits POSIX single-quoted assignments; it then sources its own output in a
clean shell and compares every value before touching /etc; and it refuses to
write unless CENTRALIS_TOKENS parses as a non-empty subject->token object after
sourcing. Tested against 16 hostile values including embedded quotes, newlines
and ;rm -rf /.

Value-identity proven, not asserted: rendered vs live compared as *effective*
values on prod (a textual diff would report a false difference, and would report
a false match if the vault had captured quote characters as part of the value),
plus both env files producing a byte-identical `docker compose config` digest.
9 keys, both token subjects preserved. Nothing deployed.

Note for later: /etc/thermograph.env is also shell-sourced, and survives on raw
dotenv only because none of its 32 current values contains a shell-special
character. It is one quoted secret away from the same bug.

Claude-Session: https://claude.ai/code/session_0182KTMrsTHJc3TcewCatJFY
2026-07-24 18:10:51 -07:00