Two runs of the full build+deploy fired for every push, and the second died:
nothing to commit, working tree clean
❌ Failure - Main Update infra repo
The deploy was fine both times — the second run had nothing left to do. The
cause is the pair of triggers meeting: ci.yml ran on `push` to main AND on a
`v*` tag, and cd.yml keys off "CI succeeded", so `git push origin main` followed
by `git push origin refs/tags/vX` produced two CI runs for one sha and two
deploys behind them. The tag run carries the same github.sha, so it rebuilt the
same image and then found the infra manifest already pointing at it.
Nothing consumed the tag-triggered run: there is no release workflow, and cd.yml
reads github.sha rather than the tag. Dropping `tags:` removes the duplicate
build outright.
The idempotency guard stays anyway, because a manual re-run has the same shape
and should not ring the CI-red alarm for work that is already done — infra#366
turns a red run into a tracked issue, so a false red costs a real triage.
Closes#118
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
On 2026-08-25 a deploy job ran with an empty IMAGE_TAG, wrote
`image: localhost:5000/gitea-mcp:` into the infra repo and pushed it.
That is invalid YAML, so Flux failed the ENTIRE apps Kustomization --
every app stopped reconciling for about an hour, including three
unrelated deploys queued behind it.
This job's existing check could not catch it. It greps for
`image: <repo>:${IMAGE_TAG}` after the sed, and with IMAGE_TAG empty that
pattern matches the corrupted line itself, so the verification passes
because of the bug rather than despite it.
Asserting the input up front is the fix: an empty tag now fails the job
before anything is written, let alone committed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011PL5XcG68SvQqz3vGVbWbf
cd.yml's own $HOME (/data) is a PVC that persists across job runs on
this runner. The previous fix (cb9c251) appended the corrected
HostName to ~/.ssh/config, but a stale 127.0.0.1:30022 entry from an
earlier failed run was already there — ssh_config is first-match-wins,
so the stale entry silently shadowed the fix and the very next run
failed identically. Cleaned the persisted stale entry on the runner
directly; this commit removes the append entirely so the step no
longer depends on file state surviving (or not surviving) between
runs — CLI -o overrides always win. Verified end-to-end against the
real infra repo from inside the runner pod (git ls-remote, correctly
reached gitea and got a clean auth rejection, not a connection error).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Roq1ajWKR5f1hG5Df9wC6A
act_runner moved from koala's bare host network into a k3s pod
(2026-07-26); loopback inside that pod's own network namespace never
reaches the host, so the git.d-ma.be SSH override (used to push the
infra repo update) failed with "Connection refused". Verified
TCP+SSH-handshake reachability to gitea-ssh-nodeport.gitea.svc.cluster.local:22
from inside the actual runner pod before committing this.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Roq1ajWKR5f1hG5Df9wC6A
Consolidate to the hyperguild-alone harness that ran the infra#170 loop-1
experiment (cmd/hyperguild + brain-mcp; routing/injection machinery off).
Verified cmd/hyperguild has zero transitive dep on internal/routing or
cmd/routing's packages (imports only internal/tier). Removed the routing
path, which is dormant from the live session (.mcp.json wires only brain-mcp)
and entangled with the survivorship-biased pass-rate router (infra#174).
Iceboxed (recoverable at tag icebox/cmd-routing-2026-07-01 / branch
icebox/cmd-routing, commit 00e5f62):
- cmd/routing/, internal/routing/
- internal/skills/{review,debug,retrospective,trainer,project}/
(each imported solely by cmd/routing — verified)
- Dockerfile.routing
- cd.yml: routing image build + infra bump + Flux-wait/rollout-verify
(ingestion build/deploy unchanged)
Kept: cmd/hyperguild, ingestion/, internal/tier (used by cmd/hyperguild +
skills/org), internal/skills/{brain,org,sessionlog} (per #75; already orphaned).
Regression: root module 21→14 pkgs (−7 = exactly the removed set, no other
breakage); ingestion 24/24 unchanged. See ICEBOX.md. Refs #75, infra#170, #174.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The gitea.d-ma.be→git.d-ma.be rename moved the infra deployment manifests, but
cd.yml still sed-patched 'gitea.d-ma.be/mathias/ingestion:' — which no longer
matches, so the patch produced no change and 'git commit' failed under set -e,
wedging all deploys (image stuck at e8dbcf6). Repoint the registry image refs,
the infra-patch sed patterns, and the rollout-verify EXPECTED values to
git.d-ma.be (same registry backend). SSH alias + INFRA_REPO left as-is.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Plan 7 (2026-05-12) retired the supervisor pod, deleted cmd/supervisor/
and the root Dockerfile, but cd.yml still tried to:
- buildctl a supervisor image using the (non-existent) root Dockerfile
- sed gitea.d-ma.be/mathias/supervisor: in k3s/apps/supervisor/deployment.yaml
(also non-existent — k3s/apps/supervisor/ only ships ingestion-* files now)
- wait for and rollout-verify a supervisor Deployment that no longer exists
Result: every CD run since the retirement has been failing at 'Build and push
supervisor image', leaving ingestion + routing un-deployed despite the binaries
being built. The routing pod was last deployed at sha 189ff89c (weeks stale).
This commit:
- Removes the supervisor build step and supervisor sed/git add lines.
- Adds 'Wait for Flux to apply new routing image' + 'Verify routing rollout'
steps that mirror the ingestion equivalents, so failures land loudly rather
than 5 min later when something tries to call the new tool.
- Updates the chore(deploy) commit message to 'ingestion+routing' to match
reality.
Unblocks deployment of feat: project_create (#10).
Aligns hyperguild's cd.yml with the cobalt-dingo reference pattern:
- Add environment: staging to the deploy job
- Add Flux reconcile trigger after infra repo push
- Add polling wait for supervisor and ingestion image tags to propagate
- Add rollout status verification for both deployments with failure
diagnostics (pod status, events, describe)
Ingestion server is a pure-Go HTTP binary — alpine runtime, no node.js.
CD now builds both supervisor and ingestion images on every push,
updates both deployment.yaml files in the infra repo.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
gitea.d-ma.be:30022 is refused externally — the NodePort is only
reachable on koala locally. Use HostName 127.0.0.1 in SSH config
so git@gitea.d-ma.be connects to localhost:30022 instead.
Unindented heredoc content inside a YAML literal block breaks parsing.
Gitea silently drops workflows with YAML errors, causing the CD job
to never trigger.
gitea.d-ma.be port 22 is rejected (NPM only proxies HTTP/HTTPS).
The runner runs on koala where the Gitea SSH NodePort 30022 is
reachable locally. Use SSH config override instead of ssh-keyscan.