Deploy (scripts/deploy_web.rb + lib/deploy_backend/)

Architecture — part 11 of 13

The deploy script owns the what; backends own the how:

  • A manifest (.deploy_manifest<suffix>.json, one per backend) records hash+size+mtime of everything the target has. Unchanged size+mtime skips even reading the file; everything else is hashed to decide. From that fall out to_upload and orphans.
  • A baseline (.deploy_baseline.json, one for all backends) records the file count and total bytes of the last build the guards accepted, plus the previous run's outcome. It is the manifest's opposite number: the manifest is the state of the target, the baseline is the shape of the build -- which is why it carries no per-backend suffix.
  • Safeguards run before any backend, and measure the build against that baseline rather than against the manifest: an upload failure must not be able to move the yardstick. Which checks run, at which thresholds, and what --prune and --force do and do not override is in Running it -- so is the single per-file size limit alongside them, enforced by lib/file_size.rb when a post is saved as well as here.
  • Backends implement one of two shapes: per-file session/upload/delete (Surfer's HTTP API, local copies) or a single batch sync (rsync, rclone and git diff against the target themselves; sftp executes the manifest's precomputed lists). The git backend is a snapshot: every deploy force-pushes one commit that mirrors the build exactly, so it declares always_prunes? and the script keeps its bookkeeping honest.
  • list_root on every backend answers doctor --online: what stands in the target's root, as name and directory-or-not, which doctor holds against the build and the manifest to name what the site did not put there. Only the root -- one request on every backend, where Surfer would need one per directory for the whole tree -- and none for git, whose branch nothing foreign survives in; there the question is only whether the remote answers. The tools run through DeployBackend::Listing, with a deadline and ssh in batch mode (git's and RSYNC_SSH's too), so a dead host, a host-key question or a password prompt is a warning rather than a hang; a target directory that is not there yet is told apart from a host that does not answer.