Skip to main content

fuel_dispatch/
variant_bake.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2//! **Optimize-time kernel-variant baking** — the same-device arm selector.
3//!
4//! ## The gap this closes
5//!
6//! `optimize_graph` records `Op::Branch` decision points whose arms are
7//! competing routes. Two *kinds* of arm coexist under one representation:
8//!
9//! - **Placement arms** — the same op on *different* `(backend, device)`
10//!   pairs (CPU vs. CUDA). These stay live `Op::Branch` points, resolved at
11//!   dispatch by the runtime route picker on live load / VRAM
12//!   ([`crate::ranker::route_picker`], 06-runtime).
13//! - **Kernel-variant arms** — *different implementations of the same op on
14//!   the SAME device* (the decomposed attention region vs. a fused flash
15//!   kernel, both on CUDA). Per 04-optimization these are **"largely baked
16//!   at optimize time"**, NOT deferred to the runtime picker.
17//!
18//! The shipped runtime picker resolves only placement arms: it ranks arms by
19//! their `(backend, device)` keyed on arm 0's op, so two same-device arms map
20//! to the same candidate and always resolve to **arm 0** (the finding in
21//! commit `c7bfc1b5`). A same-device fused variant — e.g. the CUDA flash
22//! decode arm from [`crate::decode_flash::offer_decode_flash_arm`] — can be
23//! *offered* but never *selected*.
24//!
25//! ## What this module does (the bake)
26//!
27//! [`bake_variant_branches`] runs at optimize time (Picker 1, where costs +
28//! caps + the Judge oracle are in hand — NOT the executor). For every
29//! reachable **same-device** variant branch it:
30//!
31//! 1. costs arm 0 (the decomposed-region oracle) and each variant arm;
32//! 2. picks the **unique** variant that is **strictly cheaper** than arm 0;
33//! 3. **collapses** the branch to that winner via
34//!    [`fuel_graph::Graph::collapse_variant_branch`] (the merge is rewired to
35//!    the winner; the branch becomes an inert single arm — "the Branch
36//!    collapses" of 04-optimization).
37//!
38//! **Conservative defaults (the oracle stands):** a tie, an unknown/sentinel
39//! cost, or a variant whose kernel is not available on the placed device all
40//! resolve to **arm 0** — the decomposed correctness oracle. **Placement
41//! branches (arms on ≥2 devices) are never touched** — they are left live for
42//! the runtime picker. A graph with no same-device variant branch (every
43//! CPU/Vulkan build today, since no CUDA flash arm is offered there) is a
44//! **no-op**, so the byte-exact suites are unaffected by construction.
45//!
46//! ## Where it rides
47//!
48//! The bake mutates the graph **in place** during `optimize_graph`, so the
49//! baked choice rides [`crate::optimize::OptimizedGraph`] (which derives its
50//! dispatch order from the graph) with no extra state — plan-once persistent
51//! decode bakes once per generation and every realize lowers the collapsed
52//! graph.
53//!
54//! ## What the full version adds
55//!
56//! This is the smallest constitutional version. The full version adds:
57//! **Judge-refined variant ranking** (a Layer-2 measurement overriding the
58//! Layer-1 composed cost — plugs into the cost closure); **Pareto retention
59//! of both arms** (keep the variant as a runtime-selectable path instead of
60//! pruning it, once the picker can distinguish same-device variants); and, if
61//! it ever becomes constitutional, **runtime load-adaptive variant
62//! switching**. Today variant choice is baked and the loser is pruned.
63
64use std::collections::HashSet;
65
66use fuel_graph::registry::{FusedOpParams, FusedOps};
67use fuel_graph::{Graph, NodeId, Op, branches_in_topo_order};
68use fuel_ir::backend::{BackendCapabilities, SubstrateClass, TransferPath};
69use fuel_ir::dispatch::SizeClass;
70use fuel_ir::probe::BackendId;
71use fuel_ir::{DType, DeviceLocation, DynScalar, Shape};
72
73use crate::cost::{cost_flash_decoding_cuda, cost_matmul_cpu, default_cost_for_op_kind};
74use crate::fused::CostEstimate;
75use crate::kernel::OpParams;
76use crate::pipelined::op_to_op_kind;
77use crate::ranker::cost::{composite_ns, default_backend_rates};
78use crate::ranker::judge::JudgeOracle;
79use crate::runtime_fused_kernels::fused_kernel_available;
80
81/// The composite-nanosecond cost of a branch arm, or `None` when it is
82/// **unknown or inadmissible** — an unpriced/sentinel-cost op, or a variant
83/// whose kernel is not available on the placed device. `None` means "this arm
84/// cannot win", so the conservative arm-0 oracle stands.
85///
86/// Arguments: `(graph, branch, arm_index, arm_interior)` where `arm_interior`
87/// is the arm's interior node set (the nodes on paths `diverge → exit`, arm 0's
88/// being the decomposed region and a fused arm's being the single fused node).
89pub type ArmCostFn<'a> = dyn Fn(&Graph, NodeId, usize, &[NodeId]) -> Option<u64> + 'a;
90
91std::thread_local! {
92    /// Per-thread cumulative count of same-device variant branches baked to a
93    /// **variant** arm (arm > 0) — i.e. a fused variant (e.g. the CUDA
94    /// flash-decode arm) that won on cost and collapsed the branch. Bumped by
95    /// [`bake_variant_branches`]'s return value. Lets a downstream realize
96    /// consumer (a live bench / test) confirm the flash arm was actually
97    /// **picked**, not merely offered — the `optimize_graph` call site discards
98    /// the return value, so this is the only observation seam without widening
99    /// that signature. Mirrors `pipelined_bridge::OPTIMIZE_CALLS_TL`.
100    static VARIANT_BAKES_TL: std::cell::Cell<usize> = const { std::cell::Cell::new(0) };
101}
102
103/// The current thread's cumulative variant-bake count.
104/// Read it before and after an `optimize_graph`/realize call and diff to learn
105/// how many branches this pass collapsed to a fused variant winner — e.g. a
106/// BF16 CUDA decode step should bake one flash-decode arm per layer once the
107/// flash-arm capability seam is bridged. Thread-local so a single-threaded
108/// realize sequence isn't polluted by concurrent test threads.
109pub fn variant_bakes_thread_local() -> usize {
110    VARIANT_BAKES_TL.with(|c| c.get())
111}
112
113/// Bake same-device kernel-variant branches to their cost winner (see the
114/// module docs). Returns the number of branches collapsed **to a variant arm**
115/// (arm > 0) — a diagnostic the caller / tests assert on, also accumulated into
116/// the thread-local [`variant_bakes_thread_local`] counter. Never panics: a
117/// structural surprise from [`Graph::collapse_variant_branch`] is ignored
118/// rather than crashing (never-panic on a production path).
119pub fn bake_variant_branches(
120    graph: &mut Graph,
121    roots: &[NodeId],
122    arm_cost: &ArmCostFn<'_>,
123) -> usize {
124    // Decide first (immutable analysis over the whole set), then mutate — a
125    // collapse rewires edges, so we must not analyse against a half-mutated
126    // graph. Topo order over `reconverge_at` is the picker's order; it does
127    // not matter for independent same-device bakes but keeps parity.
128    let branches = branches_in_topo_order(graph, roots);
129    let mut decisions: Vec<(NodeId, usize)> = Vec::new();
130
131    for branch in branches {
132        let arms = graph.node(branch).inputs.clone();
133        if arms.len() < 2 {
134            continue; // already inert — no decision
135        }
136        // Same-device gate: every arm must resolve to the SAME backend. A
137        // placement branch (arms on ≥2 backends) is left LIVE for the runtime
138        // route picker; an unstamped arm (no `target_backend`) is not a
139        // determinate variant branch, so skip it conservatively.
140        let Some(backend0) = graph.target_backend(arms[0]) else {
141            continue;
142        };
143        if !arms
144            .iter()
145            .all(|&a| graph.target_backend(a) == Some(backend0))
146        {
147            continue; // placement branch → runtime picker owns it
148        }
149
150        // Cost the oracle (arm 0). An unknown oracle cost ⇒ leave arm 0.
151        let interiors = arm_interiors(graph, branch);
152        let Some(c0) = arm_cost(graph, branch, 0, &interiors[0]) else {
153            continue;
154        };
155
156        // The winner is the UNIQUE variant strictly cheaper than the oracle.
157        // A tie at the cheapest cost, or no cheaper admissible variant, ⇒
158        // arm 0 (the conservative oracle default).
159        let mut best: Option<(usize, u64)> = None;
160        let mut tie_at_best = false;
161        // Iterating `interiors` rather than `0..arms.len()` is behaviour-
162        // identical because both derive from `graph.node(branch).inputs`:
163        // `arms` clones it and `arm_interiors` maps over it, so the lengths
164        // are equal by construction. Worth stating — if they could differ,
165        // this rewrite would silently truncate where the index form panicked.
166        for (w, interior) in interiors.iter().enumerate().skip(1) {
167            let Some(cw) = arm_cost(graph, branch, w, interior) else {
168                continue; // unknown / capability-missing ⇒ cannot win
169            };
170            if cw >= c0 {
171                continue; // not strictly cheaper than the oracle
172            }
173            match best {
174                None => best = Some((w, cw)),
175                Some((_, bc)) if cw < bc => {
176                    best = Some((w, cw));
177                    tie_at_best = false;
178                }
179                Some((_, bc)) if cw == bc => tie_at_best = true,
180                _ => {}
181            }
182        }
183        let winner = if tie_at_best {
184            0
185        } else {
186            best.map(|(w, _)| w).unwrap_or(0)
187        };
188        decisions.push((branch, winner));
189    }
190
191    // Apply: collapse every same-device variant branch — to its winning
192    // variant, else to arm 0 (dropping the offered-but-unpicked variant arms).
193    // Either way no same-device variant branch survives optimize; only
194    // placement branches remain for the runtime picker.
195    let mut baked_to_variant = 0usize;
196    for (branch, winner) in decisions {
197        if winner != 0 {
198            baked_to_variant += 1;
199        }
200        let _ = graph.collapse_variant_branch(branch, winner);
201    }
202    if baked_to_variant > 0 {
203        VARIANT_BAKES_TL.with(|c| c.set(c.get() + baked_to_variant));
204    }
205    baked_to_variant
206}
207
208/// The per-arm **interior** node sets of a branch — the nodes on paths
209/// `diverge → exit`, excluding the shared diverge prefix. Mirrors
210/// `fuel_graph::run`'s cone/shared-prefix derivation (the op carries only
211/// `reconverge_at`, so the diverge is recovered as the intersection of the
212/// arm exits' backward cones). Index `i` is arm `i`'s interior; a fused arm's
213/// interior is typically the single fused node, arm 0's is the decomposed
214/// region.
215fn arm_interiors(graph: &Graph, branch: NodeId) -> Vec<Vec<NodeId>> {
216    let arm_exits = graph.node(branch).inputs.clone();
217    let cones: Vec<HashSet<NodeId>> = arm_exits.iter().map(|&e| backward_cone(graph, e)).collect();
218    if cones.is_empty() {
219        return Vec::new();
220    }
221    let mut shared: HashSet<NodeId> = cones[0].clone();
222    for c in &cones[1..] {
223        shared = shared.intersection(c).copied().collect();
224    }
225    cones
226        .iter()
227        .map(|cone| {
228            cone.iter()
229                .copied()
230                .filter(|n| !shared.contains(n))
231                .collect()
232        })
233        .collect()
234}
235
236/// Backward-reachable cone of `from` (the node and all transitive inputs).
237fn backward_cone(graph: &Graph, from: NodeId) -> HashSet<NodeId> {
238    let mut seen: HashSet<NodeId> = HashSet::new();
239    let mut stack = vec![from];
240    while let Some(n) = stack.pop() {
241        if !seen.insert(n) {
242            continue;
243        }
244        for &inp in &graph.node(n).inputs {
245            if !seen.contains(&inp) {
246                stack.push(inp);
247            }
248        }
249    }
250    seen
251}
252
253/// The **production cost provider** (04-optimization "cost-from-decompose" +
254/// the region composed-Layer-1 sum). Folds a Layer-1 [`CostEstimate`] over the
255/// arm's interior and converts it to a composite-ns figure on the placed
256/// `backend`'s throughput roofline. This is the defensible v1 the session
257/// prompt blesses: **compare the fused arm's declared cost against the region's
258/// composed Layer-1 sum over its nodes.**
259///
260/// - a `Op::Fused(FLASH_ATTN, …)` arm is priced by [`cost_flash_decoding_cuda`]
261///   (its declared decode cost — work scales with the live prefix `k_len`,
262///   not the physical capacity), gated on the CUDA flash kernel being bound
263///   (capability: absent ⇒ `None` ⇒ the oracle stands);
264/// - an `Op::MatMul` interior node (the dominant decode-region cost) is priced
265///   with its geometry derived from operand shapes;
266/// - any other op with an `op_to_op_kind` mapping is priced by its Layer-1
267///   family at `OpParams::None` (the shape-derivable floor — the same
268///   documented approximation `fused_cost` uses; a param-carrying interior op
269///   under-prices here and is refined by the Judge, biasing conservatively
270///   toward the oracle);
271/// - the region's arms are summed as **sequential** launches
272///   (`Σ composite_ns`), so the fused arm's single-launch win over an N-launch
273///   region is visible.
274///
275/// Symbolic `k_len` (persistent decode): the flash arm is priced at the KV
276/// **capacity** as the representative prefix. Both the flash cost and the
277/// decomposed region scale ~linearly in the prefix, so the winner is stable
278/// across the concrete prefix — the capacity is a sound representative extent
279/// for the plan-once bake.
280///
281/// Returns `None` (⇒ arm 0) when the arm prices to zero (nothing costable —
282/// an unknown/sentinel region) so a zero never spuriously "wins".
283pub fn decode_arm_composite_ns(
284    graph: &Graph,
285    _branch: NodeId,
286    _arm_idx: usize,
287    interior: &[NodeId],
288    backend: BackendId,
289) -> Option<u64> {
290    let (compute_rate, mem_bw) = default_backend_rates(backend);
291    let caps = neutral_caps(backend, compute_rate, mem_bw);
292    let mut total_ns: u64 = 0;
293    let mut any = false;
294    for &nid in interior {
295        let Some(cost) = node_layer1_cost(graph, nid, backend, &caps) else {
296            continue;
297        };
298        any = true;
299        total_ns = total_ns.saturating_add(composite_ns(&cost, compute_rate, mem_bw));
300    }
301    if !any || total_ns == 0 {
302        return None; // nothing costable ⇒ oracle stands (no spurious zero win)
303    }
304    Some(total_ns)
305}
306
307/// The **Layer-2-aware** cost provider — the slice-4 payoff. Consults the Judge
308/// oracle (empirical measured latency, 06-optimization Layer-2) **first** per
309/// interior node, falling back to the [`decode_arm_composite_ns`] Layer-1
310/// composite for any node the Judge hasn't measured. Summed per arm exactly as
311/// the Layer-1 provider does, so the comparison stays apples-to-apples:
312///
313/// - **arm 0** (the decomposed region) = `Σ` over its primitives of
314///   `measured(op, dtype, size_class, backend) ?? layer1(op)`;
315/// - **arm 1** (the fused flash node) = `measured(FlashAttn, …) ?? layer1(flash)`.
316///
317/// A measured latency is used **directly** (it is already a wall-clock ns, the
318/// same convention [`crate::ranker::cost::compute_static_costs`] uses when it
319/// folds the Judge cell into `kernel_overhead_ns`), so flash's real
320/// algorithm-changing win (no materialized attention matrix, one launch —
321/// smaller measured latency than the region's `N` measured launches) becomes
322/// visible where Layer-1 alone saw a FLOP-for-FLOP tie and the conservative
323/// bake kept arm 0.
324///
325/// **A Judge measurement is evidence of capability.** A cell exists only
326/// because the kernel was actually profiled (it ran), so a measured flash cell
327/// is used even when the Layer-1 capability gate ([`fused_kernel_available`])
328/// would decline it — the gate only guards the *fallback* Layer-1 path (no
329/// measurement + unbound kernel ⇒ `None` ⇒ the oracle stands, unchanged).
330///
331/// **Hybrid sum.** When some of an arm's nodes are Judge-covered and others are
332/// not, measured cells and Layer-1 estimates are summed together — directionally
333/// better than an all-Layer-1 fold, and the conservative tie-break in
334/// [`bake_variant_branches`] (strictly-cheaper-or-arm-0) still protects against
335/// a bad partial.
336///
337/// **`kernel_source`.** The bake has no per-node candidate in hand, so it
338/// queries the legacy / default (`""`) cell — where a single-impl flash/matmul
339/// kernel registers. Threading a per-arm `kernel_source` is a follow-up; `""`
340/// keeps the born-red and single-impl production apples-to-apples.
341///
342/// With `judge == None` this is **byte-identical** to [`decode_arm_composite_ns`]
343/// (it delegates), so the no-Judge production path and the persistent
344/// byte-exact suites are unaffected by construction.
345pub fn decode_arm_composite_ns_judged(
346    graph: &Graph,
347    branch: NodeId,
348    arm_idx: usize,
349    interior: &[NodeId],
350    backend: BackendId,
351    judge: Option<&dyn JudgeOracle>,
352) -> Option<u64> {
353    // No oracle ⇒ the Layer-1-only provider, byte-identical to today. The
354    // no-Judge production path + the persistent byte-exact suites are
355    // unaffected by construction.
356    let Some(judge) = judge else {
357        return decode_arm_composite_ns(graph, branch, arm_idx, interior, backend);
358    };
359
360    // Layer-2 FIRST, per interior node, with a Layer-1 fallback (the hybrid
361    // sum): a measured wall-clock latency is used directly (same convention as
362    // `compute_static_costs`'s `kernel_overhead_ns` fold); an unmeasured node
363    // falls back to its Layer-1 composite. Summed as sequential launches so the
364    // fused arm's single measured launch is compared against the region's `N`
365    // measured/Layer-1 launches apples-to-apples.
366    let (compute_rate, mem_bw) = default_backend_rates(backend);
367    let caps = neutral_caps(backend, compute_rate, mem_bw);
368    let mut total_ns: u64 = 0;
369    let mut any = false;
370    for &nid in interior {
371        // A Judge measurement is evidence of capability (a cell exists only
372        // because the kernel ran), so a measured node is admissible even if the
373        // Layer-1 capability gate would decline it. The gate guards only the
374        // fallback below.
375        let ns = match node_measured_ns(graph, nid, backend, judge) {
376            Some(measured) => Some(measured),
377            None => node_layer1_cost(graph, nid, backend, &caps)
378                .map(|cost| composite_ns(&cost, compute_rate, mem_bw)),
379        };
380        if let Some(ns) = ns {
381            any = true;
382            total_ns = total_ns.saturating_add(ns);
383        }
384    }
385    if !any || total_ns == 0 {
386        return None; // nothing costable ⇒ oracle stands (no spurious zero win)
387    }
388    Some(total_ns)
389}
390
391/// The measured (Layer-2) latency for one interior node's Judge cell, keyed the
392/// SAME way the ranker + Judge producer key it: `(op, principal_dtype,
393/// SizeClass::for_op(op, input_shapes), backend, "")`. `None` when the node has
394/// no [`op_to_op_kind`] mapping (a view/leaf) or the Judge hasn't measured that
395/// cell. The principal dtype is the first operand's dtype (the
396/// [`crate::ranker::cost::compute_static_costs`] convention), so a matmul /
397/// flash cell the Judge profiled is found by the SAME `for_op` key here.
398fn node_measured_ns(
399    graph: &Graph,
400    nid: NodeId,
401    backend: BackendId,
402    judge: &dyn JudgeOracle,
403) -> Option<u64> {
404    let node = graph.node(nid);
405    let kind = op_to_op_kind(&node.op)?;
406    let principal_dtype = match node.inputs.first() {
407        Some(&i) => graph.node(i).dtype,
408        None => node.dtype, // nullary — has no OpKind mapping anyway
409    };
410    let input_shapes: Vec<Shape> = node
411        .inputs
412        .iter()
413        .map(|&i| graph.node(i).shape.clone())
414        .collect();
415    let size_class = SizeClass::for_op(kind, &input_shapes);
416    judge.measured_latency_ns(kind, principal_dtype, size_class, backend, "", 0)
417}
418
419/// Layer-1 [`CostEstimate`] for one interior node (see [`decode_arm_composite_ns`]).
420/// `None` for a node that carries no priceable compute (a view/leaf, or a
421/// flash arm whose kernel is not bound — the capability gate).
422fn node_layer1_cost(
423    graph: &Graph,
424    nid: NodeId,
425    backend: BackendId,
426    caps: &BackendCapabilities,
427) -> Option<CostEstimate> {
428    let node = graph.node(nid);
429    match &node.op {
430        // The fused flash decode arm: priced by its declared decode cost,
431        // gated on the CUDA flash kernel being bound (capability).
432        Op::Fused(fid, params) if *fid == FusedOps::FLASH_ATTN => {
433            if !fused_kernel_available(FusedOps::FLASH_ATTN, backend) {
434                return None; // capability-missing ⇒ arm cannot win
435            }
436            let op_params = flash_op_params(graph, node, params)?;
437            let dtypes = [node.dtype, node.dtype];
438            Some(cost_flash_decoding_cuda(&[], &dtypes, &op_params, caps))
439        }
440        // MatMul — the dominant decode-region cost; geometry from shapes.
441        Op::MatMul => {
442            let op_params = matmul_op_params(graph, node)?;
443            let dtypes = [node.dtype, node.dtype, node.dtype];
444            Some(cost_matmul_cpu(&[], &dtypes, &op_params, caps))
445        }
446        // Any other primitive with an OpKind mapping: its Layer-1 family at
447        // the shape-derivable floor (OpParams::None), per the fused_cost
448        // precedent. Shapes follow `[input1, .., inputN, output]`.
449        other => {
450            let kind = op_to_op_kind(other)?;
451            let mut shapes: Vec<Shape> = node
452                .inputs
453                .iter()
454                .map(|&i| graph.node(i).shape.clone())
455                .collect();
456            shapes.push(node.shape.clone());
457            let mut dtypes: Vec<DType> = node.inputs.iter().map(|&i| graph.node(i).dtype).collect();
458            dtypes.push(node.dtype);
459            Some(default_cost_for_op_kind(kind)(
460                &shapes,
461                &dtypes,
462                &OpParams::None,
463                caps,
464            ))
465        }
466    }
467}
468
469/// Derive `OpParams::Matmul` geometry from a `MatMul` node's operand shapes:
470/// `A[.., m, k] · B[.., k, n] → [.., m, n]`. `None` if either operand is
471/// rank < 2 (nothing to cost).
472fn matmul_op_params(graph: &Graph, node: &fuel_graph::Node) -> Option<OpParams> {
473    let a = graph.node(*node.inputs.first()?).shape.clone();
474    let b = graph.node(*node.inputs.get(1)?).shape.clone();
475    let ad = a.dims();
476    let bd = b.dims();
477    if ad.len() < 2 || bd.len() < 2 {
478        return None;
479    }
480    let m = ad[ad.len() - 2];
481    let k = ad[ad.len() - 1];
482    let n = bd[bd.len() - 1];
483    let lhs_batch_dims: Vec<usize> = ad[..ad.len() - 2].to_vec();
484    let rhs_batch_dims: Vec<usize> = bd[..bd.len() - 2].to_vec();
485    // Cost/bake geometry only — the row count is the capacity `m` (a
486    // dynamic-M matmul costs at its capacity, a safe over-estimate).
487    Some(OpParams::Matmul {
488        lhs_batch_dims,
489        rhs_batch_dims,
490        m,
491        n,
492        k,
493        m_compute: crate::kernel::MatmulM::All,
494    })
495}
496
497/// Derive `OpParams::FlashAttn` for the decode cost from the flash node's
498/// `[q, k, v, ..]` inputs + its `FusedOpParams::FlashAttn`. `q = [b, hq, sq, d]`,
499/// `k = [b, hkv, sk, d]`. A symbolic `k_len` prices at the KV capacity `sk`
500/// (the representative prefix — see [`decode_arm_composite_ns`]).
501fn flash_op_params(
502    graph: &Graph,
503    node: &fuel_graph::Node,
504    params: &FusedOpParams,
505) -> Option<OpParams> {
506    let FusedOpParams::FlashAttn {
507        softmax_scale,
508        causal,
509        window_size_left,
510        window_size_right,
511        softcap,
512        k_len,
513    } = params
514    else {
515        return None;
516    };
517    let q = graph.node(*node.inputs.first()?).shape.clone();
518    let kv = graph.node(*node.inputs.get(1)?).shape.clone();
519    let qd = q.dims();
520    let kvd = kv.dims();
521    if qd.len() != 4 || kvd.len() != 4 {
522        return None;
523    }
524    let (b, hq, sq, d) = (qd[0], qd[1], qd[2], qd[3]);
525    let hkv = kvd[1];
526    let sk = kvd[2];
527    // Symbolic prefix ⇒ price at the capacity (representative extent).
528    let k_len_val = match k_len {
529        Some(DynScalar::Concrete(v)) => *v,
530        _ => sk,
531    };
532    Some(OpParams::FlashAttn {
533        b,
534        hq,
535        hkv,
536        sq,
537        sk,
538        d,
539        k_len: k_len_val,
540        softmax_scale: *softmax_scale,
541        causal: *causal,
542        window_size_left: *window_size_left,
543        window_size_right: *window_size_right,
544        softcap: *softcap,
545    })
546}
547
548/// A minimal [`BackendCapabilities`] carrying only the backend id + its
549/// throughput rates — the Layer-1 cost families ignore the rest of the struct;
550/// the roofline rates flow through [`composite_ns`] separately.
551fn neutral_caps(backend: BackendId, compute: f64, mem_bw: f64) -> BackendCapabilities {
552    BackendCapabilities {
553        backend_id: backend,
554        device_location: DeviceLocation::Cpu,
555        op_dtype_support: HashSet::new(),
556        required_alignment: 1,
557        access_granularity_bits: 8,
558        transfer_paths: vec![(DeviceLocation::Cpu, TransferPath::SameDevice)],
559        storage_substrate: SubstrateClass::HostBytes,
560        compute_throughput_flops_per_ns: compute,
561        mem_bandwidth_bytes_per_ns: mem_bw,
562    }
563}
564
565#[cfg(test)]
566mod tests {
567    use super::*;
568    use crate::ranker::judge::HashMapJudge;
569    use fuel_graph::{Node, lower_runs_arm0};
570    use fuel_ir::Shape;
571    use fuel_ir::dispatch::OpKind;
572
573    fn node(g: &mut Graph, op: Op, inputs: Vec<NodeId>, dims: &[usize], dt: DType) -> NodeId {
574        g.push(Node {
575            op,
576            inputs,
577            shape: Shape::from_dims(dims),
578            dtype: dt,
579        })
580    }
581
582    /// Build a same-device 2-arm variant branch mirroring the decode flash
583    /// shape: arm 0 is a 2-node "decomposed region" (Relu→Silu over the
584    /// diverge), arm 1 is a single "fused variant" node (Gelu). Both arms are
585    /// stamped `backend`. Returns `(graph, branch, arm0_exit, arm1, reconverge, post)`.
586    fn variant_diamond(backend: BackendId) -> (Graph, NodeId, NodeId, NodeId, NodeId, NodeId) {
587        let dt = DType::F32;
588        let mut g = Graph::new();
589        let pre = node(&mut g, Op::Const, vec![], &[4], dt);
590        let diverge = node(&mut g, Op::Relu, vec![pre], &[4], dt);
591        // arm 0 = a 2-node decomposed region.
592        let a0_mid = node(&mut g, Op::Relu, vec![diverge], &[4], dt);
593        let arm0 = node(&mut g, Op::Silu, vec![a0_mid], &[4], dt);
594        // arm 1 = a single fused-variant node.
595        let arm1 = node(&mut g, Op::GeluTanh, vec![diverge], &[4], dt);
596        g.set_target_backend(a0_mid, backend);
597        g.set_target_backend(arm0, backend);
598        g.set_target_backend(arm1, backend);
599        let reconverge = node(&mut g, Op::Relu, vec![arm0], &[4], dt);
600        let mut b = g.open_branch(diverge);
601        b.add_arm(arm0);
602        b.add_arm(arm1);
603        let branch = b
604            .finalize_branches(&mut g, reconverge)
605            .expect("well-formed 2-arm branch")
606            .expect("2 arms survive");
607        let post = node(&mut g, Op::Tanh, vec![reconverge], &[4], dt);
608        (g, branch, arm0, arm1, reconverge, post)
609    }
610
611    /// A cost closure that returns fixed per-arm costs by arm index.
612    fn fixed_costs(
613        costs: Vec<Option<u64>>,
614    ) -> impl Fn(&Graph, NodeId, usize, &[NodeId]) -> Option<u64> {
615        move |_g, _b, arm, _interior| costs.get(arm).copied().flatten()
616    }
617
618    // ===================================================================
619    // BORN-RED: a same-device variant arm is NEVER selected today (the
620    // runtime picker resolves same-device arms to arm 0). The bake makes
621    // the cheaper variant SELECTABLE by collapsing the branch to it.
622    // ===================================================================
623    #[test]
624    fn cheaper_variant_is_baked_and_becomes_the_route() {
625        let (mut g, branch, arm0, arm1, reconverge, post) = variant_diamond(BackendId::Cuda);
626
627        // (RED anchor) Before the bake, the default lowering realizes arm 0 —
628        // the same-device variant (arm 1) is offered but never selected.
629        let before = lower_runs_arm0(&g, &[post]);
630        assert!(
631            before.contains(&arm0) && !before.contains(&arm1),
632            "before the bake the same-device variant is never selected (arm 0 wins)",
633        );
634
635        // (GREEN) The variant (arm 1) is strictly cheaper ⇒ the bake collapses
636        // the branch to it.
637        let cost = fixed_costs(vec![Some(1000), Some(400)]); // arm0=1000, arm1=400
638        let baked = bake_variant_branches(&mut g, &[post], &cost);
639        assert_eq!(baked, 1, "one variant branch baked to its winner");
640
641        // The merge now reads the winner; the branch is collapsed.
642        assert!(
643            g.node(reconverge).inputs.contains(&arm1),
644            "merge rewired to the variant"
645        );
646        assert_eq!(
647            g.node(branch).inputs,
648            vec![arm1],
649            "branch collapsed to the winner"
650        );
651
652        // The default lowering now follows the baked variant (arm 1) and prunes
653        // arm 0's region — selectable with NO runtime pick.
654        let after = lower_runs_arm0(&g, &[post]);
655        assert!(
656            after.contains(&arm1),
657            "after the bake the variant is realized; order={after:?}"
658        );
659        assert!(
660            !after.contains(&arm0),
661            "arm 0's region is pruned; order={after:?}"
662        );
663    }
664
665    /// The `variant_bakes_thread_local` telemetry tracks the return value: a
666    /// winning-variant bake bumps the counter by 1, an arm-0 (oracle-wins) bake
667    /// leaves it unchanged. This is the seam a live BF16-CUDA-decode bench/test
668    /// reads to confirm the flash-decode arm was actually PICKED (baked to the
669    /// fused variant), not merely offered.
670    #[test]
671    fn variant_bakes_thread_local_tracks_the_return() {
672        // A winning variant ⇒ +1.
673        let before = variant_bakes_thread_local();
674        let (mut g1, _b1, _a0, _a1, _r1, post1) = variant_diamond(BackendId::Cuda);
675        let win = fixed_costs(vec![Some(1000), Some(400)]); // arm1 strictly cheaper
676        let baked = bake_variant_branches(&mut g1, &[post1], &win);
677        assert_eq!(baked, 1);
678        assert_eq!(
679            variant_bakes_thread_local() - before,
680            1,
681            "a winning-variant bake bumps the thread-local by its return count",
682        );
683
684        // Arm 0 wins (costlier variant) ⇒ counter unchanged.
685        let mid = variant_bakes_thread_local();
686        let (mut g2, _b2, _a0b, _a1b, _r2, post2) = variant_diamond(BackendId::Cuda);
687        let lose = fixed_costs(vec![Some(400), Some(1000)]); // arm1 costlier
688        let baked2 = bake_variant_branches(&mut g2, &[post2], &lose);
689        assert_eq!(baked2, 0);
690        assert_eq!(
691            variant_bakes_thread_local(),
692            mid,
693            "an oracle-wins bake leaves the thread-local unchanged",
694        );
695    }
696
697    /// GUARD: a costlier variant ⇒ arm 0 (the oracle). The branch collapses to
698    /// arm 0 (variant pruned), realize is byte-identical to today.
699    #[test]
700    fn costlier_variant_keeps_arm0() {
701        let (mut g, branch, arm0, arm1, _recon, post) = variant_diamond(BackendId::Cuda);
702        let cost = fixed_costs(vec![Some(400), Some(1000)]); // arm1 costlier
703        let baked = bake_variant_branches(&mut g, &[post], &cost);
704        assert_eq!(baked, 0, "no variant wins ⇒ nothing baked to a variant");
705        assert_eq!(
706            g.node(branch).inputs,
707            vec![arm0],
708            "branch collapsed to arm 0"
709        );
710        let after = lower_runs_arm0(&g, &[post]);
711        assert!(
712            after.contains(&arm0) && !after.contains(&arm1),
713            "arm 0 realized (oracle)"
714        );
715    }
716
717    /// GUARD: an unknown / sentinel variant cost ⇒ arm 0. `None` cannot win.
718    #[test]
719    fn unknown_variant_cost_keeps_arm0() {
720        let (mut g, _branch, arm0, arm1, _recon, post) = variant_diamond(BackendId::Cuda);
721        let cost = fixed_costs(vec![Some(1000), None]); // arm1 unknown
722        let baked = bake_variant_branches(&mut g, &[post], &cost);
723        assert_eq!(baked, 0, "unknown variant cost ⇒ arm 0 (conservative)");
724        let after = lower_runs_arm0(&g, &[post]);
725        assert!(
726            after.contains(&arm0) && !after.contains(&arm1),
727            "arm 0 realized"
728        );
729    }
730
731    /// GUARD: a tie between the oracle and the variant ⇒ arm 0.
732    #[test]
733    fn tie_keeps_arm0() {
734        let (mut g, _branch, arm0, arm1, _recon, post) = variant_diamond(BackendId::Cuda);
735        let cost = fixed_costs(vec![Some(500), Some(500)]); // equal ⇒ not strictly cheaper
736        let baked = bake_variant_branches(&mut g, &[post], &cost);
737        assert_eq!(baked, 0, "tie ⇒ arm 0 (variant not strictly cheaper)");
738        let after = lower_runs_arm0(&g, &[post]);
739        assert!(
740            after.contains(&arm0) && !after.contains(&arm1),
741            "arm 0 realized"
742        );
743    }
744
745    /// GUARD: capability-missing (modelled as a `None` variant cost, the way
746    /// [`decode_arm_composite_ns`] surfaces an unbound flash kernel) ⇒ arm 0.
747    #[test]
748    fn capability_missing_keeps_arm0() {
749        let (mut g, _branch, arm0, arm1, _recon, post) = variant_diamond(BackendId::Cuda);
750        // A provider that declines the variant arm (capability gate) but prices
751        // the oracle — exactly the None the flash capability gate returns.
752        let cost = |_g: &Graph, _b: NodeId, arm: usize, _i: &[NodeId]| -> Option<u64> {
753            if arm == 0 { Some(1000) } else { None }
754        };
755        let baked = bake_variant_branches(&mut g, &[post], &cost);
756        assert_eq!(baked, 0, "capability-missing variant ⇒ arm 0");
757        let after = lower_runs_arm0(&g, &[post]);
758        assert!(
759            after.contains(&arm0) && !after.contains(&arm1),
760            "arm 0 realized"
761        );
762    }
763
764    /// GUARD: a **placement** branch (arms on DIFFERENT backends) is UNTOUCHED
765    /// — it stays a live 2-arm decision point for the runtime picker, even
766    /// when the variant-shaped cost would prefer arm 1. The bake only ever
767    /// collapses same-device branches.
768    #[test]
769    fn placement_branch_is_untouched() {
770        let (mut g, branch, arm0, arm1, _recon, post) = variant_diamond(BackendId::Cuda);
771        // Re-stamp arm 1 onto a DIFFERENT backend ⇒ placement branch.
772        g.set_target_backend(arm1, BackendId::Cpu);
773        let cost = fixed_costs(vec![Some(1000), Some(1)]); // arm1 "cheaper", but placement
774        let baked = bake_variant_branches(&mut g, &[post], &cost);
775        assert_eq!(baked, 0, "a placement branch is never baked");
776        assert_eq!(
777            g.node(branch).inputs,
778            vec![arm0, arm1],
779            "placement branch stays a live 2-arm decision point (runtime picker owns it)",
780        );
781    }
782
783    /// GUARD: an unstamped branch (arms with no `target_backend`) is skipped —
784    /// not a determinate same-device variant branch.
785    #[test]
786    fn unstamped_branch_is_skipped() {
787        let dt = DType::F32;
788        let mut g = Graph::new();
789        let pre = node(&mut g, Op::Const, vec![], &[4], dt);
790        let diverge = node(&mut g, Op::Relu, vec![pre], &[4], dt);
791        let a0_mid = node(&mut g, Op::Relu, vec![diverge], &[4], dt);
792        let arm0 = node(&mut g, Op::Silu, vec![a0_mid], &[4], dt);
793        let arm1 = node(&mut g, Op::GeluTanh, vec![diverge], &[4], dt);
794        // NO target_backend stamps on the arms.
795        let reconverge = node(&mut g, Op::Relu, vec![arm0], &[4], dt);
796        let mut b = g.open_branch(diverge);
797        b.add_arm(arm0);
798        b.add_arm(arm1);
799        let branch = b.finalize_branches(&mut g, reconverge).unwrap().unwrap();
800        let post = node(&mut g, Op::Tanh, vec![reconverge], &[4], dt);
801        let cost = fixed_costs(vec![Some(1000), Some(1)]);
802        let baked = bake_variant_branches(&mut g, &[post], &cost);
803        assert_eq!(baked, 0, "unstamped branch is skipped");
804        assert_eq!(g.node(branch).inputs, vec![arm0, arm1], "branch untouched");
805    }
806
807    // ===================================================================
808    // The PRODUCTION cost provider: a decomposed attention region vs. the
809    // fused flash arm — flash WINS on the region-vs-fused Layer-1 fold.
810    // ===================================================================
811
812    /// The **region-vs-fused costing approach**, priced honestly. The
813    /// production provider folds a real Layer-1 cost over BOTH arm kinds — the
814    /// decomposed region (matmul-dominated fold) and the fused flash arm
815    /// (declared decode cost from derived `OpParams`). This proves the costing
816    /// path end-to-end; it deliberately does NOT force flash to "win" on
817    /// Layer-1: `cost_flash_decoding_cuda` gives flash the SAME FLOPs as the
818    /// region's two matmuls (they compute the same attention), so on the
819    /// coarse Layer-1 model the two are ~cost-equal and the conservative bake
820    /// keeps the oracle (arm 0). Flash's real win is an *algorithm-changing*
821    /// fusion (no materialized attention matrix, one launch) that the Judge's
822    /// Layer-2 measurement corrects downward — "a missed win until measured,
823    /// not an optimistic irreversible commit" (04-optimization).
824    #[test]
825    fn region_and_flash_arms_are_both_priced_by_the_provider() {
826        let (b, hq, d, sk) = (1usize, 8, 128, 512);
827        let dt = DType::F16;
828        let mut g = Graph::new();
829        let q = node(&mut g, Op::Const, vec![], &[b, hq, 1, d], dt);
830        let k = node(&mut g, Op::Const, vec![], &[b, hq, sk, d], dt);
831        let v = node(&mut g, Op::Const, vec![], &[b, hq, sk, d], dt);
832
833        // Decomposed region interior (two matmuls dominate).
834        let kt = node(
835            &mut g,
836            Op::Permute(vec![0, 1, 3, 2]),
837            vec![k],
838            &[b, hq, d, sk],
839            dt,
840        );
841        let scores = node(&mut g, Op::MatMul, vec![q, kt], &[b, hq, 1, sk], dt);
842        let attn = node(&mut g, Op::MatMul, vec![scores, v], &[b, hq, 1, d], dt);
843        let region: Vec<NodeId> = vec![kt, scores, attn];
844
845        // (1) The region folds to a real, nonzero composite cost — no binding
846        // needed (pure shape/FLOP fold).
847        let region_ns = decode_arm_composite_ns(&g, NodeId(0), 0, &region, BackendId::Cuda)
848            .expect("the decomposed region has costable compute (its two matmuls)");
849        assert!(region_ns > 0, "region prices to a real nonzero cost");
850
851        // (2) The fused flash arm's DECLARED decode cost, priced directly from
852        // derived OpParams (the provider's capability gate is bypassed here so
853        // the costing path is exercised on any build, incl. no-CUDA).
854        let flash_node = Node {
855            op: Op::Fused(
856                FusedOps::FLASH_ATTN,
857                FusedOpParams::FlashAttn {
858                    softmax_scale: 0.1,
859                    causal: true,
860                    window_size_left: None,
861                    window_size_right: None,
862                    softcap: None,
863                    k_len: Some(DynScalar::Concrete(sk)),
864                },
865            ),
866            inputs: vec![q, k, v],
867            shape: Shape::from_dims(&[b, hq, 1, d]),
868            dtype: dt,
869        };
870        let (cr, bw) = default_backend_rates(BackendId::Cuda);
871        let caps = neutral_caps(BackendId::Cuda, cr, bw);
872        let fp_full = decode_flash_cost_at(&g, &flash_node, sk, &caps, cr, bw);
873        let fp_small = decode_flash_cost_at(&g, &flash_node, 32, &caps, cr, bw);
874        assert!(
875            fp_full > 0 && fp_small > 0,
876            "flash decode cost is real + nonzero"
877        );
878        assert!(
879            fp_full > fp_small,
880            "the flash decode cost scales with the live prefix k_len \
881             ({fp_full} @512 > {fp_small} @32) — decode work is O(prefix)",
882        );
883
884        // (3) The provider's capability gate: without a bound CUDA flash kernel
885        // the flash ARM is inadmissible (None) ⇒ the oracle stands. (In a live
886        // CUDA build the kernel is bound and the arm prices instead.)
887        let flash = node(
888            &mut g,
889            Op::Fused(
890                FusedOps::FLASH_ATTN,
891                FusedOpParams::FlashAttn {
892                    softmax_scale: 0.1,
893                    causal: true,
894                    window_size_left: None,
895                    window_size_right: None,
896                    softcap: None,
897                    k_len: Some(DynScalar::Concrete(sk)),
898                },
899            ),
900            vec![q, k, v],
901            &[b, hq, 1, d],
902            dt,
903        );
904        let gated = decode_arm_composite_ns(&g, NodeId(0), 1, &[flash], BackendId::Cuda);
905        if fused_kernel_available(FusedOps::FLASH_ATTN, BackendId::Cuda) {
906            assert!(gated.is_some(), "bound flash kernel ⇒ arm priced");
907        } else {
908            assert!(
909                gated.is_none(),
910                "unbound flash kernel ⇒ arm inadmissible (oracle stands)"
911            );
912        }
913    }
914
915    /// Helper: the flash decode composite-ns at a given prefix (bypasses the
916    /// capability gate to exercise the declared-cost path on any build).
917    fn decode_flash_cost_at(
918        g: &Graph,
919        flash_node: &Node,
920        k_len: usize,
921        caps: &BackendCapabilities,
922        cr: f64,
923        bw: f64,
924    ) -> u64 {
925        let params = FusedOpParams::FlashAttn {
926            softmax_scale: 0.1,
927            causal: true,
928            window_size_left: None,
929            window_size_right: None,
930            softcap: None,
931            k_len: Some(DynScalar::Concrete(k_len)),
932        };
933        let op_params = flash_op_params(g, flash_node, &params).expect("derivable");
934        let dtypes = [flash_node.dtype, flash_node.dtype];
935        let cost = cost_flash_decoding_cuda(&[], &dtypes, &op_params, caps);
936        composite_ns(&cost, cr, bw)
937    }
938
939    /// The flash `OpParams` derivation prices a symbolic `k_len` at the KV
940    /// capacity (the representative prefix), so a plan-once persistent-decode
941    /// bake still produces a concrete, stable cost.
942    #[test]
943    fn symbolic_k_len_prices_at_capacity() {
944        let (b, hq, d, sk) = (1usize, 4, 64, 256);
945        let dt = DType::F16;
946        let mut g = Graph::new();
947        let q = node(&mut g, Op::Const, vec![], &[b, hq, 1, d], dt);
948        let k = node(&mut g, Op::Const, vec![], &[b, hq, sk, d], dt);
949        let v = node(&mut g, Op::Const, vec![], &[b, hq, sk, d], dt);
950        let flash = node(
951            &mut g,
952            Op::Fused(
953                FusedOps::FLASH_ATTN,
954                FusedOpParams::FlashAttn {
955                    softmax_scale: 0.1,
956                    causal: true,
957                    window_size_left: None,
958                    window_size_right: None,
959                    softcap: None,
960                    // Symbolic prefix (persistent decode).
961                    k_len: Some(DynScalar::Sym(fuel_ir::symbol::SymId(0))),
962                },
963            ),
964            vec![q, k, v],
965            &[b, hq, 1, d],
966            dt,
967        );
968        let flash_node = g.node(flash).clone();
969        let params_in = match &flash_node.op {
970            Op::Fused(_, p) => p.clone(),
971            _ => unreachable!(),
972        };
973        let params = flash_op_params(&g, &flash_node, &params_in).expect("derivable");
974        match params {
975            OpParams::FlashAttn {
976                k_len,
977                sk: sk_out,
978                sq,
979                ..
980            } => {
981                assert_eq!(k_len, sk, "symbolic k_len prices at the capacity");
982                assert_eq!(sk_out, sk);
983                assert_eq!(sq, 1, "decode sq == 1");
984            }
985            _ => panic!("expected FlashAttn params"),
986        }
987    }
988
989    // ===================================================================
990    // SLICE 4 (THE PAYOFF): the variant bake consults the Judge's MEASURED
991    // latency (Layer-2) per arm, so the CUDA flash arm WINS the
992    // decode-flash-vs-decomposed bake where it merely TIES on Layer-1. With
993    // an injected oracle this proves the SELECTION logic on a CPU build (no
994    // live GPU): the born-red flips arm 0 → arm 1 the moment the provider
995    // reads the Judge.
996    // ===================================================================
997
998    /// A same-device (CUDA) 2-arm DECODE variant branch mirroring the real
999    /// decode-flash bake: arm 0 is the decomposed attention region
1000    /// (`Permute` → `MatMul` QKᵀ → `MatMul` PV), arm 1 is the fused
1001    /// `FlashAttn` node. `q` is a `Relu` over a const so a single Op::Branch
1002    /// diverge point dominates both arm exits; both arm exits are stamped
1003    /// CUDA (same-device). Returns
1004    /// `(graph, branch, region_exit, flash_exit, reconverge, post)`.
1005    fn flash_variant_diamond() -> (Graph, NodeId, NodeId, NodeId, NodeId, NodeId) {
1006        let (b, hq, d, sk) = (1usize, 8, 128, 512);
1007        let dt = DType::F16;
1008        let mut g = Graph::new();
1009        let qc = node(&mut g, Op::Const, vec![], &[b, hq, 1, d], dt);
1010        let k = node(&mut g, Op::Const, vec![], &[b, hq, sk, d], dt);
1011        let v = node(&mut g, Op::Const, vec![], &[b, hq, sk, d], dt);
1012        // The single DIVERGE point both arms read as their `q` operand.
1013        let q = node(&mut g, Op::Relu, vec![qc], &[b, hq, 1, d], dt);
1014        // arm 0 — the decomposed attention region (two matmuls dominate).
1015        let kt = node(
1016            &mut g,
1017            Op::Permute(vec![0, 1, 3, 2]),
1018            vec![k],
1019            &[b, hq, d, sk],
1020            dt,
1021        );
1022        let scores = node(&mut g, Op::MatMul, vec![q, kt], &[b, hq, 1, sk], dt);
1023        let attn = node(&mut g, Op::MatMul, vec![scores, v], &[b, hq, 1, d], dt);
1024        // arm 1 — the fused flash node (same exit shape & dtype as the region).
1025        let flash = node(
1026            &mut g,
1027            Op::Fused(
1028                FusedOps::FLASH_ATTN,
1029                FusedOpParams::FlashAttn {
1030                    softmax_scale: 0.1,
1031                    causal: true,
1032                    window_size_left: None,
1033                    window_size_right: None,
1034                    softcap: None,
1035                    k_len: Some(DynScalar::Concrete(sk)),
1036                },
1037            ),
1038            vec![q, k, v],
1039            &[b, hq, 1, d],
1040            dt,
1041        );
1042        // Same-device stamps — the bake's same-device gate reads the arm exits.
1043        g.set_target_backend(kt, BackendId::Cuda);
1044        g.set_target_backend(scores, BackendId::Cuda);
1045        g.set_target_backend(attn, BackendId::Cuda);
1046        g.set_target_backend(flash, BackendId::Cuda);
1047        let reconverge = node(&mut g, Op::Relu, vec![attn], &[b, hq, 1, d], dt);
1048        let mut br = g.open_branch(q);
1049        br.add_arm(attn);
1050        br.add_arm(flash);
1051        let branch = br
1052            .finalize_branches(&mut g, reconverge)
1053            .expect("well-formed 2-arm decode branch")
1054            .expect("2 arms survive");
1055        let post = node(&mut g, Op::Tanh, vec![reconverge], &[b, hq, 1, d], dt);
1056        (g, branch, attn, flash, reconverge, post)
1057    }
1058
1059    /// The decode-shape Judge keys, single-sourced through the SAME helpers
1060    /// the bake's `for_op` derivation and the fuel-core Judge producer use:
1061    /// scores QKᵀ = `matmul(m=1, n=sk, k=d)`, attn PV = `matmul(m=1, n=d,
1062    /// k=sk)`, flash = `attention(hq, k_len=sk, d)`.
1063    fn decode_keys() -> (SizeClass, SizeClass, SizeClass) {
1064        let (hq, d, sk) = (8usize, 128, 512);
1065        (
1066            SizeClass::matmul(1, sk, d), // scores
1067            SizeClass::matmul(1, d, sk), // attn
1068            SizeClass::attention(hq, sk, d),
1069        )
1070    }
1071
1072    /// **BORN-RED (the arc headline).** A measured flash cell that is strictly
1073    /// cheaper than the region's summed measured primitives flips the bake from
1074    /// arm 0 to arm 1. RED before the Layer-2 wiring (the flash arm ties / is
1075    /// gated on Layer-1 ⇒ arm 0 kept); GREEN after (measured flash wins).
1076    #[test]
1077    fn judge_measured_flash_wins_the_decode_bake() {
1078        let (mut g, branch, attn, flash, reconverge, post) = flash_variant_diamond();
1079        let dt = DType::F16;
1080        let (k_scores, k_attn, k_flash) = decode_keys();
1081
1082        // (RED anchor) the default lowering realizes the decomposed region.
1083        let before = lower_runs_arm0(&g, &[post]);
1084        assert!(
1085            before.contains(&attn) && !before.contains(&flash),
1086            "before the bake the decomposed region wins (arm 0); order={before:?}",
1087        );
1088
1089        // Injected Judge: flash measures CHEAPER (400 ns) than the region's two
1090        // measured matmuls (500 + 500 = 1000 ns) — flash's algorithm-changing
1091        // win Layer-1 can't see (FLOP tie / CPU-build capability gate).
1092        let mut judge = HashMapJudge::new();
1093        judge.insert(OpKind::MatMul, dt, k_scores, BackendId::Cuda, "", 500, 0);
1094        judge.insert(OpKind::MatMul, dt, k_attn, BackendId::Cuda, "", 500, 0);
1095        judge.insert(OpKind::FlashAttn, dt, k_flash, BackendId::Cuda, "", 400, 0);
1096
1097        let cost = |g: &Graph, b: NodeId, arm: usize, i: &[NodeId]| -> Option<u64> {
1098            decode_arm_composite_ns_judged(g, b, arm, i, BackendId::Cuda, Some(&judge))
1099        };
1100        let baked = bake_variant_branches(&mut g, &[post], &cost);
1101
1102        assert_eq!(
1103            baked, 1,
1104            "measured flash is strictly cheaper ⇒ the branch bakes to it"
1105        );
1106        assert_eq!(
1107            g.node(branch).inputs,
1108            vec![flash],
1109            "branch collapsed to the flash arm"
1110        );
1111        assert!(
1112            g.node(reconverge).inputs.contains(&flash),
1113            "merge rewired to flash"
1114        );
1115
1116        let after = lower_runs_arm0(&g, &[post]);
1117        assert!(
1118            after.contains(&flash),
1119            "flash realized after the bake; order={after:?}"
1120        );
1121        assert!(
1122            !after.contains(&attn),
1123            "the decomposed region is pruned; order={after:?}"
1124        );
1125    }
1126
1127    /// GUARD: the Judge says flash is SLOWER than the region ⇒ arm 0 (the
1128    /// conservative oracle default holds — a measurement never optimistically
1129    /// commits a losing variant).
1130    #[test]
1131    fn judge_measured_flash_slower_keeps_the_region() {
1132        let (mut g, branch, attn, flash, _recon, post) = flash_variant_diamond();
1133        let dt = DType::F16;
1134        let (k_scores, k_attn, k_flash) = decode_keys();
1135        let mut judge = HashMapJudge::new();
1136        judge.insert(OpKind::MatMul, dt, k_scores, BackendId::Cuda, "", 500, 0);
1137        judge.insert(OpKind::MatMul, dt, k_attn, BackendId::Cuda, "", 500, 0);
1138        judge.insert(OpKind::FlashAttn, dt, k_flash, BackendId::Cuda, "", 2000, 0);
1139        let cost = |g: &Graph, b: NodeId, arm: usize, i: &[NodeId]| -> Option<u64> {
1140            decode_arm_composite_ns_judged(g, b, arm, i, BackendId::Cuda, Some(&judge))
1141        };
1142        let baked = bake_variant_branches(&mut g, &[post], &cost);
1143        assert_eq!(
1144            baked, 0,
1145            "measured flash is slower ⇒ arm 0 (the region) stands"
1146        );
1147        assert_eq!(
1148            g.node(branch).inputs,
1149            vec![attn],
1150            "branch collapsed to arm 0"
1151        );
1152        let after = lower_runs_arm0(&g, &[post]);
1153        assert!(
1154            after.contains(&attn) && !after.contains(&flash),
1155            "region realized (oracle)"
1156        );
1157    }
1158
1159    /// GUARD: with `judge == None` the judged provider is **byte-identical** to
1160    /// the Layer-1-only provider per arm (the no-Judge production path + the
1161    /// persistent byte-exact suites stay untouched by construction), and the
1162    /// bake keeps arm 0.
1163    #[test]
1164    fn no_oracle_is_byte_identical_to_layer1() {
1165        let (mut g, branch, attn, flash, _recon, post) = flash_variant_diamond();
1166        let interiors = arm_interiors(&g, branch);
1167        for (arm, interior) in interiors.iter().enumerate() {
1168            assert_eq!(
1169                decode_arm_composite_ns_judged(&g, branch, arm, interior, BackendId::Cuda, None),
1170                decode_arm_composite_ns(&g, branch, arm, interior, BackendId::Cuda),
1171                "judged(None) must equal the Layer-1 provider for arm {arm}",
1172            );
1173        }
1174        let cost = |g: &Graph, b: NodeId, arm: usize, i: &[NodeId]| -> Option<u64> {
1175            decode_arm_composite_ns_judged(g, b, arm, i, BackendId::Cuda, None)
1176        };
1177        let baked = bake_variant_branches(&mut g, &[post], &cost);
1178        assert_eq!(
1179            baked, 0,
1180            "no oracle ⇒ Layer-1 path ⇒ arm 0 (flash unbound on a CPU build)"
1181        );
1182        assert_eq!(g.node(branch).inputs, vec![attn]);
1183        let _ = flash;
1184    }
1185
1186    /// GUARD (capability-missing, via the hybrid fallback): the Judge measured
1187    /// the region's matmuls but NOT the flash cell, so the flash arm falls back
1188    /// to Layer-1 where the capability gate (no bound CUDA flash kernel on a CPU
1189    /// build) makes it inadmissible ⇒ arm 0. A measurement is required to make
1190    /// an unbound-on-this-build variant admissible.
1191    #[test]
1192    fn judge_without_flash_cell_falls_to_capability_gate() {
1193        let (mut g, branch, attn, flash, _recon, post) = flash_variant_diamond();
1194        let dt = DType::F16;
1195        let (k_scores, k_attn, _k_flash) = decode_keys();
1196        let mut judge = HashMapJudge::new();
1197        judge.insert(OpKind::MatMul, dt, k_scores, BackendId::Cuda, "", 1, 0);
1198        judge.insert(OpKind::MatMul, dt, k_attn, BackendId::Cuda, "", 1, 0);
1199        let cost = |g: &Graph, b: NodeId, arm: usize, i: &[NodeId]| -> Option<u64> {
1200            decode_arm_composite_ns_judged(g, b, arm, i, BackendId::Cuda, Some(&judge))
1201        };
1202        let baked = bake_variant_branches(&mut g, &[post], &cost);
1203        if !fused_kernel_available(FusedOps::FLASH_ATTN, BackendId::Cuda) {
1204            assert_eq!(baked, 0, "no flash measurement + unbound kernel ⇒ arm 0");
1205            assert_eq!(g.node(branch).inputs, vec![attn]);
1206        }
1207        let _ = flash;
1208    }
1209
1210    /// GUARD (the hybrid sum): when only SOME of an arm's nodes are
1211    /// Judge-covered, measured cells and Layer-1 estimates are summed together.
1212    /// Here only the `scores` matmul is measured (500 ns); `attn` falls back to
1213    /// Layer-1. The region cost is exactly `500 + Layer-1(attn)`, and a cheaper
1214    /// measured flash still wins.
1215    #[test]
1216    fn hybrid_sum_mixes_measured_and_layer1_for_the_region() {
1217        let (mut g, branch, attn, flash, _recon, post) = flash_variant_diamond();
1218        let dt = DType::F16;
1219        let (k_scores, _k_attn, k_flash) = decode_keys();
1220        let mut judge = HashMapJudge::new();
1221        judge.insert(OpKind::MatMul, dt, k_scores, BackendId::Cuda, "", 500, 0); // scores only
1222        judge.insert(OpKind::FlashAttn, dt, k_flash, BackendId::Cuda, "", 400, 0);
1223
1224        // The region arm's hybrid cost == measured scores (500) + Layer-1 attn.
1225        let region = arm_interiors(&g, branch)[0].clone();
1226        let hybrid =
1227            decode_arm_composite_ns_judged(&g, branch, 0, &region, BackendId::Cuda, Some(&judge))
1228                .expect("region prices");
1229        let layer1_attn = decode_arm_composite_ns(&g, branch, 0, &[attn], BackendId::Cuda)
1230            .expect("attn prices on Layer-1");
1231        assert_eq!(
1232            hybrid,
1233            500 + layer1_attn,
1234            "hybrid region = measured scores (500) + Layer-1 attn ({layer1_attn})",
1235        );
1236
1237        // Flash (measured 400) is cheaper than the hybrid region ⇒ it wins.
1238        let cost = |g: &Graph, b: NodeId, arm: usize, i: &[NodeId]| -> Option<u64> {
1239            decode_arm_composite_ns_judged(g, b, arm, i, BackendId::Cuda, Some(&judge))
1240        };
1241        let baked = bake_variant_branches(&mut g, &[post], &cost);
1242        assert_eq!(
1243            baked, 1,
1244            "measured flash beats the hybrid region ⇒ bakes to flash"
1245        );
1246        assert_eq!(g.node(branch).inputs, vec![flash]);
1247    }
1248
1249    /// GUARD: a **placement** branch (arm exits on DIFFERENT backends) is never
1250    /// touched by the bake — even with a flash-loving Judge — because the
1251    /// same-device gate in `bake_variant_branches` skips it BEFORE the cost
1252    /// provider (and thus the Judge) is ever consulted. It stays a live 2-arm
1253    /// decision point for the runtime route picker.
1254    #[test]
1255    fn judge_does_not_touch_a_placement_branch() {
1256        let (mut g, branch, attn, flash, _recon, post) = flash_variant_diamond();
1257        // Re-stamp the flash arm onto a DIFFERENT backend ⇒ placement branch.
1258        g.set_target_backend(flash, BackendId::Cpu);
1259        let dt = DType::F16;
1260        let (_ks, _ka, k_flash) = decode_keys();
1261        let mut judge = HashMapJudge::new();
1262        judge.insert(OpKind::FlashAttn, dt, k_flash, BackendId::Cpu, "", 1, 0);
1263        let cost = |g: &Graph, b: NodeId, arm: usize, i: &[NodeId]| -> Option<u64> {
1264            let backend = g.target_backend(g.node(b).inputs.first().copied()?)?;
1265            decode_arm_composite_ns_judged(g, b, arm, i, backend, Some(&judge))
1266        };
1267        let baked = bake_variant_branches(&mut g, &[post], &cost);
1268        assert_eq!(
1269            baked, 0,
1270            "a placement branch is never baked, even with a flash-loving judge"
1271        );
1272        assert_eq!(
1273            g.node(branch).inputs,
1274            vec![attn, flash],
1275            "placement branch stays a live 2-arm decision point (runtime picker owns it)",
1276        );
1277    }
1278}