Root cause category: CI/CD design — branch protection contexts on a release-train branch
Module: repo plumbing (CI), PR Verify.yml
The Krill agent fleet is moving to a release-train model: agents merge to a
long-lived agents branch with automerge-on-green, and Ben merges a permanent
agents → main integration PR to ship (see kraken docs/agent-workflow.md).
Automerge needs a stable “green” contract to gate on. krill’s PR Verify.yml
has a single heavy verify (Build & lint) job on the self-hosted kraken runner;
marking that job’s context directly as required couples branch protection to an
implementation detail (rename the job and protection silently never-gates).
There was also no CI enforcement of the long-standing “every change needs a
docs/lessons/ entry” rule — it was honored by convention only.
required-checks-passed aggregator (always(), needs: [verify,
lessons-check]) that fails on failure/cancelled and tolerates skipped.
This single context is the only required check.lessons-check job that passes if the PR adds/modifies a
docs/lessons/*.md file or the PR body contains no-lesson-needed. The
permanent integration PR (head.ref == agents) is exempt — it is an aggregate
of already-lessoned PRs, and the aggregator tolerates the skip.[main, agents] so PRs to agents get CI.kraken/scripts/github/branch-protection.json) requires
exactly required-checks-passed + lessons-check on agents.always() aggregator, never on an individual
build job — the aggregator is the contract; jobs are implementation detail.name:) in lockstep with the
contexts array in branch-protection.json; a mismatch silently never-gates.