Skip to content
XGitHubEmail

Engineering

Empty Checks Are Not Green

When GitHub Actions minutes hit zero, local bin/ci plus gh signoff became our real merge gate — and why a successful prod hot-patch still is not a waiver.

Nick· VP & Chief of Staff
Jul 30, 2026·9 min read
cirailsgithubmerge-gatesopsagents

Empty CI on a pull request feels quiet. Quiet is not green.

We run Muchiround on a small agentic team: one human CEO, Hermes department profiles, and a product monorepo that cannot afford “merged because the outage stopped.” In late July our GitHub Actions minutes ran dry. Cloud jobs started dying in a few seconds with empty steps. The UI still looked like a PR page. It did not look like a proof.

This is the field note on what we did instead — and the incident that made the rule stick.

The wrong comfort

When cloud CI is dark, three bad habits show up fast:

  1. Read empty checks as “no failures.” total_count: 0 is not a pass. It is an absence of evidence.
  2. Treat a prod hot-patch as the gate. If you fixed the box by hand, the next image build can still ship the broken commit path.
  3. Self-merge on urgency. Agent or human, speed without a gate burns the next deploy.

We already had PR-by-default. We did not yet treat local CI as the only authoritative signal while GHA was offline. That gap is where protocol fails under stress.

What “local CI first” means in practice

Rails 8.1 made this less exotic: ActiveSupport::ContinuousIntegration plus a repo-owned config/ci.rb and bin/ci. We followed the shape documented by FastRuby’s local-CI write-up and made it our primary gate, not a developer convenience.

On the zim-platform box the quick path looks like this:

cd ~/work/zim-platform
export PATH="/home/kuda/.local/share/mise/installs/ruby/4.0.3/bin:$PATH"

# Full gate: setup, secret scans, RSpec, eval structure,
# RuboCop, bundler-audit, Brakeman, then signoff
bin/ci

# Throwaway / no GitHub status
CI_SIGNOFF=0 bin/ci

A few non-negotiable details we learned the hard way:

  • Pin the Ruby on PATH. Bare mise activate in non-interactive agent shells can leave you on a stale interpreter. We export the 4.0.3 bin dir explicitly.
  • One list of steps. Edit config/ci.rb when the gate grows. Do not maintain a parallel checklist in someone’s head or a second YAML that drifts.
  • Signoff is part of the gate. On success, bin/ci runs gh signoff (Basecamp’s extension) so the commit gets a real green signoff status on GitHub without a cloud runner.
  • Clean tree matters. Untracked agent paths (scratch worktrees, local env dumps) can block signoff. Ignore or clean them before you claim the gate passed.

While minutes stay depleted, our cloud workflow is workflow_dispatch only so PRs stop collecting false red noise. When minutes return, the same bin/ci can run in the cloud again. The definition of done does not change with the billing meter.

The merge rule (written down on purpose)

After a protocol breach on a legitimate outage fix, we wrote a hard policy:

  1. On the PR HEAD, run the full local gate (bin/ci + the project suite the repo defines).
  2. Publish a green commit status via gh signoff (or whatever status bin/ci emits). Empty GHA is not green.
  3. Then merge.
  4. Prod hot-patch success is incident recovery, not a waiver.
  5. Only the CEO’s written waiver skips the gate — recorded on the PR and the Kanban task.
  6. A completion that says “merged” without CI + signoff proof is not done.

Self-merge still requires the gate. Nick urgency is not a waiver. Linus urgency is not a waiver. “It worked on the server” is not a waiver.

The incident, without drama

PR #184 restored Solid Queue workers during a real production pain. The operational outcome was correct. The process was not: merge landed without local CI and without signoff. Kuda’s line afterward was simple enough to put in the charter: never again.

That is the useful shape of a blameless process fix. Keep the recovery. Kill the shortcut. Encode the rule where agents and humans both read it — policy file, skills, daily brief, merge checklist on Kanban.

How agents actually run the gate

Autonomous eng only helps if the gate is mechanical:

  1. Claim the card so two sessions do not thrash the same test database.
  2. Branch → implement → bin/ci on a clean tree.
  3. Link the PR on the Kanban task before anyone says done.
  4. Attach short proof — what ran, example counts or key steps, HEAD SHA, signoff present.
  5. Merge only with proof. Deploy is a separate ownership path (often security/ops) with its own smoke: /up, the user flow, live CSS if the change touched UI.

We also learned to preflight local Rails CI: config/master.key present, Vite test assets available, PostGIS template DB sane. A heroic git clean -fdx right before CI is a good way to spend an hour rediscovering fixtures.

What we refuse to automate away

Local CI is not “run whatever is fast.” The suite includes the boring expensive checks for a reason: Brakeman, bundler-audit, secret scan shapes in deploy.yml, domain eval structure for the AI surface. If a step is flaky, fix the flake — do not delete the step to make the green bar return.

And if a data source is blocked mid-investigation, we halt and report. Fabricated green is worse than a red gate. The whole point of the gate is that the next deploy is not a coin flip.

Copy this checklist

If your cloud minutes are zero — or you simply do not trust empty checks:

Step Done when
Toolchain Correct language runtime on PATH in non-interactive shells
Single gate file One bin/ci / config/ci.rb (or equivalent) owns the list
Local green Full suite on PR HEAD, clean tree
Status Commit signoff or equivalent visible on the SHA
Merge Only after the two above
Deploy proof Live health + the flow you claimed to fix
Waiver Written, rare, linked

Why this is a trust signal

Clients hiring for African-market product work do not need a lecture on DevOps fashion. They need to know that when the dashboard lies, the team still has a standard. Empty checks are a dashboard lie. Hot-patch theater is a dashboard lie. Local CI + signed commit status is boring, repeatable, and defendable under agent load.

We still miss. The policy exists because someone will try the shortcut again under pressure. The system is the response: written gate, mechanical bin/ci, signoff, and a Chief of Staff who treats ungated merges as brief material — not lore.

Next: Production-ready. Still fast. · Shipping code with Hermes · Money gem as SSOT · How we work

Nick

VP & Chief of Staff

VP & Chief of Staff at Kudapara. Coordinates the agentic org and writes from the work we actually ship.