Skip to content

feat(speculation): predict a batch's outcome from its scorer price and its builds - #626

Draft
behinddwalls wants to merge 1 commit into
mainfrom
preetam/outcome-predictor
Draft

feat(speculation): predict a batch's outcome from its scorer price and its builds#626
behinddwalls wants to merge 1 commit into
mainfrom
preetam/outcome-predictor

Conversation

@behinddwalls

@behinddwalls behinddwalls commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Summary

A batch's price reflects only its diff size; everything the queue learns during the run (a build passed, the batch is merging) is thrown away. Add a predictor.Predictor contract that takes the batch's build progress and revises the Scorer's price with it. Implementation predictor/evidence multiplies the price's odds by one factor per piece of evidence — logistic regression in logs, so hand-set factors can later be fitted. Path sets come from the Speculator's single-read snapshot, not a store re-read. Config predictor: factors default to 1, so behavior is unchanged until set; shipped values are placeholders.

Design: doc/rfc/submitqueue/outcome-predictor.md.

Test Plan

bazel test //submitqueue/... //service/... //platform/... — passes
✅ New: factor application, compounding failures, all-succeed caveat, extreme prices, error cases, New validation, per-dependency path sets, config defaults/validation
make fmt, make gazelle, make mocks — idempotent

@sbalabanov

Copy link
Copy Markdown
Contributor

plz simplify Summary...

@behinddwalls
behinddwalls force-pushed the preetam/outcome-predictor branch from 6664c9b to 55ed3af Compare August 25, 2026 21:52
Base automatically changed from preetam/scorer-under-speculation to main August 25, 2026 22:47
@behinddwalls
behinddwalls force-pushed the preetam/outcome-predictor branch from 55ed3af to 6f2dc66 Compare August 25, 2026 22:47
…d its builds

## Summary

### Why?

Nothing the pipeline learns about a batch changes its price. A batch whose build has passed, whose dependencies have landed, and which is being merged is priced exactly as it was before anything was known about it — on the size of its diff. The speculate controller holds that evidence in memory during the run that needs it, and throws it away, so `bestfirst` ranks paths on a number that ignores the queue's own results.

The evidence does not belong on `Score`. Putting it there was tried first and reverted: all three scorer implementations took a parameter they discarded, which is the tell that it belongs to a different contract. A scorer prices a change; how far a batch has got is not part of that question.

### What?

A second contract, `predictor.Predictor`, is handed a batch and its path set and returns how likely the batch is to reach `Succeeded`. It is built with a `Scorer` and revises that scorer's price. The generator now depends on the predictor; `scorer.Scorer` is untouched.

`predictor/evidence` is the implementation. It converts the scorer's price to odds, multiplies by one configured factor per piece of evidence, and converts back — so the result stays a probability with no clamping, and a factor means the same thing whatever the price was. Written as logs and summed the same arithmetic is a logistic regression, which is what lets hand-written factors later be replaced by fitted ones without changing the form.

Evidence priced today: a passed build, failed builds (compounding), and the merging and cancelling states. A passed build only counts on the all-succeed path — one built without a dependency's changes says nothing about a candidate that assumes the dependency lands.

Two edges worth knowing. The price is bounded away from 0 and 1 before conversion, because those have no finite odds and a certain scorer could otherwise never be revised. A price that is not a probability is an error rather than a clamp: that is a broken scorer, and `bestfirst` already substitutes its own default when a price cannot be had. `New` validates its inputs and returns an error rather than panic, because the fitted-factor file loader planned in the RFC bypasses configuration validation and there this check is the only guard.

`Generate` gains the path sets, threaded from the Speculator, which already receives them. The alternative — reading the path-set store from inside the predictor — would re-read what the run already holds and could see a newer version than the rest of the run, breaking the single-read invariant the snapshot depends on.

Configuration is a `predictor:` block whose factors default to 1, so an absent block ranks on the scorer's price exactly as before. The queue's existing `scorer:` is the base; it is not named again. The shipped factor values are hand-set placeholders, not measured — they are uncalibrated until the fitting work in the RFC lands.

Design and rationale: `doc/rfc/submitqueue/outcome-predictor.md`.

## Test Plan

✅ `bazel test //submitqueue/... //service/... //platform/...` — passes
✅ New: the neutral set returns the scorer's price unchanged; each factor applies only on its evidence; failures compound; a passed path assuming a failure does not count; prices of 0 and 1 stay in range and still move; a non-probability price, a NaN price and a scorer error each surface as errors; `New` rejects a nil base and a non-positive factor with an error
✅ New: each dependency is priced against its own path set, and one that never speculated gets the zero value
✅ New: config defaults to neutral, rejects unknown and non-positive factors
✅ `make fmt`, `make gazelle`, `make mocks` — idempotent

Not run: `make e2e-test`. The end-to-end check worth doing before the factors are turned up is a queue configured with a large `pathPassed`, confirming a batch with a passed path ranks ahead of a same-size batch without one.
@behinddwalls
behinddwalls force-pushed the preetam/outcome-predictor branch from 6f2dc66 to db38323 Compare August 26, 2026 16:28
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