Record the host channel, its retention, and what the ref gate holds up - #35
Conversation
The two sides of the deploy are maintained separately and exchange rounds through two files on the VPS. The mechanics lived only in those files and in session directories, so nothing outside the conversation described how the channel works or what protects it. Record the paths, the transfer commands, the four rules, and the ownership convention that is the only thing keeping either side from overwriting the other's file. Name the host's prune unit rather than its count. A second daily retention runs on the same host and keeps a different number, so "ten, daily" identifies neither once it is read on its own. State what a single deploy key confined to the parent of both roots costs. The environments hold separate credentials and that separation stops at the runner, so the workflow's ref gate is what decides which tree a run writes into. It reads like housekeeping and is the boundary the credentials do not draw. Record that a rebuild regenerates the host keys. The transport pins them and fails closed, so a rebuilt host blocks the deploy and the rollback together until the pinned value is replaced on both environments. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🟢 Ready to approve
Changes are documentation-only and consistent/well-formed (no functional code paths or config behavior are modified).
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Pull request overview
This PR updates operational documentation for the blog’s deployment/operations model, capturing deploy-channel mechanics, retention ownership on the VPS vs local mirrors, the security role of the production ref gate, and the impact of VPS rebuilds on pinned SSH host keys. It also ensures the local working copies of the host communication channel are not accidentally committed.
Changes:
- Expand Retention documentation to distinguish local mirror pruning vs VPS host-side pruning, including the relevant timer unit.
- Add a new “Channel Between the Two Sides” section documenting the VPS file-based round exchange and its safety rules.
- Document the ref gate as a load-bearing security control and record the SSH known_hosts update requirement after host rebuilds; ignore
comms/working copies in git.
File summaries
| File | Description |
|---|---|
OPERATIONS.md |
Adds/clarifies operational facts about retention, the VPS comms channel, ref gating as a security boundary, and host-key pinning behavior on rebuilds. |
.gitignore |
Ignores comms/ to prevent committing local working copies of the VPS comms channel files. |
Review details
- Files reviewed: 1/2 changed files
- Comments generated: 0
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
There was a problem hiding this comment.
🟢 Ready to approve
The changes are documentation and gitignore updates that are internally consistent, low-risk, and align with the stated operational intent.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Review details
- Files reviewed: 1/2 changed files
- Comments generated: 0 new
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
There was a problem hiding this comment.
🟢 Ready to approve
The changes are documentation and a narrowly scoped .gitignore update, and the updated Markdown structure/commands appear internally consistent with the repo’s existing deploy documentation.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Review details
- Files reviewed: 1/2 changed files
- Comments generated: 0 new
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
Four operational facts that existed only in the agent channel with the host, or only in one side's head. Raised while retesting the deploy transport for #33, which is where each of them surfaced.
What changes
The channel itself is documented. The two sides of the deploy share no filesystem and no session, and exchange rounds through two files on the VPS. Nothing outside those files described the paths, the transfer commands, or the rules — including the two that exist because the channel has already failed: never pass
--delete, and re-pull immediately before appending, because pushing this side's file is a read-modify-write and is the one operation that can silently drop a round. Convention is the only protection either file has, and the doc says so rather than implying a permission scheme.The prune unit is named rather than its count quoted. The host runs two daily retention timers that keep different numbers,
blog-prune-releases.timerat ten release bundles andpangolin-backup.timerat fourteen config archives. "Ten, daily" identifies neither once it is read on its own. The host declared the count; this records the declaration rather than holding a second copy of it.The ref gate is stated as the control it is. One deploy key confined to the parent of both roots means whichever key is installed can write both trees. The two GitHub Environments hold separate secrets and separate variables, and that separation stops at the runner. So
assert-refrefusing a production deploy from any ref but the default branch is the boundary the credentials do not draw — and it reads like workflow housekeeping, which is the shape of thing that gets simplified away by someone who does not know what it holds up.A rebuild breaks the deploy and the rollback together. Cloud-init deletes and recreates the host keys when the instance identity changes, and the transport pins them with
StrictHostKeyChecking=yes. A rebuilt host therefore fails every deploy closed untilDEPLOY_SSH_KNOWN_HOSTSis replaced on both environments — at exactly the moment a rollback is most likely to be wanted.What is deliberately not here
The channel's rounds themselves are not committed. They carry the server's internals and the other side's material about a host this repository does not own, and this repository is public. The working copies live in
comms/, gitignored, at a fixed path so they are found by name rather than in whichever session directory last held them. The host's nightly backup covers both files and reaches an off-host copy.Verification
Both sides measured, on 2026-08-05:
31018236212, release20260805-150321, 1,245 contract URLs honored against the live site.ExecStart=/usr/local/sbin/blog-prune-releases --keep 10 --quietwithOnCalendar=daily, confirmed on the host after this text was drafted.31019247342, gate job failed, downstream jobs skipped, no deployment recorded.markdownlint-cli2 and editorconfig-checker both clean.
🤖 Generated with Claude Code