docs(rfc): add queue-scoped speculation RFC#396
Conversation
9bca892 to
dc7a99e
Compare
131286e to
7380982
Compare
## Summary ### Why? The current speculation design (doc/rfc/submitqueue/speculation.md) materializes a batch's full 2^N speculation tree up front, persists it, and re-walks all of it on every event — and each per-batch pass additionally triggers a queue-wide prioritize round. The enumerate/score/select seams force the materialized tree through every contract boundary, which caps how far the dependency limit can ever scale and couples per-event cost to tree size. ### What? Adds an RFC proposing a queue-scoped execution model for speculation: a queue-keyed speculation pass (pure function of ground truth, one pass per dirty signal, self-arming tick backstop) replaces the batch-keyed speculate and prioritize stages; persistence inverts to bets-not-candidates (bets keyed by content-addressed path IDs with a correctness-required attempt counter, an executor-owned path→build record, and a per-queue book as bet index and membership linearization point); extension moves to a single Speculator seam with a composed Belief/Generator/Admitter default. The RFC records the adversarial validation of each load-bearing assumption (single-writer, crash choreography under no-transactions NoSQL, merge safety, cost ceiling), the design decisions with rejected alternatives, a shadow-mode cutover test, and open questions. Merge finalization is strict: the pass advances a batch to merge only when its predecessors have actually merged (observed via mergesignal). speculation.md's optimistic merge hand-off is deliberately dropped and deferred to its own design, recorded as an open question, to keep merge-executor concerns out of the speculation pass.
7380982 to
e3cf143
Compare
Early signalThanks, I spent some time working through this. My early signal is that I prefer this direction over continuing the materialized-tree stack. My mental model is now: This feels similar to a level-based reconciliation controller. The event tells speculation where to look, but current stored state determines what to do. What I like
Concerns I think should be resolved in the RFCExternal side-effect idempotencyThe reconciliation loop can only supervise external work that it knows exists. The current execution-record sequence still appears to be: A crash after triggering CI but before persisting the record leaves an unknown build. A later pass can trigger another one. I think the design needs a durable pre-trigger reservation plus a runner-level idempotency key derived from The same issue exists for committing merges. Runway needs a durable request/result record written before calling Tick multiplicationIf every delivered poke schedules an occurrence-unique delayed tick, then a burst of ten pokes creates ten permanent tick chains. Each tick schedules its own successor. I think the tick needs singleton semantics per queue and scheduling epoch. Multiple passes should converge on the same next tick rather than each creating an independent chain. Book boundsThe RFC says the book stays small because bets are budget-bounded, but passed bets hold no budget and remain book-listed until their batches become terminal. During a merge backlog, passed bets can accumulate while new builds continue to be admitted. The book then grows with queue depth or merge backlog rather than CI budget. It may be cleaner for the book to track only bets that could still hold CI capacity, with the winning passed bet stored separately on the batch or in a head-to-winning-bet mapping. Path identityHashing only: does not appear sufficient because dependency ordering is unspecified, dependencies can change for the same head, and excluded dependencies are part of the path's meaning. I would define a versioned canonical encoding containing the complete dependency universe or graph generation, deterministic ordering, and included/excluded assumptions. Policy versus correctnessThe proposed Speculator owns both:
That boundary feels too broad. In particular, if a Generator may choose a narrower path space, it should not be able to influence the correctness conclusion that no viable path exists. I would keep mandatory lifecycle and reconciliation rules in controller/core code and make only beliefs, ordering, admission, and optional preemption pluggable. DeterminismThe RFC says the same snapshot produces the same plan, but budget, depth, time-based fairness, model version, and injected signals can change independently from the snapshot. If replayability and shadow-mode comparison are important, I think those values should be frozen into an immutable Things I would investigate next
OverallI think the foundational choice is right: persist facts and actual side effects, then continuously derive the plan, rather than persisting and incrementally maintaining the entire possibility space. I would pivot toward this design, but tighten the points above before committing to the interfaces and persistence model. |
Performance comparisonLet:
BeforeEach affected batch walks its tree and triggers another queue-wide tree sweep. AfterEach poke reloads the queue, but candidates are generated only when needed. Likely crossoverThe new approach generally wins when:
ExampleApproximate work: The main risk for the new approach is not candidate generation. It is repeatedly loading Passes also serialize per queue: If a pass takes |
Summary
Why?
The current speculation design (doc/rfc/submitqueue/speculation.md) materializes a batch's full 2^N speculation tree up front, persists it, and re-walks all of it on every event — and each per-batch pass additionally triggers a queue-wide prioritize round. The enumerate/score/select seams force the materialized tree through every contract boundary, which caps how far the dependency limit can ever scale and couples per-event cost to tree size.
What?
Adds an RFC proposing a queue-scoped execution model for speculation: a queue-keyed speculation pass (pure function of ground truth, one pass per dirty signal, self-arming tick backstop) replaces the batch-keyed speculate and prioritize stages; persistence inverts to bets-not-candidates (bets keyed by content-addressed path IDs with a correctness-required attempt counter, an executor-owned path→build record, and a per-queue book as bet index and membership linearization point); extension moves to a single Speculator seam with a composed Belief/Generator/Admitter default. The RFC records the adversarial validation of each load-bearing assumption (single-writer, crash choreography under no-transactions NoSQL, merge safety, cost ceiling), the design decisions with rejected alternatives, a shadow-mode cutover test, and open questions.
Merge finalization is strict: the pass advances a batch to merge only when its predecessors have actually merged (observed via mergesignal). speculation.md's optimistic merge hand-off is deliberately dropped and deferred to its own design, recorded as an open question, to keep merge-executor concerns out of the speculation pass.