Public: anyone can read this; the crew can change it.

When checks are scarce, they go to the work that matters most: the check queu… #12231

Merged opened this in answer to

Check · Review · Land · Live done — Landed and live in production.

Merged

Queued checks now start in the owner's ranked order, and the home lanes list them in that order. `tsc` and `bun scripts/gate.ts` were clean, and the tests that cover the change pass. I ran no other tests locally: `scripts/fast.ts` said the diff touches 2240 of 3057 files, so I ran the relevant suites by hand. I didn't run `bun scripts/design-lint.ts`, which this change doesn't call for.

shipped production is serving it deploy bc5c621

opened this

Queued checks now start in the owner's ranked order, and the home lanes list them in that order. tsc and bun scripts/gate.ts were clean, and the tests that cover the change pass. I ran no other tests locally: scripts/fast.ts said the diff touches 2240 of 3057 files, so I ran the relevant suites by hand. I didn't run bun scripts/design-lint.ts, which this change doesn't call for.

What changed

  • Check order: pickNext (src/checks/service.ts) takes a new rank argument, read from issue_rank by src/checks/ranked_first.ts.

- The order is: a merge-queue gate, then an approved pull's check, then by the rank of the pull's issue, top first. Unranked checks go last, newest first. - A check past STARVATION_MS still beats all of these, so nothing waits forever. - Among approved checks, rank breaks ties before recency does. The issue didn't say which should win there, so that is my call.

  • Builder slots: the new-build pick already followed pickOrder. Rework did not, so moveRequested and sweepStaleReds now walk pulls in rank order through a new inRankOrder in src/core/rank.ts. When slots are scarce, the higher-ranked pull's rework or re-check gets one first.
  • Home lanes: src/flow/lanes_read.ts now sorts waiting checks and builds in the order they will be taken, and numbers them in that order. The first tile reads "next in line". Moving an issue to the top moves its check to that spot.
  • Tests: test/checks-ranked.test.ts queues five checks ranked 3,1,5,2,unranked and sees them start 1,2,3,5,unranked. It also covers approved-first, starvation, the lane order and the rework order.

Left out

  • The lane doesn't mark approved checks, so a waiting approved check isn't pulled to the front of the tiles the way the real queue does. Showing that would need a review lookup per lane read.
  • Ranks are per repository, so two repos' top-ranked checks tie on place and fall back to newest first.

Try it: rank two pulls with next_up, queue checks for both, and the lane shows the higher-ranked one first.

🤖 Generated with Claude Code

Closes #12230

4 earlier comments · 2 events
commented

Queued checks now start in the owner's ranked order, and the home lanes list them in that order. tsc and bun scripts/gate.ts were clean, and the tests that cover the change pass. I ran no other tests locally: scripts/fast.ts said the diff touches 2240 of 3057 files, so I ran the relevant suites by hand. I didn't run bun scripts/design-lint.ts, which this change doesn't call for.

What changed

  • Check order: pickNext (src/checks/service.ts) takes a new rank argument, read from issue_rank by src/checks/ranked_first.ts.

- The order is: a merge-queue gate, then an approved pull's check, then by the rank of the pull's issue, top first. Unranked checks go last, newest first. - A check past STARVATION_MS still beats all of these, so nothing waits forever. - Among approved checks, rank breaks ties before recency does. The issue didn't say which should win there, so that is my call.

  • Builder slots: the new-build pick already followed pickOrder. Rework did not, so moveRequested and sweepStaleReds now walk pulls in rank order through a new inRankOrder in src/core/rank.ts. When slots are scarce, the higher-ranked pull's rework or re-check gets one first.
  • Home lanes: src/flow/lanes_read.ts now sorts waiting checks and builds in the order they will be taken, and numbers them in that order. The first tile reads "next in line". Moving an issue to the top moves its check to that spot.
  • Tests: test/checks-ranked.test.ts queues five checks ranked 3,1,5,2,unranked and sees them start 1,2,3,5,unranked. It also covers approved-first, starvation, the lane order and the rework order.

Left out

  • The lane doesn't mark approved checks, so a waiting approved check isn't pulled to the front of the tiles the way the real queue does. Showing that would need a review lookup per lane read.
  • Ranks are per repository, so two repos' top-ranked checks tie on place and fall back to newest first.

Try it: rank two pulls with next_up, queue checks for both, and the lane shows the higher-ranked one first.

🤖 Generated with Claude Code

commented

Fixed the gate failure and pushed it as 15895ac73.

The gate rejected test/checks-ranked.test.ts because a comment line was 124 columns long. I shortened that comment. I also wrapped the long createRun line above it, which was code rather than a comment.

bun scripts/gate.ts passes now. bun x tsc --noEmit printed nothing, so it found no type errors. The four tests in test/checks-ranked.test.ts pass. The gate only passed after I committed. Run on the uncommitted file, it still reported the old line 42.

I didn't run the full suite here. The forge runs it on this push.

Changes requested — before the latest push

Ranked check order is sound and tested, but the home lane can name the wrong check as next. Fix in one round:

  1. The lane says "next in line" for the top ranked check, but pickNext starts an approved pull check first, and a starved one before that. The lane ignores both, so the tile is wrong in exactly the case the pull describes as handled. Either mark approved/starved in the lane order (one batched query, not per row) or do not claim "next in line" there. Add a test for it.
  2. runRows still ORDER BY created_at LIMIT ?3 before the rank sort, so on a long queue a high-ranked newer check can be cut off the lane. Order by rank in SQL (rk IS NULL, rk) before the limit, and test it.
  3. Ties across repos: ranks are per repo, so the lane and pickNext interleave repos arbitrarily. Say so in a test or tie-break by repo explicitly.
  4. Add docs/features/ note on how ranking now drives check and rework order; README is not the place.

Preview not exercised beyond reading the diff.

commented

The home checks lane now orders waiting checks the way pickNext does, so "next in line" names the check that starts next. This answers all four review points, pushed as 77e27f369.

  • Lane order: takenOrder in src/flow/lanes_read.ts now sorts a starved check first, then an approved pull's check, then everything else. Within each group it uses rank, then newest first. A starved check is the oldest queued check that has waited at least half of BUDGETS.laneWait, the same bound as STARVATION_MS. I don't import STARVATION_MS itself, because service.ts is heavy for the lane worker thread. Approval is read with reviewSummariesFor, one batch per lane read, not one query per row.
  • Rank before the limit: the SQL now orders by the starved check, then rank (k.pos IS NULL, k.pos), then age, before LIMIT. A ranked check can no longer be cut off by newer unranked ones. I also made the checks lane order newest first before the limit, since that is what pickNext takes among the unranked.
  • Ties across repos: I kept the tie-break as newest first and said so in a test and in the doc, rather than adding a repo ordering. I judged that interleaving repos by some other rule would be arbitrary too.
  • Doc: docs/features/ranked-checks.md explains how ranking now drives check and rework order. I left the README alone.

I added three tests to test/checks-ranked.test.ts:

  • Lane tiers: an approved check goes ahead of the ranked ones, and a starved one goes ahead of that.
  • Scan bound: with 60 extra queued checks, the ranked ones still lead the lane.
  • Ties across repos: equal ranks in two repos pick the newest check.

The gate passes, tsc is clean, test/checks-ranked.test.ts passes (7 tests), and the other lane tests I ran pass. scripts/fast.ts said the diff was too broad to name tests for, so I ran only the files that import lanes_read or readFast, plus the two home-query tests. I didn't run the whole suite, since the forge's check does that on the push. I haven't looked at the preview.

An approved check can still fall outside the 40-row window if it is unranked and there are more than 40 newer ones. The review only asked for the rank ordering in SQL, and approval is read after the fetch.

Changes requested — before the latest push

No security findings: no new input, write or secret, and the SQL is parameterised. Three things to fix in one round.

  1. The lane can still name the wrong check as next (src/flow/lanes_read.ts, runRows). The SQL orders by starved, then rank, then age before LIMIT 40. It does not put approved checks first. An approved pull whose check is unranked and has more than 40 newer checks queued is cut off the window. pickNext starts it first, but the lane never shows it. You list this as a known gap, but it breaks the claim that the tile is the check that starts next. Put approval in the ORDER BY before the limit. One way is an EXISTS on review for the run commit_oid and issue, with approved and no changes_requested, matching approvedOnce. Alternatively, read approval for the whole queued set, which is small. Add a test: an approved unranked check older than 40 newer ones still appears, first.
  1. The starvation bound is duplicated (starvedCheck uses BUDGETS.laneWait / 2). STARVATION_MS in checks/service.ts is a second copy of the same number, and the two can drift. Export the bound from a light module that both service.ts and lanes_read.ts import, such as kernel/budgets.ts. Add a test that fails if they differ. Also, the lane picks the oldest queued check as starved without the atLimit skip pickNext applies, so say in a comment that this is approximate or match it.
  1. Test hygiene (test/checks-ranked.test.ts).
  • The setup comment says "ranked 3,1,5,2,unranked". The real order is pull 2, 4, 1, 3, and pull 5 unranked. Fix the comment.
  • The scan-bound test has a stale comment ("Rank pull 5 last of the ranked"), and expect(pulls.length).toBe(5) asserts nothing about the change. Remove both.
  • Test 6 only passes because the extras are unranked. Add a case where the ranked check is the OLDEST of 60+, so that it fails without the SQL rank ordering.
  • Test 2 hand-builds a Run with a raw SELECT to fake starvation. Use the same helper as the lane test.

The docs and the rework ordering look right. The README is untouched, which is correct. No TUI screen is needed, because this is ordering only.

commented

When checks are scarce, the work the owner ranked highest gets them first (#12230). Queued checks, rework and re-checks now follow the owner's ranked list: highest first, unranked last, and newest first only as a tie-break. A check that has waited too long ("starved") still goes first, and an approved pull's check still goes before the rest. The home checks lane lists waiting checks in the order they will start, and the first one says "next in line".

This round, from review:

  • Approved checks are no longer cut off the lane (src/flow/lanes_read.ts). The lane shows at most 40 checks. Before, an approved check could fall outside those 40 even though it starts first. Now approval is worked out for every queued check (that set is small), using the same review rule approvedForCheck uses. The order is decided before the 40-check cutoff: starved, then approved, then rank, then age.
  • One starvation limit. STARVATION_MS now lives in src/kernel/budgets.ts. checks/service.ts re-exports it and the lane imports it, so the two can't drift apart.
  • The lane's starved check is approximate, and a comment now says so. pickNext skips a check whose repository is at its concurrency limit; the lane doesn't read that live state, so it doesn't apply the skip.
  • Tests (test/checks-ranked.test.ts):

- Fixed the setup comment and removed the stale comment and the pulls.length assertion. - Faking an old or approved check now goes through two shared helpers, age and approve, in every test. - Two new cases: a ranked check that is the oldest of 60 newer unranked ones, and an approved unranked check behind 45 newer ones. Each still appears first in the lane, and each fails when its part of the ORDER BY is removed. - A new test pins the starvation limit: just under it, rank decides in both the lane and pickNext; just over it, the starved check leads the lane.

Not done: there are no README or terminal screen changes, because this PR only changes ordering.

Checks run:

  • bun scripts/gate.ts and bun x tsc --noEmit pass.
  • scripts/fast.ts couldn't name the tests (exit 2) because kernel/budgets.ts changed. So the 71 test files that touch the checks service, the lanes, or the budgets were run: 653 pass, 0 fail, 33 skipped. The skipped ones are the unix-socket and cell suites this sandbox can't run; the forge's check runs them on every push.

To try it: on the preview, queue checks on pulls in one repository, reorder its ranked list, and watch the home checks lane reorder to match.

🤖 Generated with Claude Code

commented

When checks are scarce, the work the owner ranked highest gets them first (#12230). Queued checks, rework and re-checks follow the owner's ranked list: highest first, unranked last, and newest first only as a tie-break. A check that has waited too long ("starved") still goes first, and an approved pull's check still goes before the rest. The home checks lane lists waiting checks in the order they will start, and the first one says "next in line".

Changed after review:

  • Approved checks are no longer cut off the lane (src/flow/lanes_read.ts). The lane shows at most 40 checks. Before, an approved check could fall outside those 40 even though it starts first. Now approval is worked out for every queued check (that set is small), using the same review rule approvedForCheck uses. The order is decided before the 40-check cutoff: starved, then approved, then rank, then age.
  • One starvation limit. STARVATION_MS now lives in src/kernel/budgets.ts. checks/service.ts re-exports it and the lane imports it, so the two can't drift apart.
  • The lane's starved check is approximate, and a comment now says so. pickNext skips a check whose repository is at its concurrency limit; the lane doesn't read that live state, so it doesn't apply the skip.
  • Tests (test/checks-ranked.test.ts):

- Fixed the setup comment and removed the stale comment and the pulls.length assertion. - Faking an old or approved check now goes through two shared helpers, age and approve. - Two new cases: a ranked check that is the oldest of 60 newer unranked ones, and an approved unranked check behind 45 newer ones. Each still appears first in the lane, and each fails when its part of the ORDER BY is removed. - A new test pins the starvation limit: just under it, rank decides in both the lane and pickNext; just over it, the starved check leads the lane.

  • Check fix: the forge's check failed because a comment line in the test file was 104 columns long. It is rewrapped to 94. The gate only measures committed lines, which is why it passed when run before the commit.

Not done: there are no README or terminal screen changes, because this pull only changes ordering.

Checks run:

  • bun scripts/gate.ts and bun x tsc --noEmit pass on the pushed commit, and test/checks-ranked.test.ts passes (10 tests).
  • On the previous push, scripts/fast.ts couldn't name the tests (exit 2) because kernel/budgets.ts changed. So the 71 test files that touch the checks service, the lanes, or the budgets were run: 653 pass, 0 fail, 33 skipped. The skipped ones are the unix-socket and cell suites this sandbox can't run; the forge's check runs them on every push. The last push only changed a comment, so only the ranked test was re-run.

To try it: on the preview, queue checks on pulls in one repository, reorder its ranked list, and watch the home checks lane reorder to match.

🤖 Generated with Claude Code

Approved

All earlier asks are met. (1) Approval now orders the lane before the 40-row bound: checkTiers reads the whole queued set in one batch and the SQL puts starved, approved, rank, age first; the test for an approved unranked check behind 45 newer ones covers it. (2) STARVATION_MS lives in kernel/budgets.ts and both pickNext and the lane read it, with a test pinning them equal; the lane's starved pick is documented as approximate because it skips the atLimit check. (3) Test hygiene is fixed: the comment is right, the stale assertion is gone, there is a case with the ranked check oldest of 60+, and shared age/approve helpers replace the hand-built Run. Docs are in docs/features/ranked-checks.md, the README is untouched, and this is ordering only so no TUI screen is needed. No new input or write, SQL is parameterised. Two things I would do next, non-blocking: (a) Non-blocking: checkTiers runs on every lane read; if queued checks ever number in the hundreds, cache it for a second or two. (b) Non-blocking: where checks wait on one repo at its concurrency limit, the lane's next-in-line can differ from pickNext; expose the at-limit set to the lane read.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs