From 9642952a54634645df4d69ac4ef38627051c95c5 Mon Sep 17 00:00:00 2001 From: Vuong Hoang Date: Sun, 23 Aug 2026 02:55:02 -0700 Subject: [PATCH] docs(hrafn-ci): mirror the now-canonical vh/hrafn pipeline; record two failed runs claude-bot holds write on vh/hrafn as of 2026-08-23, so the canonical copy of the pipeline moved there and infra-ops maintains it directly instead of routing patches through the repo holder. The files here are a verified mirror (byte-identical to live at 22e0eb9d75a6). Live state: run 9922 green, and both new content assertions executed rather than merely existing -- verify 4/5 host tree matches shipped context (a99ce748a0c9...) verify 5/5 image source matches host source (06f209fd0641...) The CI-computed context hash matching on the host is the end-to-end proof that the converge lands what CI ships. Its absence is what let the frozen-source bug survive every green deploy. Also records why the HEAD == GITHUB_SHA assertion was added and then removed: it needed the git binary (run 9920, exit 127), and installing git flipped actions/checkout@v4 from its node implementation to the git binary, which died on a missing CA bundle (run 9921). A nice-to-have assertion changed the checkout code path and broke a working pipeline; it guarded a hypothesis that proved wrong, so it went rather than getting ca-certificates bolted on. --- stacks/hrafn/ci/README.md | 47 +++++++++++++++++---- stacks/hrafn/ci/gitea-workflows-deploy.yaml | 25 ++++++----- 2 files changed, 53 insertions(+), 19 deletions(-) diff --git a/stacks/hrafn/ci/README.md b/stacks/hrafn/ci/README.md index d9ceeee..9195935 100644 --- a/stacks/hrafn/ci/README.md +++ b/stacks/hrafn/ci/README.md @@ -1,18 +1,24 @@ -# hrafn CI deploy — authored here, lands in `vh/hrafn` +# hrafn CI deploy — mirror of what runs in `vh/hrafn` -These two files replace hrafn's hand-rsync deploy. They are **authored and -version-controlled here** because infra-ops owns hrafn's uptime, but they -**belong in the `vh/hrafn` repo** — infra-ops has no write access to it -(claude-bot is not a collaborator), so they are handed to the repo holder -rather than committed directly. +These two files are hrafn's deploy pipeline. The **canonical copy now lives in +`vh/hrafn`** — as of 2026-08-23 claude-bot holds `write` there, so infra-ops +maintains the pipeline it owns directly instead of routing patches through the +repo holder. -| file here | destination in `vh/hrafn` | +| file here | canonical location in `vh/hrafn` | |---|---| | `playbooks-deploy.yaml` | `playbooks/deploy.yaml` | | `gitea-workflows-deploy.yaml` | `.gitea/workflows/deploy.yaml` | -Keep this copy in sync if the deployed version changes, or delete it once -infra-ops has write access to `vh/hrafn` and the repo copy is canonical. +This copy is a **mirror kept for review and history**, verified byte-identical +to the live files at commit `22e0eb9d75a6`. If you change one, change both — +or check with: + +```bash +curl -s "https://gitea.phasefinal.com/api/v1/repos/vh/hrafn/contents/playbooks/deploy.yaml?ref=main" \ + -H "Authorization: token $(cat ~/.config/claude-bot/gitea-token-repo-create)" \ + | python3 -c 'import json,sys,base64,hashlib; print(hashlib.sha256(base64.b64decode(json.load(sys.stdin)["content"])).hexdigest()[:12])' +``` ## What the change buys @@ -98,6 +104,29 @@ and `__pycache__` appears at runtime, so a naive `find src -type f` compare fails on every healthy deploy. Verified against a known-good container before shipping: 12 host files, 18 in the container, 0 content differences. +## Two failed runs getting there (9920, 9921) + +Worth reading before adding anything to the workflow's prerequisite step. + +The frozen-source fix originally shipped with a `HEAD == GITHUB_SHA` +assertion. It failed twice, both times for reasons the change itself +introduced: + +- **run 9920** — `git: command not found` (exit 127). act_runner's job image + ships no git binary, and `actions/checkout@v4` does not need one. +- **run 9921** — adding `git` made the checkout fail with `server certificate + verification failed. CAfile: none`. Installing git flips checkout@v4 from + its **node implementation** — which every working run of this pipeline had + used — to the **git binary**, and the image has no CA bundle. + +So a nice-to-have assertion changed the checkout's code path and broke a +working pipeline. It was removed rather than patched with `ca-certificates`: +it guarded a hypothesis that turned out to be **wrong** (the frozen source was +a self-referential rsync in the playbook, not a stale checkout), and +`clean: true` plus the host-side content hash already cover the real risk. + +**Do not add `git` to the prerequisite step.** Run 9922 is green with it out. + ## Validation The playbook parses and interpolates clean under elway's own parser: diff --git a/stacks/hrafn/ci/gitea-workflows-deploy.yaml b/stacks/hrafn/ci/gitea-workflows-deploy.yaml index 03bbdf5..99463d9 100644 --- a/stacks/hrafn/ci/gitea-workflows-deploy.yaml +++ b/stacks/hrafn/ci/gitea-workflows-deploy.yaml @@ -36,6 +36,13 @@ jobs: steps: - name: Install playbook prerequisites + # DO NOT add `git` here. actions/checkout@v4 uses its node + # implementation when no git binary is present, which is what every + # working run of this pipeline has used. Installing git flips it to + # the git binary, and this image ships no CA bundle — the checkout + # then dies with "server certificate verification failed. CAfile: + # none" (run 9921). Adding ca-certificates would paper over it; not + # installing git avoids the code-path change entirely. run: | apt-get update -qq apt-get install -y --no-install-recommends \ @@ -50,16 +57,14 @@ jobs: # exactly the kind of drift the SHA tagging is supposed to prevent. clean: true - - name: Assert the checkout really is the triggering commit - # Cheap, and it converts "the runner shipped stale files" from a - # silent deploy into a failed job. - run: | - head=$(git rev-parse HEAD) - echo "checkout HEAD : $head" - echo "GITHUB_SHA : $GITHUB_SHA" - test "$head" = "$GITHUB_SHA" || { - echo "CHECKOUT DRIFT — refusing to deploy a tree that is not $GITHUB_SHA" - exit 1; } + # NO HEAD-vs-GITHUB_SHA ASSERTION. One was added here and removed: it + # needed the git binary, whose installation broke the checkout (above), + # and it was guarding a hypothesis that turned out to be wrong — the + # frozen-source bug was a self-referential rsync in the playbook, not a + # stale runner checkout. `clean: true` covers workspace reuse, and the + # host-side content hash proves the shipped bytes landed. Adding a + # package and a code-path change to assert a third time was not worth + # destabilising a working checkout. - name: Checkout management repo (for elway) uses: actions/checkout@v4