Files
esh-pfi-infrastructure/persistent-memory.d/2026-08-23-hrafn-adopted-ci-frozen-source.md
vh b6340519bc memory: snapshot — Anaheim tunnel at 25% of circuit; selene retired; hrafn CI fixed
Session captured for a context reset. Six new detail entries.

THE OPEN ITEM: Anaheim's IPsec tunnel delivers ~550 Mbit/s aggregate against a
circuit measured at 2,153 Mbit/s. Not WireGuard (it is IPsec on ana-gw), not
CPU (idle), not crypto exhaustion (NPU-offloaded), not the fibre. Both tunnels
negotiate aes256-sha1; AES-GCM proposed. Operator signalled authorization;
execution pending, untracked by operator choice.

Also recorded: selene retired after losing a head-to-head on its own job with
chat-judge moved to gen and the model name left to 404; the 7-alias collision
on the gen seat that makes cross-alias corroboration an echo; hrafn adopted and
its CI found to have been reporting green while deploying nothing for its whole
life; all three Worldtree instances de-armed from a 69-day-stale :latest and
the Matrix homeserver re-plumbed to personal; every secret-bearing .env on
ana-docker tightened to 0600; the pfi org closing the repo-creation half of the
credential-migration directive; booth kept-board deletion and link pruning.

Two entries under Tried and abandoned: the CI checkout assertion that broke the
pipeline twice and was removed, and my proposal to alias a retired model name
at a different model, which the operator correctly overruled.

Index 271 -> 282 lines, under the 300 cap, so no archival fired.
2026-08-23 13:35:48 -07:00

3.1 KiB

[2026-08-23] hrafn adopted; its CI deploy reported green while deploying nothing

hrafn — genuine-Chromium browser-fetch behind a REST API, for bot-gated sites (Reddit first). Built by nevermore-claude on ana-docker, handed to infra-ops for uptime ownership. Internal-only on traefik-net, no host port; consumers reach http://hrafn:8080. Canonical at stacks/hrafn/.

Intake found a live credential exposure

/opt/docker/compose/hrafn/.env was mode 0644 with a live 57-char bearer token — verified as real exposure by reading it as nobody on a box with four interactive accounts. Tightened to 0600. That triggered the wider sweep (see 2026-08-23-ana-docker-env-perms-sweep).

The CI defect — the one worth remembering

I authored the deploy (elway playbook + gitea workflow) to replace a hand-rsync, tagging the image with the commit SHA for provenance. nevermore-claude later found v1.0.0 deploying "green" while the host still served 0.1.0.

Root cause was mine and nastier than either hypothesis. The staging dir was $compose_dir/.stageinside the rsync target. So rsync -a --delete $compose_dir/.stage/ $compose_dir/ deleted .stage from the destination (absent from the source listing) during the transfer, destroying its own source mid-copy. Reproduced exactly:

before:  app.py="OLD"   leftover.txt   .stage/app.py="NEW"
after:   app.py="OLD"   leftover.txt GONE, .stage GONE

Deletion succeeded, the copy silently did not, rsync exited 0. So the directory looked converged while host source stayed frozen at the first manual rsync — and because the build's COPY inputs never changed, Docker full-cache-hit and every SHA tag aliased one image. The provenance the tagging existed to provide was false for the pipeline's entire life.

The real failure is the verification. The verify steps asserted the marker, container health, and a 200 from /readyz — all of which pass against a completely frozen host. None measured content. A deploy that reports success without asserting the bytes changed is verifying an uptime, not a deploy.

Fixes

  • stage at /tmp/hrafn-deploy-stage, outside the target
  • CI computes context_sha256 over the shipped file list; the playbook recomputes it on the host after the converge and fails on mismatch
  • compare the running container's src/**/*.py against the host's, so a SHA tag cannot name layers the image lacks
  • compare *.py onlypip install . generates src/*.egg-info/* inside the image and __pycache__ appears at runtime, so a naive find src -type f compare false-fails on every healthy deploy. Verified against a known-good container before shipping (12 host files, 18 in container, 0 content differences).
  • declined --no-cache: a cache hit is correct when the context is genuinely unchanged; assert the property rather than brute-force it.

Access

Operator granted claude-bot write on vh/hrafn, so infra-ops maintains the pipeline it owns instead of routing patches through the repo holder. vh/hrafn is canonical; stacks/hrafn/ci/ is a verified mirror.

Commits b6924de, b001d0c, 11b9d18, b38c369, 9642952.