Publish docs — automated release

Dispatch publish.yml with the epoch Devin tagged after pushing changes. The old manual flow (stepwise sync → wiki builds → deploys → backups → bookkeeping) is fully automated — review is the only manual gate. Architecture: publish-pipeline; infrastructure: gitea, wiki, infra-wiki, dev-vm.

Steps

  • Devin works in ~/repos/infra-docs (branch → squash-merge → main), tags the publish epoch, then pushes main + tags to the devvm mirror.
  • Operator reviews the diff and dispatches publish.yml from gitea → Actions on the tooling repo, expect_epoch=<hash> (the bare hash — no publish-epoch- prefix). force_wiki=true only to force a redeploy when content moved but infra-wiki didn’t.
  • Watch the run — each phase logs a === header. Phases: setup → sync → wiki → backups → finalize-epoch → state-save.
  • Verify: ci/epoch.sh status ~/mirrors infra-docs infra-docs-mirror infra-wiki — the new epoch tag on all repos = the run landed end-to-end (mirrors ← runner ← store). Content on the wiki: green deploy message in the log, or spot-check a new page.
  • Per operator machine: ./operator-pull.sh — ff-pulls the clones. On the LiveSync-source machine, open Obsidian once to push to couchdb; other clients receive it from LiveSync.

What the run does

setup → poll for expect_epoch on all epoch repos (5s, 2min budget; waits out the ferry) → set the publish-lock ref → render the docmirror config from ci.env + secrets → sync-in → sync-out → wiki: w.sh sync into infra-wiki → commit content → build + deploy local (wiki over rsync/ssh) and portfolio (wrangler → Pages) → --mirror backup push of each backup repo to gitea → stamp the new epoch tags → commit/push the state repo (declared files only) → the lock ref clears on exit and the ferry shuttles the run’s output refs back to the devvm mirrors on its next pass.

Operator prerequisites

  • host-ferry service running on «HOSTNAME» — ssh «HOSTNAME» 'systemctl status host-ferry'. Output relay uses ssh aliases devin/ci from the host’s ~/.ssh/config.
  • Workflow credentials in gitea — Actions secrets + variables on the tooling repo (GITEA_* is a reserved prefix — names can’t start with it).
  • Runner LXC 116 gitea-runner up (10.0.1.36), service unit gitea-runner, registered label gitea-runner:host — the workflow selects it via runs-on: gitea-runner. Needs features: nesting=1 in /etc/pve/lxc/116.conf for the containerized wiki build.

Notes

  • The runner mirrors are read-only endpoints for everyone but the runner — ssh ci /srv/mirrors/*.git only for inspection. Push to them only if you’re fixing runner state by hand (log says what it refused to deliver).
  • Devin doesn’t touch devvm mirrors while a run is in flight — if a repo’s tracked head diverges from canonical the ferry abandons the whole repo’s output, so the epoch can never claim a completed run that lost writes. It’s already happened for a routine push during a window; treat the epoch as the verdict.
  • The output epoch lives on main of infra-docs, infra-docs-mirror, infra-wiki. Watching it appear on the devvm mirrors is the green-light — a run that never completes never stamps it.

Failure → action

  • Epoch wait times out (still waiting for in setup): the ferry hasn’t delivered the input epoch to the runner yet — check the ferry service on «HOSTNAME», then re-dispatch the same epoch.
  • abandoning this run's output in the ferry log: runner-side heads diverged from canonical — check whether the run actually finished (stale publish-epoch-* tag on the runner’s repo is the tell). If so the diverged data is recoverable from the runner’s /srv/mirrors or the tracking refs in the store; if not, rerun.
  • Wiki deploy failed but the rest went green: phase order preserves the redaction bookkeeping; force the wiki stage only via force_wiki=true on re-dispatch.
  • State push failure at state-save: the epoch still landed — fix the state clone remote/permissions on the runner, then re-run or push manually.
  • Ferry service down / machine change: output stays on the runner’s mirrors until a pass relays it — no data loss, epoch just lags on devvm.