Skip to content

feat(speculation): allocator contract and sticky impl - #450

Open
behinddwalls wants to merge 1 commit into
preetam/speculation-generatorfrom
preetam/speculation-allocator
Open

feat(speculation): allocator contract and sticky impl#450
behinddwalls wants to merge 1 commit into
preetam/speculation-generatorfrom
preetam/speculation-allocator

Conversation

@behinddwalls

@behinddwalls behinddwalls commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Summary

Why?

The standard Speculator splits into two halves: rank the candidate paths (#446), then spend the build budget on them. This is the spending half.

Like the generator, it is not controller-facing — the controller knows only the Speculator contract — so there is no Config or Factory; an Allocator is chosen when the standard Speculator is constructed.

What?

Adds allocator (the contract) and allocator/sticky (the first implementation).

Allocate takes the queue's path sets and the generator's candidate iterator and returns the build and cancel actions for this run. Reconciling candidates against paths already in flight is the allocator's job; whether to preempt anything is its policy.

sticky never preempts. It counts the paths still holding a build slot — pending, building, and cancelling (a cancel is a request; the build keeps its slot until it actually stops) — then pulls candidates in order into whatever is free and proposes a build for each new one. It never proposes a cancel. That trades responsiveness for never throwing away a build already started. Its counterpart, a preempting allocator, would cancel a low-value in-flight path to fund a better candidate.

A path stored with no status at all is a data defect. It holds no slot — one that never reaches a terminal state would pin a slot forever, permanently lowering the queue's capacity — so it is skipped and logged as a warning rather than passing unnoticed. New therefore takes a logger.

Includes the package README.md and generated mocks.

Test Plan

bazel test //submitqueue/extension/speculation/..., make lint, make check-gazelle

sticky's table test covers filling free budget in candidate order; keeping an in-flight path funded while filling the remaining slot; which statuses hold a slot (pending, building, and cancelling do, terminal ones do not); a path with no status holding nothing; deduplicating a repeated candidate; and propagating an iterator error. Two further tests assert the warning fires exactly once for a status-less path and stays silent otherwise.

Both new behaviors were mutation-checked — reverting the skip, or removing the warn, each fails the suite — so the assertions are not passing vacuously.

Stack

  1. feat(entity): speculation path and run entities #444
  2. feat(speculation): speculator extension contract #445
  3. feat(speculation): generator contract and bestfirst impl #446
  4. @ feat(speculation): allocator contract and sticky impl #450
  5. feat(speculation): standard composed speculator #451

@sbalabanov sbalabanov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical comment about failing fast


Because cancellation is best-effort, an `Allocator` should not spend capacity it merely expects a cancel to release — a build cancelled to make room keeps charging the budget until its cancel reaches a terminal state, so the queue converges over successive runs rather than oversubscribing the hard cap on concurrent builds in a single pass.

## `sticky`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move that into sticky/README.md instead


## `sticky`

The `sticky` `Allocator` fills only free budget slots and leaves every in-flight build running. Against the budget it counts the paths that still hold a build slot — `pending`, `building`, and `cancelling` (a cancel is a request, and the build keeps its slot until it actually stops). It then proposes a build for each new candidate, in order, until the budget fills; it never proposes a cancel.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add that 'sticky' operates the "builds" as a build unit budget (so, it is quite coarse).
More interesting implementations may operate with more granular units, understanding the size of the build needed to be done (i.e. based on number of targets, historical data etc).

}

// New returns a sticky allocator.Allocator with the given concurrent-build
// budget.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

explain what unit of measure for the budget is

// data defect. Skip it rather than counting it: a status that
// never turns terminal would pin a build slot forever. That leaves
// the path free to be proposed again, which is self-correcting,
// but the malformed entry is worth knowing about.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SQ default on data inconsistencies is to fail fast and hard

@behinddwalls
behinddwalls force-pushed the preetam/speculation-allocator branch from 10e097e to bf09ae6 Compare July 29, 2026 18:12
Add submitqueue/extension/speculation/allocator, the budget-spending composition point (Allocator) the standard Speculator hands its candidate stream to, plus the sticky implementation and mocks.

sticky fills only free budget slots and never preempts a running build, trading responsiveness for never discarding work already started; its policy counterpart is a preempting allocator.
@behinddwalls
behinddwalls force-pushed the preetam/speculation-allocator branch from bf09ae6 to 6977b91 Compare July 29, 2026 18:24
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.

2 participants