@@ -486,7 +486,12 @@ def from_trunk(
486486 max_passes : int ,
487487 activation_budget_bytes : int ,
488488 ) -> EagleTTTState :
489- """Validate the complete bound before retaining any supplied tensor."""
489+ """Validate the per-layer multi-pass K/V bound before retaining tensors.
490+
491+ The complete bound across layers, hidden taps, rope, and loss rows is
492+ enforced by the provider's storage plan and, at runtime, by the
493+ resource ledger; this check covers only this layer's K/V retention.
494+ """
490495 _validate_kv_pair (trunk_key , trunk_value , name = "trunk" )
491496 EagleTTTStoragePlan (
492497 batch_size = trunk_key .shape [0 ],
@@ -563,6 +568,16 @@ def __init__(
563568 if attention_type != "self" :
564569 raise ValueError ("EAGLE TTT only supports self attention" )
565570 self .layer_number = layer_number
571+ recompute_granularity = getattr (config , "recompute_granularity" , None )
572+ if recompute_granularity is not None :
573+ # Activation recompute re-enters this forward during backward, which
574+ # violates the one-shot begin_pass/forward/finish_pass lifecycle and
575+ # would corrupt the retained multi-pass state on re-entry.
576+ raise ValueError (
577+ "EAGLE TTT is incompatible with activation recompute "
578+ f"(recompute_granularity={ recompute_granularity !r} ); disable "
579+ "recompute for the draft decoder stack"
580+ )
566581 self .context_parallel_size = int (getattr (config , "context_parallel_size" , 1 ))
567582 self .sequence_parallel = bool (getattr (config , "sequence_parallel" , False ))
568583 self .softmax_scale = softmax_scale
@@ -1509,7 +1524,8 @@ def eagle_ttt_attention(
15091524 raise ValueError ("sequence layout must match query batch and sequence axes" )
15101525 if layout .valid_tokens .device != query .device :
15111526 raise ValueError ("sequence layout and query must share a device" )
1512- _expand_gqa (state .trunk_key , query_heads = query .shape [1 ])
1527+ if query .shape [1 ] % state .trunk_key .shape [1 ] != 0 :
1528+ raise ValueError ("query heads must be divisible by key/value heads" )
15131529
15141530 attention_scale = scale if scale is not None else 1.0 / math .sqrt (query .shape [- 1 ])
15151531 if query .is_cuda and query .dtype != torch .float64 :
0 commit comments