Skip to content

feat(speculation): add probability path scorer#333

Open
behinddwalls wants to merge 1 commit into
preetam/int/speculation-parity-implsfrom
preetam/int/speculation-pathscorer-probability
Open

feat(speculation): add probability path scorer#333
behinddwalls wants to merge 1 commit into
preetam/int/speculation-parity-implsfrom
preetam/int/speculation-pathscorer-probability

Conversation

@behinddwalls

@behinddwalls behinddwalls commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Why?

The pathscorer seam has no real implementation — only mocks and a programmable fake — yet its output is the ranking currency the selector and prioritizer act on. Speculation needs a default scorer whose scores mean something from the start: inert while trees hold a single path, but ranking chain-vs-fallback paths correctly the moment an enumerator produces alternatives. It is split out from the parity-stub impls because it is the one seam implementation with an actual model, worth reviewing on its own.

What?

pathscorer/probability — scores each path as the probability that exactly that path's assumption holds: Score = p(head) × Π p(d) for base deps × Π (1−p(d)) for non-base head deps.

Each batch's probability resolves from its state, so resolved outcomes override predictions: succeeded → 1, failed/cancelled → 0, otherwise the score stage's predicted Batch.Score (neutral 0.5 when unscored; best-effort cancelling keeps its prediction). A dead dependency therefore zeroes every path built on it and boosts every path that excluded it by the full (1−p)=1 factor — score mass shifts to the paths consistent with reality, with no cross-path coupling. Folding outcomes into path status stays the controller's reconcile job; the scorer only recomputes Score, over every path regardless of status.

Dependencies are read one at a time through the injected storage.BatchStore per the store's key/value contract, each batch loaded at most once per call; store errors return wrapped and unclassified. The README walks a three-path worked example (chain / drop-B / alone) before and after a dependency failure.

Test Plan

make gazelle && make fmt && bazel test //submitqueue/extension/speculation/.... Unit coverage: probability-formula table including all state-resolution cases (succeeded/failed/cancelled in and out of base, cancelling keeps prediction, unscored fallbacks), a three-path dependency-failure scenario pinning the score-mass shift, per-dep single store read, error propagation, empty-tree short-circuit.

Stack

  1. feat(speculation): add enumerator + dependency-limit extensions #315
  2. feat(speculation): add path scorer extension #316
  3. feat(speculation): add selector + selection-limit extensions #317
  4. feat(speculation): add prioritizer + prioritization-limit extensions #320
  5. feat(storage,entity): path identity + speculation path→build mapping store #331
  6. feat(speculation): add parity default impls for the speculation seams #332
  7. @ feat(speculation): add probability path scorer #333

## Summary

### Why?

The pathscorer seam has no real implementation — only mocks and a programmable fake — yet its output is the ranking currency the selector and prioritizer act on. Speculation needs a default scorer whose scores mean something from the start: inert while trees hold a single path, but ranking chain-vs-fallback paths correctly the moment an enumerator produces alternatives. It is split out from the parity-stub impls because it is the one seam implementation with an actual model, worth reviewing on its own.

### What?

`pathscorer/probability` — scores each path as the probability that exactly that path's assumption holds: `Score = p(head) × Π p(d) for base deps × Π (1−p(d)) for non-base head deps`.

Each batch's probability resolves from its state, so resolved outcomes override predictions: `succeeded` → 1, `failed`/`cancelled` → 0, otherwise the score stage's predicted `Batch.Score` (neutral 0.5 when unscored; best-effort `cancelling` keeps its prediction). A dead dependency therefore zeroes every path built on it and boosts every path that excluded it by the full `(1−p)=1` factor — score mass shifts to the paths consistent with reality, with no cross-path coupling. Folding outcomes into path *status* stays the controller's reconcile job; the scorer only recomputes `Score`, over every path regardless of status.

Dependencies are read one at a time through the injected `storage.BatchStore` per the store's key/value contract, each batch loaded at most once per call; store errors return wrapped and unclassified. The README walks a three-path worked example (chain / drop-B / alone) before and after a dependency failure.

## Test Plan

✅ `make gazelle && make fmt && bazel test //submitqueue/extension/speculation/...`. Unit coverage: probability-formula table including all state-resolution cases (succeeded/failed/cancelled in and out of base, cancelling keeps prediction, unscored fallbacks), a three-path dependency-failure scenario pinning the score-mass shift, per-dep single store read, error propagation, empty-tree short-circuit.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant