Skip to content

feat(speculation): generator contract and bestfirst impl - #446

Open
behinddwalls wants to merge 1 commit into
preetam/speculation-speculatorfrom
preetam/speculation-generator
Open

feat(speculation): generator contract and bestfirst impl#446
behinddwalls wants to merge 1 commit into
preetam/speculation-speculatorfrom
preetam/speculation-generator

Conversation

@behinddwalls

@behinddwalls behinddwalls commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Add submitqueue/extension/speculation/generator, the candidate-stream composition point (Generator/PathIterator) the standard Speculator pulls from, plus the bestfirst implementation and mocks.

Open takes only the queue's batches. The generator offers every coherent path in the space, including paths whose builds already ran — suppressing finished paths belongs to the Allocator, the piece that already reconciles candidates against the stored path sets by ID. Keeping the generator ignorant of path sets leaves it a pure enumerator and removes the expand-before-skip subtlety from its iterator: Next pops, expands, returns, with no filtering loop.

bestfirst ranks each path by the product of its dependencies' landing chances (scored through an injected scorer) and builds them lazily. A single heap holds every path built but not yet handed out, across all heads; handing one out builds only the one or two paths that come after it within that same head. Pulling k candidates builds O(k) paths however large the space behind them, so a head with twelve unresolved dependencies costs no more at the front of the queue than one with two.

Within a head, the best path bets the preferred (likelier) way on every unresolved dependency, and its score is precomputed once; every other path applies some subset of the head's flips — a flip is the option to bet one unresolved dependency the unlikely way — and scores bestScore times the applied flips' penalties (alternative over preferred). The heap stores only paths: which flips a path applies is read back off its bets, so there is no parallel flip-set representation to keep in sync. Subsets are walked by a canonical expansion under which every subset has exactly one parent, so each path is built exactly once with no visited set, and a child never outranks its parent — which is what lets the heap hand paths out in true descending order. Equal scores break on path ID among candidates resident in the heap together, which makes a run repeatable rather than globally ID-sorted.

There is no depth bound. It existed to cap 2^n enumeration, and lazy generation removed that cost, so a head may now have as many unresolved dependencies as it likes.

A dependency absent from the live batches cannot be scored, and is assumed very likely to land rather than treated as a coin flip. The even-odds threshold used to pick which way to bet is a separate constant from that default, so the two move independently — sharing one constant would have silently inverted the preferred bet for every dependency below the default.

Tests pin the exact emitted sequence across heads, the preferred bet on a below-even dependency, settled dependencies dropping out of the search, a head table over all eight batch states, the built-path count behind the laziness claim, deterministic tie-breaking, and a randomized cross-check of the whole walk against brute-force enumeration. The generator README carries a worked walkthrough tracing the heap pop by pop.

Also documents on scorer.Scorer that a speculation run scores each batch at most once but does not carry results across runs, so anything expensive belongs behind the implementation's own cache.

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

@behinddwalls
behinddwalls force-pushed the preetam/speculation-generator branch 3 times, most recently from c8ec6b1 to 3fb7e2b Compare July 27, 2026 23:14
@behinddwalls
behinddwalls marked this pull request as ready for review July 27, 2026 23:17
@behinddwalls
behinddwalls requested review from a team and sbalabanov as code owners July 27, 2026 23:17
@behinddwalls
behinddwalls force-pushed the preetam/speculation-generator branch 2 times, most recently from 5e0bdbd to 3fb7e2b Compare July 28, 2026 19:13
Comment thread submitqueue/extension/speculation/generator/README.md Outdated
Comment thread submitqueue/extension/speculation/generator/generator.go Outdated
Comment thread submitqueue/extension/speculation/generator/generator.go Outdated
Comment thread submitqueue/extension/speculation/generator/bestfirst/bestfirst.go Outdated
Comment thread submitqueue/extension/speculation/generator/bestfirst/bestfirst.go Outdated
Comment thread submitqueue/extension/speculation/generator/bestfirst/bestfirst.go Outdated
Comment thread submitqueue/extension/speculation/generator/bestfirst/bestfirst.go Outdated
Comment thread submitqueue/extension/speculation/generator/bestfirst/bestfirst.go Outdated
Comment thread submitqueue/extension/speculation/generator/bestfirst/bestfirst.go Outdated
Comment thread submitqueue/extension/speculation/generator/bestfirst/bestfirst_test.go Outdated
@behinddwalls
behinddwalls force-pushed the preetam/speculation-generator branch from 3fb7e2b to 5e2ad89 Compare July 29, 2026 18:12
@behinddwalls
behinddwalls force-pushed the preetam/speculation-generator branch from 5e2ad89 to 4c727b2 Compare July 29, 2026 18:24
@behinddwalls
behinddwalls requested a review from sbalabanov July 29, 2026 18:41
@behinddwalls
behinddwalls force-pushed the preetam/speculation-generator branch from 4c727b2 to ccb1aa4 Compare July 29, 2026 22:31
@behinddwalls
behinddwalls force-pushed the preetam/speculation-generator branch 3 times, most recently from e9e54ca to ee4ab40 Compare July 29, 2026 23:18
Add submitqueue/extension/speculation/generator, the candidate-stream composition point (Generator/PathIterator) the standard Speculator pulls from, plus the bestfirst implementation and mocks.

Open takes only the queue's batches. The generator offers every coherent path in the space, including paths whose builds already ran — suppressing finished paths belongs to the Allocator, the piece that already reconciles candidates against the stored path sets by ID. Keeping the generator ignorant of path sets leaves it a pure enumerator and removes the expand-before-skip subtlety from its iterator: Next pops, expands, returns, with no filtering loop.

bestfirst ranks each path by the product of its dependencies' landing chances (scored through an injected scorer) and builds them lazily. A single heap holds every path built but not yet handed out, across all heads; handing one out builds only the one or two paths that come after it within that same head. Pulling k candidates builds O(k) paths however large the space behind them, so a head with twelve unresolved dependencies costs no more at the front of the queue than one with two.

Within a head, the best path bets the preferred (likelier) way on every unresolved dependency, and its score is precomputed once; every other path applies some subset of the head's flips — a flip is the option to bet one unresolved dependency the unlikely way — and scores bestScore times the applied flips' penalties (alternative over preferred). The heap stores only paths: which flips a path applies is read back off its bets, so there is no parallel flip-set representation to keep in sync. Subsets are walked by a canonical expansion under which every subset has exactly one parent, so each path is built exactly once with no visited set, and a child never outranks its parent — which is what lets the heap hand paths out in true descending order. Equal scores break on path ID among candidates resident in the heap together, which makes a run repeatable rather than globally ID-sorted.

There is no depth bound. It existed to cap 2^n enumeration, and lazy generation removed that cost, so a head may now have as many unresolved dependencies as it likes.

A dependency absent from the live batches cannot be scored, and is assumed very likely to land rather than treated as a coin flip. The even-odds threshold used to pick which way to bet is a separate constant from that default, so the two move independently — sharing one constant would have silently inverted the preferred bet for every dependency below the default.

Tests pin the exact emitted sequence across heads, the preferred bet on a below-even dependency, settled dependencies dropping out of the search, a head table over all eight batch states, the built-path count behind the laziness claim, deterministic tie-breaking, and a randomized cross-check of the whole walk against brute-force enumeration. The bestfirst README carries a worked walkthrough tracing the heap pop by pop; the generator README keeps only the contract.

Also documents on scorer.Scorer that a speculation run scores each batch at most once but does not carry results across runs, so anything expensive belongs behind the implementation's own cache.
@behinddwalls
behinddwalls force-pushed the preetam/speculation-generator branch from ee4ab40 to d5dd68b Compare July 29, 2026 23:18
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