Files
kernbench2/docs/adr-proposed/DDD-0065-flat-ops-composite-softmax-merge-detailed-design.md
T
ywkang a8c50238c6 gqa(adr): ADR-0064 Rev2 (structural dispatch cost) + ADR-0065/DDD-0065 (flat-ops composite + softmax_merge recipe)
ADR-0064 Revision 2: replace per-op-type calibration table with a
structural formula `FIXED_PER_CMD + cmd.logical_bytes × R`, defaults
anchored at typical composite ≈ 45 ns. Topology yaml override under
`pe_cost_model:` block; logical_bytes property per PE command.

ADR-0065: implement ADR-0060 §5.6 / §8 item 4 carve-out as a flat-ops
CompositeCmd (no head/epilogue structural fields — position + scope
drives placement) + first stateful recipe `softmax_merge` (MATH-only
8-step). RECIPE_DESCRIPTORS lives in TLContext-adjacent module only;
PE_SCHEDULER stays recipe-free and auto-inserts DMAs from operand
`space`. Strict-FIFO RW hazard tracker; ≤1 GEMM per composite
invariant. User-facing `tl.composite(prologue=[...], op=, epilogue=[...])`
API preserved; existing benches unchanged (meaning-preserving refactor).

DDD-0065: implementation-ready phased plan (P0=ADR-0064 Rev2 first,
P1-P6 for ADR-0065), file plan, recipe engine sequence, scheduler
plan-gen algorithm, RW tracker design, test matrix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-10 16:11:20 -07:00

23 KiB
Raw Blame History

Detailed Design Document — Flat-ops CompositeCmd + softmax_merge recipe (ADR-0065)

Status: Draft (companion to ADR-0065, Proposed) Scope: implementation-ready plan for the CompositeCmd flat-ops restructure, the softmax_merge recipe, and the decode opt2 variant in _gqa_decode_long.py. Audience: reviewer / implementer resuming after the ADR-0065 design round. Read ADR-0065 first (boundary D5 + D7 set the layering), and ADR-0064 Revision 2 (dispatch cost model that opt2's win depends on).


1. Goal and success criteria

Goal: make decode opt2 runnable, numerically equivalent to opt3, and measurably cheaper in PE_CPU dispatch under the ADR-0064 Rev2 cost model. Existing benches keep their (post-ADR-0064 Rev2) goldens unchanged.

Success criteria:

  1. Refactor safety. CompositeCmd flat-ops restructure preserves the op_log byte-for-byte for every existing bench (tests/<existing> all green, no goldens diff).
  2. Recipe correctness. opt2 final (m, l, O) matches opt3 within fp tolerance in data mode (enable_data=True).
  3. Boundary preservation. PE_SCHEDULER imports nothing recipe-related; PE_MATH/PE_GEMM/PE_DMA see only Stage.params["op_kind"] (no new engine code).
  4. Dispatch ratio. Per-tile PE_CPU dispatch cycles ratio(opt3 / opt2) ≈ 2.4× at default ADR-0064 calibration.
  5. K-before-V invariant. op_log of decode opt2 shows zero V-related DMA during #2's MATH prologue.

Non-goals: prefill (causal if in kernel control flow, separate work); RW-aware scheduler reorder (strict FIFO ships); user-defined recipes; new engine micro-ops in PE_MATH (it stays op_kind-opaque).


2. Where the design sits in the current code

runtime_api (host)
  RuntimeContext.zeros/empty/launch          context.py
        │  KernelLaunchMsg
        ▼
sim_engine
  GraphEngine(enable_data=…)                 engine.py
  MemoryStore                                memory_store.py
        │
        ▼
components / PE pipeline (per PE)
  PE_CPU → PE_SCHEDULER → PE_{DMA,GEMM,MATH,IPCQ,TCM}
  greenlet kernel ↔ SimPy                    kernel_runner.py, pe_cpu.py
  CompositeCmd → tile plan → engines         pe_scheduler.py (ADR-0014 D6)
        │
        ▼
tl programming model                         tl_context.py
  composite / dot / load / store / scratch_scope
  ── ADR-0065 NEW ──────────────────────────
  tl_recipes.py                              RECIPE_DESCRIPTORS, EngineOp,
                                             RecipeDescriptor, PrimaryOutSpec

The new module tl_recipes.py sits beside tl_context.py. PE_SCHEDULER (pe_scheduler.py) and tiling.py extend to consume the flat ops list without importing tl_recipes.


3. File plan

3.1 Modified production files

File Change ADR ref
src/kernbench/common/pe_commands.py CompositeCmd flat-ops dataclass; OpSpec.operands: dict; new Scope value semantics (KERNEL position-based); logical_bytes property on every PeCommand. 0065 D1/D2, 0064 D2
src/kernbench/triton_emu/tl_context.py composite(prologue=[...], out=TensorHandle, …); recipe lowering pass (RECIPE_DESCRIPTORS lookup, scratch alloc, OpSpec expansion, primary_out auto-bind); legacy API preserved (op="gemm", a, b, epilogue=[...] still works, internally lowers to flat ops). 0065 D1/D5
src/kernbench/triton_emu/tl_recipes.py (NEW) RecipeDescriptor, PrimaryOutSpec, EngineOp dataclasses; RECIPE_DESCRIPTORS["softmax_merge"] entry; expansion helper. 0065 D5
src/kernbench/components/builtin/pe_scheduler.py _generate_plan rewritten for flat ops: scan for GEMM (≤1), position-based KERNEL placement, OUTPUT_TILE/K_TILE epilogue, strict-FIFO RW tracker keyed by handle id. 0065 D3/D6
src/kernbench/components/builtin/tiling.py generate_plan_from_ops(ops, rw_handles, pe_prefix) replaces generate_gemm_plan / generate_math_plan (or wraps them). DMA auto-insertion from handle.space. Epilogue add stage emits other_handle in params (GAP 9 fix). 0065 D3/D4
src/kernbench/components/builtin/pe_cpu.py dispatch cost from cmd.logical_bytes via ADR-0064 Rev2 formula; topology config override. 0064 D1/D4
topology yaml (e.g., topologies/llama70b_4sip.yaml) optional pe_cost_model: block under PE node attrs. 0064 D4
src/kernbench/benches/_gqa_decode_long.py opt2 variant — tl.composite(prologue=[{"op":"softmax_merge", …}], op="gemm", b=V_ref, out=O, epilogue=[{"op":"add", "other":O}]). 0065 §Migration P3

3.2 New tests

File Covers
tests/test_composite_flat_ops_refactor.py every existing bench's op_log byte-equal pre/post refactor (parametrized over bench list)
tests/test_tl_recipe_softmax_merge.py recipe lowering — given inputs, asserts CompositeCmd has 10 ops in expected order + rw_handles == (m, l, O)
tests/test_pe_scheduler_strict_fifo.py two consecutive composites sharing rw_handles complete in dispatch order; no stage interleave
tests/test_pe_scheduler_auto_dma.py space=hbm operand → DMA_READ stage; space=tcm → none; out.space=hbm → DMA_WRITE
tests/test_pe_cost_model.py ADR-0064 Rev2 — typical 1-GEMM composite at 45 ns; topology override path; PeCpuOverheadCmd bypass
tests/attention/test_gqa_decode_opt2.py opt2 numeric parity with opt3; K-before-V DMA invariant; per-tile dispatch ratio measurement

4. Data model — CompositeCmd flat-ops

4.1 New shape

@dataclass(frozen=True)
class CompositeCmd:
    completion: CompletionHandle
    ops: tuple[OpSpec, ...]                       # ordered MATH/GEMM ops
    rw_handles: tuple[TensorHandle, ...] = ()     # cross-composite hazard
    data_op: bool = True

    @property
    def logical_bytes(self) -> int:
        return (
            4                                     # framing
            + 1 + sum(op.logical_bytes for op in self.ops)
            + 1 + 8 * len(self.rw_handles)
        )

The previous op, a, b, out_addr, out_nbytes, math_op fields are removed. All info lives in ops[i].

4.2 OpSpec extended

@dataclass(frozen=True)
class OpSpec:
    kind: str                                     # "gemm" | "rmax" | "exp_diff" | ...
    scope: Scope                                  # KERNEL | K_TILE | OUTPUT_TILE
    operands: dict[str, TensorHandle]
    extra: dict[str, Any] = field(default_factory=dict)
    out: TensorHandle | None = None

    @property
    def logical_bytes(self) -> int:
        return (
            1 + 1                                        # opcode + scope enum
            + 1 + 8 * len(self.operands)                 # named handles
            + (8 if self.out is not None else 0)
            + 1 + 4 * len(self.extra)                    # scalars
        )

Backward compat: existing operands: tuple[Any, ...] use sites (epilogue bias, scale, add, etc.) migrate to operands={"other": h} / operands={"src": h} per a small lookup in pe_commands.EPILOGUE_OPS.

4.3 Scope semantics (position-based for KERNEL)

Scope keeps its three values (KERNEL, K_TILE, OUTPUT_TILE). What changes: KERNEL no longer means "once anywhere"; it now means "execute at this op's position in the sequence — once". Combined with position relative to the GEMM op:

  • KERNEL ops before GEMM → pre-tile-loop (single shot)
  • KERNEL ops after GEMM → post-tile-loop (single shot)
  • K_TILE / OUTPUT_TILE ops after GEMM → inside tile loop as before

5. Recipe: softmax_merge

5.1 tl_recipes.py definitions

@dataclass(frozen=True)
class PrimaryOutSpec:
    from_shape: str          # operand name to copy shape from
    from_dtype: str          # operand name to copy dtype from
    transform: str           # "identity" | "trans" (forward-compat)


@dataclass(frozen=True)
class EngineOp:
    engine: Literal["MATH", "GEMM", "DMA"]
    op_kind: str             # PE_MATH op_kind label (opaque to engine)
    # Slot names: any of "src", "src_a", "src_b", "src_c", "dst" — these
    # are RecipeDescriptor.operands names or internal scratch names.
    src: str | None = None
    src_a: str | None = None
    src_b: str | None = None
    src_c: str | None = None
    dst: str | None = None
    reduce_axis: int | None = None
    bcast_axis: int | None = None


@dataclass(frozen=True)
class RecipeDescriptor:
    operands: dict[str, str]                            # name → "R" | "RW"
    primary_out: PrimaryOutSpec | None                  # implicit output spec
    tile_alignment: Literal["single_shot", "tile_aligned"]
    internal_scratch_bytes_fn: Callable[..., int]
    engine_seq: tuple[EngineOp, ...]


RECIPE_DESCRIPTORS: dict[str, RecipeDescriptor] = { ... }

5.2 Engine sequence (8 MATH ops)

# engine op_kind reads (slots) writes (slots) extras
1 MATH rmax s m_loc reduce_axis=-1
2 MATH max_elem m, m_loc m_new
3 MATH exp_diff m, m_new corr
4 MATH exp_diff s, m_new P (primary_out) bcast_axis=0
5 MATH rsum P l_loc reduce_axis=-1
6 MATH fma l, corr, l_loc l
7 MATH mul_bcast O, corr O bcast_axis=1
8 MATH copy m_new m

Intermediates m_loc, m_new, corr, P, l_loc are scratch slots allocated by TLContext before lowering. P is the recipe's primary output; auto- bound to the head GEMM's operands["a"].

5.3 PE_MATH op_kind additions

PE_MATH is op_kind-opaque (pe_math.py:90-99). Latency = ceil(num_elements / vector_width) / clock. Adding new op_kind labels (rmax, max_elem, exp_diff, rsum, fma, mul_bcast, copy) requires no PE_MATH code changes — they pass through as string labels in Stage.params["op_kind"]. Latency stays consistent for the same num_elements.

(Reductions like rmax / rsum have log-depth final stages in real HW not modelled by ceil(num_elements / vector_width); this is an existing approximation, not introduced by ADR-0065.)


6. TLContext lowering pipeline

Input (user-facing API, preserved):

tl.composite(
    op="gemm", b=tl.ref(v_tile(j), (TILE, d)), out=O,
    prologue=[{"op": "softmax_merge", "s": Sj, "m": m, "l": l, "O": O}],
    epilogue=[{"op": "add", "other": O}],
)

Lowering steps in TLContext.composite():

  1. Validate prologue items. For each, lookup RECIPE_DESCRIPTORS[item["op"]]. Check all operands present, type tags (R / RW) match handle states (e.g., RW must not be tl.ref).
  2. Allocate internal scratch. Call recipe.internal_scratch_bytes_fn(G, TILE, d, bpe); allocate via scratch_scope helper (ADR-0063). Get slot addresses for m_loc, m_new, corr, P, l_loc.
  3. Derive primary_out handle. From recipe.primary_out: P handle = TensorHandle(shape=Sj.shape, dtype=Sj.dtype, addr=<P slot>, space="tcm").
  4. Expand engine_seq → flat OpSpecs. For each EngineOp:
    • Resolve slot names (operands or scratch) to TensorHandles.
    • Build OpSpec(kind=op_kind, scope=Scope.KERNEL, operands={...}, extra={...}, out=...).
    • out is the handle for dst slot; operands is {src*: handle}.
  5. Auto-bind head GEMM. GEMM OpSpec built from op="gemm", operands={"a": P_handle, "b": V_handle}, out=<output handle>, extra={"m": G, "k": TILE, "n": d}.
  6. Build epilogue OpSpecs. Each epilogue=[{...}] entry maps to OpSpec(kind=..., scope=Scope.OUTPUT_TILE, operands={...}, ...). The add epilogue specifically gets operands={"other": O_handle} so the Stage later carries other_handle (GAP 9 fix).
  7. Compute rw_handles. Collect all handles tagged RW in prologue recipes + the head GEMM's out (if accumulating) + any RW epilogue targets. For softmax_merge: rw_handles = (m, l, O).
  8. Emit CompositeCmd. ops = (8 MATH + 1 GEMM + 1 MATH(add)), rw_handles = (m, l, O), completion = new.

Legacy lowering. Pre-existing tl.composite(op="gemm", a=A, b=B, epilogue=[{"op":"bias","bias":h}]) goes through the same emit path: no prologue, head OpSpec from op="gemm", epilogue OpSpecs built from epilogue=[...]. Output CompositeCmd has flat ops list; semantics preserved.


7. PE_SCHEDULER tile plan generation (flat-ops)

def _generate_plan(cmd: CompositeCmd) -> PipelinePlan:
    pp = self._pe_prefix
    bpe = 2

    # 1. Identify GEMM op (≤1).
    gemm_idx = next(
        (i for i, o in enumerate(cmd.ops) if o.kind == "gemm"),
        None,
    )

    # 2. MATH-only composite (no GEMM): single tile of all ops in order.
    if gemm_idx is None:
        return _math_only_plan(cmd.ops, pp)

    gemm = cmd.ops[gemm_idx]
    M, K, N = gemm.extra["m"], gemm.extra["k"], gemm.extra["n"]

    # 3. Partition ops by position.
    pre_loop_ops  = cmd.ops[:gemm_idx]              # KERNEL scope
    after_ops     = cmd.ops[gemm_idx+1:]            # mixed scopes

    # 4. Pre-loop MATH Stages (single-shot, before tile loop).
    pre_stages = [_math_stage_from_op(op, pp) for op in pre_loop_ops]

    # 5. Tile loop (existing generate_gemm_plan pattern, but:
    #    - DMA_READ inserted only when operand.space == "hbm"
    #    - K_TILE epilogue from after_ops with scope == K_TILE
    #    - OUTPUT_TILE epilogue from after_ops with scope == OUTPUT_TILE
    #    - DMA_WRITE inserted only when out.space == "hbm")
    tile_plans = _generate_tile_loop(
        gemm, M, K, N, after_ops, pp, bpe,
    )

    # 6. Post-loop KERNEL Stages (after tile loop completes).
    post_loop_ops = [op for op in after_ops if op.scope == Scope.KERNEL]
    post_stages   = [_math_stage_from_op(op, pp) for op in post_loop_ops]

    return PipelinePlan(
        prologue_stages=tuple(pre_stages),
        tiles=tile_plans,
        epilogue_stages=tuple(post_stages),
        m_tiles=..., k_tiles=..., n_tiles=...,
    )

PipelinePlan gets two new fields:

@dataclass(frozen=True)
class PipelinePlan:
    tiles: list[TilePlan]
    m_tiles: int
    k_tiles: int
    n_tiles: int
    prologue_stages: tuple[Stage, ...] = ()
    epilogue_stages: tuple[Stage, ...] = ()

Feeder change (_feed_loop): yield prologue_stages Stages first, then tile loop as today, then epilogue_stages. For the single-Stage case (no prologue/epilogue), behaviour identical to today.


8. Strict-FIFO RW hazard tracker

class _RwHazardTracker:
    def __init__(self):
        self._inflight: list[tuple[CompletionHandle, set[str]]] = []
        # (completion, set of handle ids written or RW)

    def admit(self, env, cmd: CompositeCmd) -> Generator:
        """Block until no in-flight composite has overlapping RW."""
        rw_ids = {h.id for h in cmd.rw_handles}
        # Strict FIFO: wait for ALL prior composites whose rw_set
        # intersects, in order.
        while True:
            blocking = [c for c, s in self._inflight if s & rw_ids]
            if not blocking:
                break
            # Wait on the *first* blocking composite's completion.
            yield blocking[0].done_event
        self._inflight.append((cmd.completion, rw_ids))

    def retire(self, completion: CompletionHandle) -> None:
        self._inflight = [
            (c, s) for c, s in self._inflight if c != completion
        ]

PE_SCHEDULER invokes admit() before queueing a CompositeCmd's tile plan and retire() upon done_event.succeed(). Strict FIFO: even when overlap is partial, the new composite waits for all prior overlapping composites to fully drain — simple, easy to reason about, easy to test. (RW-aware reorder deferred per ADR-0065 A4.)


9. Phased implementation plan (test-first per CLAUDE.md)

Each phase is an independent Phase-1 → Phase-2 cycle per CLAUDE.md Part 1.

Phase Deliverable Gate
P0 (= ADR-0064 Rev2) logical_bytes property + dispatch formula + topology override; one-time goldens regeneration typical composite ≈ 45 ns; dispatch ratio test infrastructure in place
P1 CompositeCmd flat-ops dataclass refactor + OpSpec.operands: dict + legacy tl.composite lowering preserved every existing bench's op_log byte-equal pre/post
P2 tl_recipes.py + RECIPE_DESCRIPTORS["softmax_merge"] + TLContext lowering for prologue=[...] recipe lowering test (10 ops, rw_handles, addresses) passes
P3 PE_SCHEDULER _generate_plan flat-ops + PipelinePlan.prologue_stages + DMA auto-insertion + _feed_loop extension all existing bench Stage sequences unchanged; new MATH chain visible in op_log for opt2 mock
P4 Strict-FIFO RW hazard tracker + _RwHazardTracker integration two-composite RW conflict test serializes correctly
P5 _gqa_decode_long.py opt2 variant; data-mode numeric parity check; K-before-V invariant check opt2 matches opt3 within fp tolerance; no V DMA during prologue
P6 Dispatch-ratio measurement: opt3 vs opt2 per-tile PE_CPU cycles ratio ≈ 2.4× ± 10% at default calibration

P0 must land first (separate ADR). P1 is pure refactor (safest). P2P4 build the new path without touching opt3. P5 enables opt2. P6 closes the measurement loop.


10. Verification plan (concrete)

Mirrors ADR-0065 §Test Requirements; grounded in SPEC R2/R5, ADR-0023/ 0025, ADR-0046, ADR-0054.

Refactor safety (P1):

  • Parametrize over tests/<existing bench>.py baseline op_logs.
  • Pre/post refactor diff must be empty for every bench.
  • Failure → revert P1 atomically; do not land partial.

Recipe lowering (P2):

  • Given Sj=(8,64), m=(8,), l=(8,), O=(8,128), lower tl.composite(prologue=[{"op":"softmax_merge", "s":Sj,...}], op="gemm", b=V_ref, out=O, epilogue=[{"op":"add", "other":O}]).
  • Assert len(cmd.ops) == 10, cmd.ops[0..7].kind == [rmax, max_elem, exp_diff, exp_diff, rsum, fma, mul_bcast, copy], cmd.ops[8].kind == "gemm", cmd.ops[9].kind == "add".
  • Assert cmd.rw_handles == (m, l, O).
  • Assert all OpSpec addresses are concrete (no None).

Scheduler plan (P3):

  • For the above CompositeCmd, assert PipelinePlan has 8 prologue_stages (MATH), tile loop with FETCH/GEMM/MATH(add), no epilogue_stages.
  • Assert no DMA_READ for prologue MATH stages (operands TCM-resident).
  • Assert one DMA_READ for V (b.space == "hbm").
  • Assert no DMA_WRITE (out.space == "tcm").

RW hazard (P4):

  • Submit composite A (rw_handles=(O,)) then composite B (operands reading O). Assert B's Stages start only after A's done_event.

Numeric parity (P5):

  • In data mode, run opt2 and opt3 for (G=8, T_q=1, S_kv=64, C=1, P=1).
  • Assert O_opt2 ≈ O_opt3 within fp16 tolerance.

K-before-V invariant (P5):

  • op_log inspection: for each tile's #2 CompositeCmd, no memory/dma_read events between #2 start and the GEMM compute begin that are not the V tile DMA itself.

Dispatch ratio (P6):

  • For S_kv=64, n_tiles=16, measure total PE_CPU dispatch cycles for opt3 vs opt2 paths.
  • Assert ratio in [2.0, 2.8] (centre 2.4×).

Determinism (all phases):

  • Identical inputs → identical op_log + latency (SPEC §0.1).

11. Performance model (expected)

Per-tile PE_CPU dispatch cycles, ADR-0064 Rev2 default calibration:

opt3: 10 cmds × 32 + total_bytes(≈232) × 0.25 = 320 + 58  ≈ 378 ns
opt2:  2 cmds × 32 + total_bytes(≈380) × 0.25 =  64 + 95  ≈ 159 ns
ratio = 378 / 159 ≈ 2.4×

Per-tile engine timing dominates total latency; dispatch is one component. The ratio above is the dispatch-only relative cost. Total latency improvement depends on whether dispatch was on the critical path — measured per workload in P6.


12. Open items (status)

Most ADR-0065 §Open review items map to specific implementation choices already documented in §§58. Live remaining items:

Item Resolution venue
Non-identity PrimaryOutSpec.transform (e.g., "trans") Future recipe addition; current code uses string dispatch in step 3 of §6
_gqa_decode_long.py opt2 — TILE size sweep Open (existing §B-3, §9 of ADR-0060)
Larger composite descriptors (10+ OpSpecs) and logical_bytes growth Monitored in P6; if R term dominates, calibration revisit
scratch_scope budget vs softmax_merge intermediates (G·TILE for P) ADR-0063 sizing check at S_kv = 256K

13. Risks

Risk Likelihood Mitigation
CompositeCmd refactor (P1) changes op_log for some bench med Parametrized regression over all benches; revert atomically
OpSpec.operands migration (positional → dict) breaks epilogue site med Per-EPILOGUE_OPS migration table; existing epilogue tests cover
_RwHazardTracker false-positive serializes too aggressively low Strict FIFO is the safe direction; RW-aware reorder is a future ADR
ADR-0064 Rev2 and ADR-0065 P1 land in wrong order → stale goldens med PR ordering enforced; CI gate requires both to be green
softmax_merge scratch budget exceeds scratch_scope at long context med ADR-0063 sizing check; if needed, tile_alignment promotion (future)
PE_MATH op_kind label collision with new strings low Labels are opaque strings — no enum conflict; just add to allowed set if validated

14. Glossary & references

  • flat ops listCompositeCmd.ops: tuple[OpSpec, ...] with no head/epilogue field; placement determined by op position + scope.
  • prologue (user API)tl.composite(prologue=[...]) kwarg for recipe ops that lower into pre-GEMM KERNEL-scope OpSpecs. HW command does not carry this concept.
  • recipe — a named macro op (e.g., softmax_merge) that TLContext expands to multiple flat OpSpecs at emit time. Registry = RECIPE_DESCRIPTORS.
  • primary_out — recipe's implicit output (e.g., P for softmax_merge). Auto-bound to head GEMM's first matrix operand.
  • handle-identity strict FIFO — cross-composite serialization rule: a composite waits for all prior composites whose rw_handles intersect with its own to complete.
  • logical_bytes — HW-logical byte size of a PE command, derived from a structural rule (ADR-0064 D2), not from Python's sys.getsizeof.

Source anchors: tl_context.py (tl API), pe_scheduler.py:104-143 (composite tile plan), pe_dma.py:45,89 (read channel), pe_math.py (op_kind opaque latency), pe_cpu.py (dispatch hook), pe_commands.py (CompositeCmd, OpSpec, EPILOGUE_OPS).

ADRs: 0065 (this design), 0064 Revision 2 (dispatch cost), 0060 (GQA fused attention, §5.6 / §8 item 4 carve-out), 0063 (scratch_scope), 0046 (tl_context contract), 0042 (tile plan generators), 0014 (PE pipeline execution model).