|
14 | 14 |
|
15 | 15 | package entity |
16 | 16 |
|
17 | | -// SpeculationPathAction defines the possible actions for a speculation path. |
| 17 | +// SpeculationPath is a single speculation path: an assumed-good prefix of |
| 18 | +// predecessor batches (Base) on top of which the batch under verification |
| 19 | +// (Head) is built and validated. |
| 20 | +// |
| 21 | +// This is the unit the build stage consumes: Base maps to the build runner's |
| 22 | +// base changes (an assumed-good prefix to apply) and Head maps to the changes |
| 23 | +// being validated. |
| 24 | +type SpeculationPath struct { |
| 25 | + // Base is the ordered list of predecessor batch IDs assumed to have passed. |
| 26 | + // Empty means the path builds the head batch directly on the target branch. |
| 27 | + Base []string |
| 28 | + // Head is the batch ID being verified by this path. |
| 29 | + Head string |
| 30 | +} |
| 31 | + |
| 32 | +// SpeculationPathStatus is the observed lifecycle state of a speculation path. |
| 33 | +// It is written only by the orchestrator's speculate controller (into the |
| 34 | +// speculation tree store) and read by the decision seams (selector, prioritizer) |
| 35 | +// as input; the seams never write it. |
| 36 | +type SpeculationPathStatus string |
| 37 | + |
| 38 | +const ( |
| 39 | + // SpeculationPathStatusUnknown is the unreachable zero value, set by default |
| 40 | + // on init. A persisted path always carries a real status (candidate onward), |
| 41 | + // so this should never be seen in the store. |
| 42 | + SpeculationPathStatusUnknown SpeculationPathStatus = "" |
| 43 | + // SpeculationPathStatusCandidate is a freshly enumerated path the controller |
| 44 | + // has persisted but not yet acted on. |
| 45 | + SpeculationPathStatusCandidate SpeculationPathStatus = "candidate" |
| 46 | + // SpeculationPathStatusSelected is a path the selector has promoted — a |
| 47 | + // per-batch desire to build it — that the queue-wide prioritizer has not yet |
| 48 | + // cleared. It is not sent to build while Selected: it waits on the build |
| 49 | + // budget until it is prioritized (or dropped). |
| 50 | + SpeculationPathStatusSelected SpeculationPathStatus = "selected" |
| 51 | + // SpeculationPathStatusPrioritized is a path the prioritizer has admitted |
| 52 | + // under the queue's build budget; it is cleared to run. The build effector |
| 53 | + // triggers only Prioritized paths. |
| 54 | + SpeculationPathStatusPrioritized SpeculationPathStatus = "prioritized" |
| 55 | + // SpeculationPathStatusBuilding is a path a build signal has confirmed is in |
| 56 | + // flight; its BuildID is known. |
| 57 | + SpeculationPathStatusBuilding SpeculationPathStatus = "building" |
| 58 | + // SpeculationPathStatusPassed is a path whose build succeeded. |
| 59 | + SpeculationPathStatusPassed SpeculationPathStatus = "passed" |
| 60 | + // SpeculationPathStatusFailed is a path whose build failed. |
| 61 | + SpeculationPathStatusFailed SpeculationPathStatus = "failed" |
| 62 | + // SpeculationPathStatusCancelling is a path whose in-flight build the |
| 63 | + // controller has asked to stop but whose cancellation is not yet confirmed. It |
| 64 | + // mirrors the batch-level cancelling intent (BatchStateCancelling): the cancel |
| 65 | + // decision is recorded here and the effector drives it to terminal Cancelled. |
| 66 | + // A path with no build in flight is dropped straight to Cancelled instead. |
| 67 | + SpeculationPathStatusCancelling SpeculationPathStatus = "cancelling" |
| 68 | + // SpeculationPathStatusCancelled is the terminal state for a path that is no |
| 69 | + // longer pursued — its in-flight build was confirmed stopped, or the path was |
| 70 | + // abandoned before a build started. |
| 71 | + SpeculationPathStatusCancelled SpeculationPathStatus = "cancelled" |
| 72 | +) |
| 73 | + |
| 74 | +// SpeculationPathAction is the decision a seam (the selector or the prioritizer) |
| 75 | +// asks the controller to take for a path. It names the decision, not its effect: |
| 76 | +// it is ephemeral (recomputed every time a seam runs) and never persisted. The |
| 77 | +// controller maps it to the corresponding SpeculationPathStatus transition — |
| 78 | +// applied under the tree's optimistic lock (Version) — and records the result; |
| 79 | +// the seams never write status themselves. |
18 | 80 | type SpeculationPathAction string |
19 | 81 |
|
20 | 82 | const ( |
21 | | - // SpeculationPathActionUnknown is the default zero value for SpeculationPathAction. |
| 83 | + // SpeculationPathActionUnknown is the unreachable zero value. A seam |
| 84 | + // expresses "leave this path as-is" by omitting the path from its decisions, |
| 85 | + // not by returning this. |
22 | 86 | SpeculationPathActionUnknown SpeculationPathAction = "" |
23 | | - // TODO: Add comprehensive list of actions |
| 87 | + // SpeculationPathActionPromote asks the controller to advance this path one |
| 88 | + // stage toward running. The target status depends on which seam decided it: |
| 89 | + // the selector's promote moves a path to Selected; the prioritizer's promote |
| 90 | + // moves it to Prioritized (cleared to build). |
| 91 | + SpeculationPathActionPromote SpeculationPathAction = "promote" |
| 92 | + // SpeculationPathActionCancel asks the controller to stop pursuing this path: |
| 93 | + // it moves to Cancelling if a build is in flight (the effector then confirms |
| 94 | + // the stop and drives it to terminal Cancelled), or straight to Cancelled if |
| 95 | + // no build has started. |
| 96 | + SpeculationPathActionCancel SpeculationPathAction = "cancel" |
24 | 97 | ) |
25 | 98 |
|
26 | | -// SpeculationInfo represents metadata about a single speculation path, including the path through the dependency graph, its current state, and the predicted build score. |
27 | | -type SpeculationInfo struct { |
28 | | - // Path represents the speculation path; which is an ordered list of batches. |
29 | | - Path []string |
30 | | - // Action is a state that this path is in. |
31 | | - Action SpeculationPathAction |
32 | | - // Score is score for this speculation path. |
| 99 | +// SpeculationPathInfo is the per-path entry in a speculation tree: a path, its |
| 100 | +// latest predicted-success score, its controller-owned status, and a link to |
| 101 | +// the build dispatched for it (if any). Path is immutable once the entry is |
| 102 | +// persisted; Score, Status, and BuildID are updateable, written only by the |
| 103 | +// controller under the tree's Version optimistic lock. |
| 104 | +type SpeculationPathInfo struct { |
| 105 | + // Path is the Base/Head split this entry covers. Immutable: it identifies |
| 106 | + // the entry and never changes after the path is first persisted. |
| 107 | + Path SpeculationPath |
| 108 | + // Score is the path's predicted-success score. Updateable: it is computed by |
| 109 | + // the scorer and persisted by the controller, not set at enumeration — the |
| 110 | + // enumerator produces structure only. It is dynamic: the controller re-runs |
| 111 | + // the scorer on every respeculate (as dependencies land, dependency builds |
| 112 | + // pass, or sibling paths fail), so the value tracks the latest state rather |
| 113 | + // than a figure frozen when the path was first enumerated (~0 until the |
| 114 | + // first pass). |
33 | 115 | Score float32 |
| 116 | + // Status is the observed lifecycle state of the path. Updateable: written |
| 117 | + // only by the controller; read by the decision seams (scorer, selector, |
| 118 | + // prioritizer). |
| 119 | + Status SpeculationPathStatus |
| 120 | + // BuildID links this path to its build. Updateable: empty until a build |
| 121 | + // signal confirms the build and the controller records it (Prioritized -> |
| 122 | + // Building); the controller never knows the ID at send time. |
| 123 | + BuildID string |
| 124 | +} |
| 125 | + |
| 126 | +// SpeculationPathDecision is a seam's decision for a single path: the action the |
| 127 | +// controller should take for it. It is the output of both the selector (per |
| 128 | +// batch) and the prioritizer (queue-wide), and is not persisted. A seam returns |
| 129 | +// a decision only for the paths it wants to act on; omitted paths are left |
| 130 | +// as-is. |
| 131 | +type SpeculationPathDecision struct { |
| 132 | + // Path identifies the speculation path the action applies to. |
| 133 | + Path SpeculationPath |
| 134 | + // Action is what the controller should do for the path. |
| 135 | + Action SpeculationPathAction |
34 | 136 | } |
35 | 137 |
|
36 | | -// SpeculationTree represents the set of speculation paths constructed for a batch based on its dependency graph. |
| 138 | +// SpeculationTree is the set of candidate speculation paths for a batch, built |
| 139 | +// from its dependency graph. BatchID is immutable; Paths is updateable (the |
| 140 | +// controller overwrites it wholesale on every respeculate), guarded by Version. |
37 | 141 | type SpeculationTree struct { |
38 | 142 | // BatchID is the batch for which this speculation tree is constructed. |
| 143 | + // Immutable: it identifies the tree. |
39 | 144 | BatchID string |
40 | | - // Speculations is a list of speculation paths for this batch based on a graph of its |
41 | | - // dependents. |
| 145 | + // Paths is the candidate speculation paths for this batch, derived from a |
| 146 | + // graph of its dependencies. Each entry's per-path dynamic state (Score, |
| 147 | + // Status, BuildID) is documented on SpeculationPathInfo. |
42 | 148 | // |
43 | 149 | // For e.g - Consider batches - queueA/batch/1, queueA/batch/2, queueA/batch/3 |
44 | | - // such that - queueA/batch/2 and queueA/batch/3 depend on queueA/batch/1 |
| 150 | + // such that - queueA/batch/2 and queueA/batch/3 depend on queueA/batch/1. |
| 151 | + // Each dependent batch gets two paths: build alone, or build on the |
| 152 | + // assumed-good predecessor. Just after enumeration every path is a candidate: |
45 | 153 | // |
46 | | - // Speculations for queueA/batch/1 - [{Path: []string{"queueA/batch/1"}, State: "scheduled", Score: 0.1}] |
47 | | - // Speculations for queueA/batch/2 - [{Path: []string{"queueA/batch/2"}, State: "scheduled", Score: 0.9}, {Path: []string{"queueA/batch/1", "queueA/batch/2"}, State: "scheduled", Score: 0.3}] |
48 | | - // Speculations for queueA/batch/3 - [{Path: []string{"queueA/batch/3"}, State: "scheduled", Score: 0.9}, {Path: []string{"queueA/batch/1", "queueA/batch/3"}, State: "scheduled", Score: 0.3}] |
| 154 | + // Paths for queueA/batch/2 - [{Path: {Base: [], Head: "queueA/batch/2"}, Status: "candidate"}, {Path: {Base: ["queueA/batch/1"], Head: "queueA/batch/2"}, Status: "candidate"}] |
| 155 | + // Paths for queueA/batch/3 - [{Path: {Base: [], Head: "queueA/batch/3"}, Status: "candidate"}, {Path: {Base: ["queueA/batch/1"], Head: "queueA/batch/3"}, Status: "candidate"}] |
49 | 156 | // |
50 | | - Speculations []SpeculationInfo |
| 157 | + Paths []SpeculationPathInfo |
| 158 | + // Version is the version of the object. It is used for optimistic locking: |
| 159 | + // updates are conditional on the persisted version matching the caller's |
| 160 | + // expected version. Versioning starts at 1 and is incremented for each |
| 161 | + // change to the object; version arithmetic is owned by the controller, the |
| 162 | + // store performs a pure conditional write. |
| 163 | + Version int32 |
51 | 164 | } |
0 commit comments