Skip to main content
Loom Core docs

Renovate And Image-Build Gate Guardrails

Repo-local guardrails for handling Renovate merge requests and image-build gate failures without changing external systems. Use this document when a Renovate branch, build:image:* job, or Mills ci_watch escalation needs a deterministic operator decision.

This document complements docs/ci-triage-runbook.md and docs/ci-incident-triage.md. Those runbooks classify repeated CI incidents; this one defines the required branch checks, retry rules, and closeout notes for the two CI families that most often look external while still needing repo-local evidence.

Operating Rule

Do not retry, rebase, merge, or regenerate a Renovate or image-build branch until the first failure has been classified as one of:

  • repo-fix: the branch diff caused the failure and needs a repository change.
  • ci-config-fix: loom-core CI configuration or guardrail logic caused the failure.
  • external-dependency-incident: GitLab, registry, package proxy, checksum, DNS, TLS, runner, or Kubernetes infrastructure caused the failure.
  • flake-retried: one bounded retry passed and no matching recurrence exists.
  • operator-escalated: Mills or Renovate automation needs human disposition before another attempt.

The first failed job is authoritative. Later skipped, blocked, or downstream jobs are follow-on signals unless they contain the first meaningful error.

Required Preflight

Run these checks before changing pipeline state:

git status --short --branch
git diff --name-only origin/main...HEAD
git log --oneline origin/main..HEAD

For Mills-generated work, resolve the live plan from the shared store and compare the slice files with the branch diff:

agent_plan_get{plan_id:"<plan-id>"}

For local repository checks, use the narrowest guardrail that matches the branch first:

bash scripts/ci/check_docs_guardrails.sh
bash scripts/ci/check_docs_guardrails_test.sh
make ci-contracts
go test ./...

If the branch has no commits, the MR is empty, the plan slice does not match the diff, or required docs are missing for code-facing changes, stop and fix branch hygiene before retrying CI.

Renovate Gate Handling

Renovate branches are repository-owned until evidence proves the package infrastructure failed. A dependency update that changes compile behavior, generated metadata, lockfiles, module graph resolution, or tests is a repo-fix even when Renovate created the branch.

Classify a Renovate failure with this decision table:

SignalClassificationOperator action
Compile, lint, contract, docs guardrail, or deterministic test failure points at the updated dependency or changed lockfilerepo-fixPatch the branch, pin or adjust the update, add tests when behavior changed, then rerun the failed job
go mod, package download, checksum, tarball, or package metadata returns repeatable 404 for the target version onlyrepo-fix or dependency policy issueConfirm the version exists upstream; if invalid, close/reconfigure the update rather than retrying
Registry, package proxy, checksum DB, DNS, TLS, or GitLab API returns 429/5xx or connection failures across unrelated Renovate branchesexternal-dependency-incidentRecord the shared incident and retry only after recovery or bounded backoff
Renovate cannot update the branch because GitLab rejects pushes, API calls, or MR metadata updatesexternal-dependency-incident if shared, otherwise operator-escalatedCapture GitLab response and stop automation until auth/rate-limit state is known
One timeout or connection reset passes on a single clean retry and does not recur elsewhereflake-retriedRecord the retry job ID and close the loop

Required Renovate evidence:

  • Package name, manager, current version, target version, and Renovate branch.
  • Changed lockfile or module metadata paths.
  • First failing job, job ID, and first meaningful error line.
  • Registry, checksum, or package-proxy response when downloads fail.
  • Whether the same signature appears on unrelated Renovate branches or main.
  • Retry job ID and result, if a single retry was allowed.

Do not close a Renovate failure as external solely because Renovate authored the MR. Do not keep retrying a dependency update that deterministically breaks repository tests; either adapt the repo, constrain the update, or close the MR with the evidence note.

Image-Build Gate Handling

Image-build gates publish deployable images for loom-core, custom-server, and loom-mills-operator. The loom-core and custom-server jobs are gated by changed image inputs so unrelated default-branch merges do not roll shared MCP server fleets.

Current image jobs:

JobDockerfileBuild commandInput gate
build:image:loom-coreDockerfilescripts/ci/buildkit-build.sh mcp/loom-core Dockerfile loom-core.gitlab-ci.yml, .dockerignore, Dockerfile, build script, go.mod, go.sum, cmd/**, internal/**, pkg/**
build:image:custom-serverDockerfile.custom-serverscripts/ci/buildkit-build.sh "$CUSTOM_SERVER_IMAGE_REPO" Dockerfile.custom-server custom-server.gitlab-ci.yml, .dockerignore, Dockerfile.custom-server, build script, go.mod, go.sum, cmd/**, internal/**, pkg/**
build:image:loom-mills-operatorDockerfile.loom-mills-operatorscripts/ci/buildkit-build.sh mcp/loom-mills-operator Dockerfile.loom-mills-operator loom-mills-operatorDefault branch always builds; feature branches build for operator Dockerfile, build script, module files, cmd/loom-mills-operator/**, and pkg/mills/**

Classify an image-build failure with this decision table:

SignalClassificationOperator action
Dockerfile command, Go build, frontend build, asset generation, .dockerignore, build script, or image tag logic fails inside changed inputsrepo-fix or ci-config-fixPatch the repository and rerun the image job
Job fails before checkout or before scripts/ci/buildkit-build.sh startsRunner or cluster incidentCapture runner/pod evidence and escalate to the runner owner
Base image pull, BuildKit startup, registry login, layer push, DNS, TLS, or registry API returns shared 429/5xx/auth errorsexternal-dependency-incidentRecord registry/runner evidence and retry only after recovery or bounded backoff
Image job is skipped on a branch that changed deployable inputsci-config-fixPatch .gitlab-ci.yml rules and verify with a branch diff that exercises the gate
Image job runs on a branch that changed only docs or unrelated filesci-config-fixTighten rules:changes to prevent unnecessary image publication and fleet rolls

Required image-build evidence:

  • Job name, image repository, tag, Dockerfile path, and commit SHA.
  • Branch diff against origin/main, including whether gated inputs changed.
  • First failing log line and the 50 lines before it.
  • BuildKit runner or pod identity, Kubernetes events if available, and runner system-failure message when the job does not reach user scripts.
  • Base-image source, registry endpoint, and push/pull response when layer operations fail.
  • Whether the same signature appears on unrelated branches or recent main.

Do not manually force an image publish to work around an unclassified failure. For shared images, an unnecessary default-branch publish can roll many MCP server pods; fix the gate or wait for dependency recovery instead.

Retry Rules

Allowed retries are intentionally narrow:

  • Repository and CI configuration failures require a new commit before retry.
  • Renovate download, registry, and image publication failures may be retried once only after evidence shows the failure is transient or the dependency has recovered.
  • Runner or cluster failures may be retried after the runner owner confirms a healthy pool or the failing runner is replaced.
  • Mills ci_watch retries require a non-empty pushed branch, matching live plan slice, and a known-good dependency state.
  • A second failure with the same signature ends the retry loop and becomes an incident or operator escalation.

Every retry note must include the original job ID, retry job ID, classification, and why the retry condition was satisfied.

Closeout Note Template

Use this shape in the MR discussion, Mills escalation note, or incident record:

Disposition: <repo-fix|ci-config-fix|external-dependency-incident|flake-retried|operator-escalated>
Family: <renovate|image-build>
First failing job: <job name> <job id>
First error: <one line>
Branch diff: <summary or git diff --stat>
Evidence: <registry/package/runner/GitLab/Kubernetes links or command output>
Retry: <not retried|retry job id + result>
Next action: <commit, wait for dependency recovery, close MR, or escalate>

For repo-owned fixes, include the commit SHA that changed loom-core. For external dependency incidents, include the dependency owner or incident link and avoid creating additional repo backlog unless it improves classification, retry behavior, telemetry, configuration, or this documentation.

Renovate And Image-Build Gate Guardrails | Loom Core docs