Skip to content

skills: run lanes as a pipeline — push and move on, land PRs on a cadence - #612

Merged
Yaraslaut merged 1 commit into
masterfrom
skills/pipeline-lanes-no-ci-wait
Sep 20, 2026
Merged

Yaraslaut merged 1 commit into
masterfrom
skills/pipeline-lanes-no-ci-wait

Conversation

@Yaraslaut

Copy link
Copy Markdown
Member

Restructures running-issue-lanes from "one lane, one PR, wait for green" into a pipeline: lanes produce PRs continuously and a scheduled sweep drains them.

Documentation only — no code, no workflow, no behaviour change.

Lanes stop waiting for CI (Step 4)

A lane's job now ends when it has pushed and opened the PR. Previously lanes sat watching their own CI, which at 26–74 minutes a cycle is a worker doing nothing while tickets queue behind it, and caps throughput at about one batch per lane per cycle.

The ceiling rises to five concurrent lanes, but the section is explicit that the real bound is disjointness, not the number: five batches only pay off on five disjoint file trees, and a lane on a tree another lane already holds is worse than an idle slot — it produces a PR that invalidates the other.

The hard-bounds block is unchanged and now says outright that it does not relax as the count rises. Six lanes dispatched without it became 16 agent tasks and ~318 background bash tasks; four dispatched with it stayed at four. The count was never what went wrong.

Step 7 becomes the landing sweep

Walks every open PR each pass and sorts it green / red / pending / fork.

Red now has an owner. Under the old model the lane that wrote a PR was still around to fix it; under this one it has handed back, so a red PR belonged to nobody and would sit red indefinitely. The sweep takes it, and is told to read the failing job's log first — a leg that stops within seconds of its siblings is a cancellation rather than a defect, and purged logs mean re-running is the only thing that teaches anything. Both of those cost real time this week before being recognised.

The staleness rule is narrowed

From "rebase if the base moved" to "rebase if something material moved".

This matters much more in a queue, where most open PRs are stale most of the time — the old reading costs one full CI cycle per PR per sweep. The test is now:

  • a gate moved (.github/workflows/, scripts/, CMakePresets.json) → rebase; its CI was judged by rules that no longer exist
  • a source file it touches, or a header those include, moved → rebase; the combination was never tested
  • only unrelated or reporting-only lines → merge; re-running cannot change the verdict

Applied by hand twice already, and it separated the two cases cleanly: #607 merged without a rebase (the delta was a message(STATUS …) string plus a link line on a target no CI job builds), while #609 was rebased (the delta carried a core header and a coverage-allowlist input). The sweep must state which of the three it concluded, and why.

Step 0 stops routing to one next step

A pass now drains, triages and refills every time. A sweep that lands three PRs and dispatches nothing has emptied the pipeline; one that dispatches without draining lets PRs pile up. Both halves, every pass.

Red flags and rationalizations

Added: a lane still running because it is watching its own CI; a sweep that merges but dispatches nothing; reflexive rebasing of every stale PR; and leaving a red PR for a lane that has already gone.

What is not claimed

This is a process document and nothing in it is measured by a test. The throughput argument rests on the CI cycle times quoted (26–74 min, taken from gh run list over recent runs) and on the rebase cascade being real — #609 cost two cycles for one ticket because two other PRs landed while it sat. Whether five lanes is better than three is not established; it is a ceiling with a stated condition, not a recommendation to run five.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GS5K2vqZtC4xbRiGJHT7jH

Lanes were waiting for their own CI before handing back. At 26-74 minutes
a cycle that is a worker doing nothing while tickets queue behind it, and
it caps throughput at roughly one batch per lane per cycle.

A lane's job now ends when it has pushed and opened a PR. Step 4 says so
explicitly and raises the ceiling to five concurrent lanes, with the real
bound stated as disjointness rather than the number: five batches only pay
off on five disjoint file trees, and a lane on a tree another lane already
holds is worse than an idle slot. The hard bounds are unchanged and do not
relax as the count rises -- six lanes without them became 16 agent tasks
and ~318 background bash tasks, so the count was never what went wrong.

Step 7 becomes the other half of the pipeline: a scheduled sweep that
walks every open PR and sorts it green / red / pending / fork. Red now has
an owner, which it did not before -- the lane that wrote it has handed
back, so the sweep diagnoses it, reading the failing log first because a
leg that stops within seconds of its siblings is a cancellation rather
than a defect.

The staleness rule is narrowed from "rebase if the base moved" to "rebase
if something material moved". In a queue most open PRs are stale most of
the time, so the old reading costs one full cycle per PR per sweep. A gate
change or a change to a file the PR touches still forces a rebase; an
unrelated or reporting-only delta does not, because re-running cannot
change the verdict.

Step 0 stops routing to a single next step: a pass drains, triages and
refills every time, since skipping either half stalls it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GS5K2vqZtC4xbRiGJHT7jH
@codecov

codecov Bot commented Sep 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant