---
name: a-pr-open-is-a-ci-battery-on-both-runner-boxes
description: Opening a PR fires thin CI onto both self-hosted runner boxes at once; beside a builder battery it OOM-kills the kitsubito runner (15 GB) and the service does not self-recover — open PRs only when both boxes are free
metadata: 
  node_type: memory
  type: feedback
  originSessionId: 7024face-6a64-4294-8609-8fafebc8e4df
  modified: 2026-09-07T02:26:16.430Z
---

**Measured 2026-09-07 (W1 #249, PR #196 at 8d980fdf):** I told todlando "open the PR at the respin tip" and he did at 01:40Z, while his batteries ran on BOTH boxes. Thin CI run 34073766394 landed on both self-hosted runners within seconds: the Windows unit job died on "There is not enough space on the disk" (this box was at 0.5 GB free from his test-profile build), and on kitsubito the CI job's `rust-lld` was OOM-killed inside the runner service's cgroup (15 GB RAM, three OOM kills 01:48Z, journal `Killed process … (rust-lld)`, memcg = the runner unit) — the unit went `failed`, runsvc's "re-launch in 5 seconds" did NOT bring it back, and every later Linux CI job would have queued forever. Both reds carried ZERO test signal (0 Summary, 0 panics) and read as "the head is red" from the PR page.

**Why:** the "one battery per box" rule is about load on the runner boxes, and a PR open IS a battery on both of them — the golden boxes are the same machines the builders and I batter. A cold `nextest` battery plus a CI unit job's link step exceeds kitsubito's memory; the runner service is the process the kernel picks.

**How to apply:**
- A PR is opened only when BOTH boxes are free of batteries (builder's and mine), and the CI rerun after a fix goes in the box order like any other battery, never beside one. Say this in the dispatch, not just "open at the tip".
- After any CI job that ends "runner has received a shutdown signal" or a kitsubito red with no Summary: `ssh reavus@kitsubito systemctl is-active actions.runner.BigscreenVR-spt-bs-core.kitsubito.service` and read `journalctl -u` — an OOM-killed unit stays `failed`; `sudo systemctl reset-failed && start` (passwordless sudo works for reavus) restores it; confirm `Runner.Listener` by pgrep.
- Pull job logs from `gh api repos/O/R/actions/jobs/<id>/logs` and grep `Summary \[` / `panicked at` / `not enough space` / `shutdown signal` BEFORE reading any red as the head's.
- INFRA-REGISTER candidate: the kitsubito runner has no memory headroom for a concurrent battery; either a `MemoryMax`/nice for batteries or a CI concurrency gate keyed on the lane lock.

See [[dispatch-window-legs-must-name-the-golden-box]], [[prefire-check-reads-the-disk-floor]], [[in-flight-run-logs-are-gated-read-steps-and-annotations]], [[failed-job-is-not-a-test-victim]].
