core/docs/ci-optimization.md
Shay 82f9b021fb
Some checks failed
smoke / smoke (-m "not quarantine") (pull_request) Failing after 53s
lane-shas / verify pinned lane SHAs (pull_request) Failing after 32m58s
ci: fast-lane main gate, nightly full suite, skip-safe lane-shas
Unblock the single Act runner: post-merge full-pytest runs the fast
marker (not quarantine and not slow); full non-quarantine suite moves
to nightly + workflow_dispatch. lane-shas uses job-level path detection
so docs-only PRs skip green without hanging required checks. Sync
smoke/conftest/docs CI contracts to the PR/main/nightly policy.
2026-07-14 21:02:43 -07:00

77 lines
3.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CI optimization — runner bottleneck and lane policy
Companion to [testing-lanes.md](./testing-lanes.md) (SSoT for markers and
workflow → lane mapping). This note records **why** the multi-lane CI split
exists and what capacity still limits PR queue time.
## The bottleneck
A single self-hosted Act runner (≈2 vCPU / limited RAM) serializes all workflows
that target `ubuntu-latest` for this repo. When post-merge CI ran the **full**
non-quarantine suite (`-m "not quarantine"`) with `-n 2`, the slow registry
dominated wall-clock:
- Module fixture floor: `test_inner_loop_phase2` ≈16 min setup alone
- ~912 tests classified `slow` in `conftest.py` (including the register matrix)
- Thrashing under oversubscription can stretch the job toward **12 hours**
While that job holds the runner, PR gates (`smoke`, `lane-shas`) sit in
**Waiting**. That is a queue problem first, a test-count problem second.
## What we changed (in-repo)
| Change | Effect |
|---|---|
| `full-pytest.yml` → fast marker | Main push runs `not quarantine and not slow`; frees the runner much sooner after merge |
| `nightly-full-pytest.yml` | Full suite (`not quarantine`) daily at 02:00 UTC + `workflow_dispatch`; timeout 120 min |
| `lane-shas.yml` job-level path skip | PR pin verify runs only when pin-relevant paths change; job still green when skipped (no required-check hang) |
| Contract comments | `smoke.yml`, `conftest.py`, `testing-lanes.md` match the real PR / main / nightly split |
Workflow **id** `full-pytest` is kept on purpose so Forgejo history / required-check
names do not break; the job display name is `fast pytest (...)`.
## What is out of band (ops, not git)
Host cgroup limits, hung-container cleanup, and adding a second runner are
**VM/ops** actions. They are not encoded in this repository. Document them in
ops runbooks when you change the host; do not treat this file as a substitute.
## Expected feedback loop after this change
| Stage | Typical hold |
|---|---|
| Local | Targeted tests; `make test-fast` before push |
| PR | `smoke` (+ `lane-shas` when pin-relevant paths change) |
| Main | Fast `full-pytest` + always-on `lane-shas` |
| Nightly | Full soak including slow registry |
This is roughly **hours of runner hold after merge → tens of minutes** on the
fast lane for the same host class — not infinite parallel capacity. Multiple
open PRs still queue on one runner.
## Capacity still required
1. **Second Act runner or larger VM** — only real fix for concurrent PR + main
execution.
2. **xdist hermeticity** — see follow-ups in `testing-lanes.md` before raising
`-n` further.
3. **Warm-runtime fixture** — long tail of `ChatRuntime` construction in the
fast lane.
4. **Nightly failure signal** — wire Forgejo notification / issue on red
`nightly-full-pytest` so ≤24h slow-break debt is not silent.
5. **Optional path-triggered slow job** — if main must catch soak breaks same-day
without nightly wait, add a non-blocking or path-filtered slow workflow later.
## Validation
```bash
# Local parity with main CI
make test-fast
# Local parity with nightly
make test-full
# Lane pins (same as lane-shas job body)
uv run python scripts/verify_lane_shas.py
uv run python scripts/generate_claims.py --check
```