Commit Graph
5 Commits
Author SHA1 Message Date
Omar SobhandClaude Opus 5 3124fd3c8f feat(library): weekly harvest on a systemd timer
ci / gates (push) Failing after 7s
ci / rust (push) Skipped
ci / frontend (push) Skipped
ci / e2e (push) Skipped
ci / publish (push) Skipped
Monday 07:00, Persistent=true so a week missed to downtime fires on next
boot rather than leaving a silently empty library. 30-minute timeout so a
wedged run cannot hold the slot until the following week.

The script is deliberately thin — it calls the API and reports — so it
never needs changing when the harvest does. Auth is a long-lived operator
session in /etc/clawmates/library.token (root-only, 600); rotate by
replacing the file.

Exit status follows `healthy`, not paper count. A mature library shelves
nothing most weeks and that is success; a run that errored is a failure
even if it shelved something.

The first manual fire caught a real bug in this script, in the opposite
direction to this week's usual: the harvest genuinely shelved 15 papers
and pushed them, and the reporter crashed on an escaped quote inside an
f-string, so systemd marked the unit FAILED. A false failure destroys
trust in the signal exactly as a false success does. The reporter now
avoids backslashes entirely (it is embedded in a single-quoted shell
string) and was proved against the real response shape before being
trusted.

Verified end to end on gw-04:
  run 1: 25 candidates, 10 already held, 15 shelved, pushed
  run 2: 25 candidates, 25 already held,  0 shelved, no branch, healthy

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-03 10:59:13 -07:00
Omar Sobh 8f29cf8e44 deploy(gw-04): run the timer as a dedicated clawmates user under /opt
ci / gates (push) Successful in 6s
ci / frontend (push) Successful in 37s
ci / e2e (push) Failing after 15s
ci / publish (push) Successful in 21s
ci / rust (push) Successful in 2m57s
Move the running stack off root ownership. The systemd service now runs
as User=clawmates:clawmates with WorkingDirectory=/opt/clawmates, and the
script's COMPOSE_DIR default follows. This closes the "rootful compose
stack" ask from the original ship-readiness audit — deploys no longer
require any part of the pipeline to run as root beyond docker access
(the clawmates user gets that via the docker group).

Docker-managed volumes (pgdata, broker_run, broker_key, brains, filedata)
stay put; the compose project name is unchanged so docker resolves them
to the same physical volumes. The old /root/clawmates directory stays in
place as an emergency rollback for a week, then gets removed as follow-up.
2026-07-05 19:39:08 -07:00
Omar Sobh 39a6424d72 deploy(gw-04): drop the un-prefixed retag bridge
ci / frontend (push) Successful in 24s
ci / e2e (push) Failing after 24s
ci / gates (push) Successful in 6s
ci / rust (push) Successful in 3m39s
ci / publish (push) Successful in 20s
The compose file on gw-04 was migrated to registry-prefixed image
references (100.94.185.103:5000/clawmates/<svc>:latest), which lets
`docker compose up` pick up the pulled image directly. The old script
retagged each pulled image to `clawmates/<svc>:latest` as a bridge so
the previous compose file (which used bare names) would find it —
that step is now unnecessary and just added a small window where the
un-prefixed tag could diverge from the registry.

Drift check now compares against the registry-prefixed tag directly.
`docker compose` v2 preferred with `docker-compose` v1 fallback stays.
2026-07-05 19:25:25 -07:00
Omar Sobh 3f82d9efe4 deploy(gw-04): running-container drift check + docker-compose v1 fallback
ci / gates (push) Successful in 21s
ci / frontend (push) Successful in 35s
ci / rust (push) Failing after 1m2s
ci / e2e (push) Has been skipped
ci / publish (push) Successful in 4m35s
Two fixes needed to make the timer actually roll correctly on gw-04:

1. Drift check compares the running container's image ID against the
   local `clawmates/<svc>:latest` tag, not just pre/post-pull digests.
   The pre/post check only catches new pulls — if a previous roll failed
   between the retag and `docker compose up` (e.g. compose CLI failed),
   the tag was updated but the container wasn't, and the next tick saw
   no drift and silently left the stale container running. The
   running-vs-tag check catches that case on the next tick.

2. Prefer `docker compose` (v2 plugin) but fall back to legacy
   `docker-compose` (v1). GW-04 ships v1 only right now, and calling
   `docker compose up -d` failed with "unknown shorthand flag: 'd'"
   because docker had no `compose` subcommand at all. The fallback
   keeps the script portable when the stack moves to a host with v2.
2026-07-05 18:55:12 -07:00
Omar Sobh 4480c750bf build+deploy: reproducible pipeline via Gitea Actions + gw-04 image-watcher
ci / gates (pull_request) Successful in 1m3s
ci / frontend (pull_request) Successful in 27s
ci / rust (pull_request) Failing after 2m44s
ci / e2e (pull_request) Has been skipped
ci / publish (pull_request) Has been skipped
Adds a `publish` job to ci.yml that fires only on green pushes to main. It
builds broker, server, and frontend from images/*.Dockerfile, tags each with
:main-<sha> + :latest, and pushes to the fleet registry at
redclaw-web-01:5000 (via its Tailscale IP 100.94.185.103, which the daemons
already trust in insecure-registries).

Adds a small systemd oneshot + 1-minute timer for gw-04 that polls :latest
of each service, pulls on drift, retags to the un-prefixed name the current
compose file uses, and rolls only the changed services. The retag keeps
/root/clawmates/docker-compose.yml unchanged for now — a follow-up can
migrate the compose file to registry-prefixed names once we're confident.

End-to-end: push to main -> tests -> images pushed -> gw-04 timer pulls
within ~1 min -> prod updated. Rollback = docker tag <old-sha> :latest and
`docker compose up -d`.
2026-07-05 08:41:40 -07:00