sitesd cutover #
sitesd takes over site pushes after appview stops. do not restart appview
while sitesd is running: its old sitefeed would also deploy pushes. sitesd
follows org.tangled.git.refs on a jetstream and keeps its own cursor in the
sitefeed:jetstream:cursor Redis key, so it doesn't pick up appview's
sitefeed:cursor:* keys and starts live the first time. start the optional sites worker with
docker compose --profile sites-worker up; without it, local site pushes
have no active deploy executor. compose sets SITESD_DEV=true so sitesd starts
without R2 credentials; the feed remains inactive until they are supplied.
production starts fail if any R2 credential is missing.
for production, configure sitesd, the sites worker, Redis, and R2 before
stopping appview. start sitesd only after appview is down. set
SITESD_JETSTREAM_ENDPOINT (a jetstream that carries knot-hosted repos, like
hydrant's /subscribe), SITESD_KNOTS (the knots whose repos may deploy, empty for every knot),
SITESD_REDIS, Cloudflare R2 credentials and bucket, and a private
SITESD_INTERNAL_ADDR.
Expose that private /deploy listener only to the sites worker. Set the
worker's SITES_SD_URL to that reachable private endpoint; the checked-in
production value is empty, so config writes save the row but report
WorkerUnavailable and cannot trigger a deploy. Do not deploy this cutover
as if the empty value were working. The worker verifies ownership using the repo DID document and
the knot's describeRepo answer, not a record-supplied owner.
sites-migrate -apply -yes -remote imports only into an empty D1 target;
it refuses to overwrite live claims or deploy history. -validate -apply
checks parity after the import. Run the PDS claim backfill (claimer) after
import, and do not rerun the one-shot migration on a live D1. The standalone
count-parity check is for the initial import, before later claims and deploys
make the two databases intentionally different. Verify the new worker has the
site configs, then trigger initial deployments explicitly. sitesd resumes from
its saved jetstream cursor; with none it starts live and does not replay old
pushes.