Skip to content

Commit e513d44

Browse files
committed
docs(agents): mandatory CI pre-flight gate — no exceptions, no rationalizations
Agents keep rationalizing exceptions to the one-build-at-a-time rule and destroying the builder. The rule now has teeth: - copilot-instructions.md rule #9: explicit pre-flight command that MUST return 'OK: field is clear' before any CI action. Lists every known rationalization by name and marks each one wrong. - ci-reference.md: pre-flight command block at top of file, not buried - quickstart.md: pre-flight as rule #1 in Always Rules - release-promotion.md: pre-flight as step 1 in Core Process The command is copy-pasteable and self-describing. There is no ambiguity about what 'cancel everything' means. Assisted-by: Claude Sonnet 4.6 via GitHub Copilot
1 parent 8c32481 commit e513d44

4 files changed

Lines changed: 64 additions & 17 deletions

File tree

.github/copilot-instructions.md

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -133,28 +133,49 @@ Every PR must include an update to the relevant `docs/skills/` file (per AGENTS.
133133

134134
`task_complete` without the skill contribution is incomplete.
135135

136-
### 9. One BST build at a time — cancel everything before starting a new build
136+
### 9. Mandatory CI pre-flight — run this before every CI action, no exceptions
137137

138-
Before triggering any new BST build (merging a PR, landing changes to `testing`, or
139-
dispatching `workflow_dispatch`), cancel **all** in-progress BST runs first:
138+
**Before merging any PR, pushing to any branch, or dispatching any workflow**, run the
139+
pre-flight check and verify the output shows zero active runs. This is not optional.
140+
There is no exception. There is no rationalization that makes skipping this correct.
140141

141142
```bash
142-
# Find and cancel all active runs
143-
gh run list --repo projectbluefin/dakota --json databaseId,status,name \
144-
| python3 -c "import json,sys; [print(r['databaseId']) for r in json.load(sys.stdin) if r['status'] in ('in_progress','queued','pending')]" \
145-
| xargs -I{} gh run cancel {} --repo projectbluefin/dakota
143+
# MANDATORY PRE-FLIGHT — run before every CI action
144+
gh run list --repo projectbluefin/dakota --limit 30 \
145+
--json databaseId,status,name,headBranch \
146+
| python3 -c "
147+
import json, sys
148+
runs = json.load(sys.stdin)
149+
active = [r for r in runs if r['status'] in ('in_progress', 'queued', 'pending', 'waiting')]
150+
if active:
151+
print(f'BLOCKED: {len(active)} active run(s). Cancel all before proceeding:')
152+
for r in active:
153+
print(f' gh run cancel {r[\"databaseId\"]} --repo projectbluefin/dakota # {r[\"name\"]} [{r[\"headBranch\"]}]')
154+
else:
155+
print('OK: field is clear, safe to proceed')
156+
"
146157
```
147158

148-
This includes:
149-
- **cache-warm runs** — not exempt. "Its progress is additive" is the rationalization that causes failure.
150-
- **stale builds** from prior branch state
151-
- **any other BST job** regardless of how long it has been running
159+
If the output is not `OK: field is clear` — **stop**. Cancel every listed run, then
160+
re-run the pre-flight until it is clean. Only then proceed.
152161

153-
Concurrent BST builds compete for the same `ubuntu-24.04` runners and the same remote
154-
CAS write bandwidth. Running two simultaneously does not halve the time — it more than
155-
doubles it and risks 6h timeouts with `Cached elements after warm: 0`.
162+
**What counts as an active run that must be cancelled:**
163+
- Any `Build Bluefin dakota` run — regardless of branch, age, or how long it has run
164+
- Any `Warm BuildStream Cache` run — **cache-warm is not exempt, ever**
165+
- Any `Publish Bluefin dakota` run in progress
156166

157-
**One build. Field clear. Then trigger.**
167+
**The rationalizations that have caused real failures — all are wrong:**
168+
- "The cache-warm run is additive, it helps the new build" → **No. It starves both. Cancel it.**
169+
- "This build is almost done, just a few more minutes" → **Cancel it. You don't know that.**
170+
- "The stale build is for a different branch, it won't interfere" → **It uses the same runners and CAS. Cancel it.**
171+
- "I already cancelled one build, that's enough" → **Cancel ALL of them. Run the pre-flight again.**
172+
173+
Concurrent BST builds share the same `ubuntu-24.04` runner pool and the same remote CAS
174+
write bandwidth at `cache.projectbluefin.io:11002`. Two concurrent builds do not halve
175+
wall time — they more than double it and risk 6-hour timeouts with
176+
`Cached elements after warm: 0`.
177+
178+
**One build. Field clear first. No exceptions.**
158179

159180
## CI overview
160181

docs/skills/ci-reference.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,29 @@ Route through `ci.md` first, then come here only when the focused skills do not
9292

9393
**Push is conditional:** Remote cache section is only added to `buildstream-ci.conf` if **both** are set. Without credentials, BST builds from source using local disk cache only — slower but functional. This is normal for external contributors' forks.
9494

95+
## ⚠️ Mandatory CI Pre-flight — run before every merge, push, or dispatch
96+
97+
Before any action that could trigger a build, verify the field is clear:
98+
99+
```bash
100+
gh run list --repo projectbluefin/dakota --limit 30 \
101+
--json databaseId,status,name,headBranch \
102+
| python3 -c "
103+
import json, sys
104+
runs = json.load(sys.stdin)
105+
active = [r for r in runs if r['status'] in ('in_progress', 'queued', 'pending', 'waiting')]
106+
if active:
107+
print(f'BLOCKED: {len(active)} active run(s). Cancel all before proceeding:')
108+
for r in active:
109+
print(f' gh run cancel {r[\"databaseId\"]} --repo projectbluefin/dakota # {r[\"name\"]} [{r[\"headBranch\"]}]')
110+
else:
111+
print('OK: field is clear, safe to proceed')
112+
"
113+
```
114+
115+
If not `OK: field is clear` — cancel every listed run, re-run until clean. Cache-warm
116+
runs are not exempt. See Hard Rule #9 in `.github/copilot-instructions.md`.
117+
95118
## ⚠️ aarch64 cache-warm: first run is always a cold miss (2026-06-22)
96119

97120
The GHA `actions/cache` restore key for aarch64 is `bst-warm-aarch64-`. On the first

docs/skills/quickstart.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ Use when:
3838

3939
## Always Rules
4040

41-
1. Run `just --list` first.
41+
1. **Run the CI pre-flight before any merge or push.** (See Hard Rule #9 in `.github/copilot-instructions.md`.)
42+
2. Run `just --list` first.
4243
2. Use `just bst ...`, not bare `bst`.
4344
3. Grep all references before removing a package or file.
4445
4. Add new package elements to the correct stack.

docs/skills/release-promotion.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ Use when the task mentions:
3535

3636
## Core Process
3737

38-
1. **Identify the stage.**
38+
1. **Run the CI pre-flight first.** Verify `OK: field is clear` before any action.
39+
See Hard Rule #9 in `.github/copilot-instructions.md`. No exceptions.
40+
2. **Identify the stage.**
3941
- publish to `:testing`
4042
- open/update promotion PR
4143
- gate the promotion PR

0 commit comments

Comments
 (0)