Skip to content

perf(dflash, gfx1100): dedicated MQ4-V2 verify kernels, split-K residual, and launch fusion — merge-sort xt 209 → 285 tok/s - #702

Closed
Kaden-Schutt wants to merge 50 commits into
masterfrom
feat/dflash-dedicated-kernels-pr
Closed

perf(dflash, gfx1100): dedicated MQ4-V2 verify kernels, split-K residual, and launch fusion — merge-sort xt 209 → 285 tok/s#702
Kaden-Schutt wants to merge 50 commits into
masterfrom
feat/dflash-dedicated-kernels-pr

Conversation

@Kaden-Schutt

Copy link
Copy Markdown
Collaborator

Summary

DFlash decode on the 7900 XTX (gfx1100) was occupancy-bound in the verify GEMMs and launch-bound around them. This branch adds dedicated per-card × per-quant kernels (not generic reuse) for the MQ4-V2 27B verify path and fuses the per-cycle launch storm:

  • gemm_mq4g256v2_residual_wmma_gfx1100_ksplit_lds.hip / …_ldsstage.hip — split-K residual WMMA GEMM with LDS-staged X fragments (the ISA bind was s_waitcnt vmcnt(0) on the X-fragment load before every WMMA).
  • Launch fusion wave 1 (~2307 → ~984 launches/cycle): dflash_draft_collapse, dflash_gdn_pre, dflash_hidden_scatter, dflash_state_bulk_copy, fused_rmsnorm/silu_mul/gated_norm/sigmoid_mul_mq_rotate_f16, kv_cache_write_q8_0_pair_batched, qwen35_fa_prep_batched (all .gfx1100.hip, arch-gated).
  • Every fusion has a kill switch in rdna-compute/src/feature_flags.rs (HIPFIRE_*_OFF); with all nine off the branch reproduces today's path byte-for-byte (same token sha).

49 commits, 53 files, +12,170/−501. Rebased onto master e23c55e79 cleanly — none of master's 21 commits since the merge-base touch campaign files.

Numbers (byte-identical fixture, fresh process each)

hipx, RX 7900 XTX (gfx1100), ROCm 7.15, rustc 1.98.1. Target xt qwen3.8-27b.mq4v2.xt.hfq (md5 e45d15bfe0c9…), draft qwen38-27b-dflash-mq4.hfq (md5 013395583cd0…), prompt benchmarks/prompts/merge_sort_thinking_off.txt (md5 253c7ac50857…), dflash_spec_demo built from this tip in a clean worktree (md5 ec539c53d69b…):

HIPFIRE_VERIFY_GRAPH=0 dflash_spec_demo --target …xt.hfq --draft …dflash-mq4.hfq \
  --prompt-file benchmarks/prompts/merge_sort_thinking_off.txt --max 256 --temp 0.0 \
  --no-chatml --kv-mode q8 --ctx 4096 --no-adaptive-b
run decode tok/s tokens / cycles / τ DFlash tokens sha
1 285.60 157 / 11 / 13.1818 c2313b39
2 282.54 157 / 11 / 13.1818 c2313b39
3 285.01 157 / 11 / 13.1818 c2313b39
4 284.84 157 / 11 / 13.1818 c2313b39

(run 0 of the set was the cold kernel-cache compile and is excluded.) Master on the same fixture: ~209 tok/s. Split-K residual alone: 256. Decoded output identical across all runs and to master (same sha); eyeballed — a correct merge sort, no attractor.

R9700 (gfx1201) on the same fixture: ~300 tok/s (hiptrx device 3, earlier this week; gfx12 uses its own ldsstage variant).

Correctness route

  • Token identity is the accuracy gate: DFlash tokens sha c2313b39 with fusion on, with all nine switches off, and on master.
  • Kernel parity: relL2 ≤ 5e-5 + f64 floor on every new GEMM/fusion kernel (examples test_mq4v2_residual_ksplit_gfx1100, bench_dflash_verify_shapes in crates/rdna-compute/examples).
  • Not yet run through scripts/redline_daemon_harness.py (kernel bucket): this is the first kernel PR through hw-gate, so its Redline step gets exercised here.

Explicitly not in this PR

S8 top-K-direct (reverted), S9 persistent prologues (not built), ks4 weight prefetch (kill experiment: dead), gfx1100 ldsstage-as-weights-only beyond the 53% residual efficiency (closed). X-in-LDS residual is the next lever and is separate work.

Which surface(s) does this touch?

  • kernels/ (12 new gfx1100 kernels), crates/rdna-compute (dispatch + kill switches), crates/hipfire-arch-qwen35 (speculative.rs, prefill.rs), crates/hipfire-runtime (dflash.rs), crates/hipfire-dispatch (families/attention.rs)
  • crates/radiowave (ks4 campaign recipe, research)
{"routes": [{"mode": "battery", "tag": "qwen3.8:27b-mq4-xt"}], "claim": "DFlash decode on gfx1100 for the MQ4-V2 27B target is 285 tok/s vs ~209 on master on benchmarks/prompts/merge_sort_thinking_off.txt with identical decoded tokens; batteries and Redline parity show no regression on non-DFlash paths."}

Do not merge yet — held for maintainer review after the gate's kernel-bucket evidence; this PR exists so the branch stops accruing rebase debt against prefill.rs/speculative.rs (#690, #695).

@hipfire-sol

hipfire-sol Bot commented Sep 4, 2026

Copy link
Copy Markdown

hw-gate sol prelim

summary: Adds gfx1100-specific MQ4-V2 split-K residual GEMMs and DFlash launch-fusion paths, plus Qwen speculative/runtime plumbing, shared Q8 KV-write dispatch, replay contracts, harnesses, and a 10-count increase to the dispatch-bypass policy ceiling.

run_hardware: true
run_hardware_reasons: Changes are ordinary Rust and HIP code with no new dependencies, toolchains, network access, credential access, or opaque payloads.; Cargo.toml only registers local examples; the policy edit only changes a repository threshold.; Developer-example filesystem access stays within model, HOME-output, and temporary paths.; The shown unsafe code is identifiable GPU ABI and byte-slice handling.; The R9700 can test gfx1201 load, serve, and fallback behavior, but cannot validate exact-gfx1100 fast paths or 7900 XTX performance.

routes:

mode tag source why
battery qwen3.6:27b bucket bucket kernel,load,serve
chain qwen3.6:27b bucket bucket kernel,load,serve
battery ornith-1.5:35b-a3b-mq4r bucket bucket kernel,load,serve
chain ornith-1.5:35b-a3b-mq4r bucket bucket kernel,load,serve
battery lfm2.5:1.2b bucket bucket kernel,load,serve
chain lfm2.5:1.2b bucket bucket kernel,load,serve
battery qwen3.8:27b-mq4-xt bucket bucket kernel,load,serve
chain qwen3.8:27b-mq4-xt bucket bucket kernel,load,serve

unavailable_routes:

tag why
qwen3.8:27b-mq4-xt@gfx1100 The artifact exists, but the runner GPU is gfx1201; exact-gfx1100 kernels and the 7900 XTX throughput claim cannot run here.

claim_assessment: Proof requires exact-gfx1100 evidence of coherent token-equivalent output, approximately 285 versus 209 tok/s under pinned artifacts and prompt, kernel parity, and non-DFlash Redline behavior. This runner can establish load/serve coherence and gfx1201 fallback only, not the gfx1100 speedup or kernel correctness.

questions_for_author:

  • Provide exact-gfx1100 Redline output and kill-switch on/off token evidence.
  • Account for the bypass_total increase from 237 to 247 and identify the ten new bypasses.

@hipfire-sol

hipfire-sol Bot commented Sep 4, 2026

Copy link
Copy Markdown

hw-gate evidence — 2 lane(s) — verdict pass

lane hiptrx (gfx1201)

hw-gate evidence

field value
base 0652500c28e3c302484b4b9f8cca5135e9fc777e
head 87233eae1469f1604d53e1e57899104990357078
buckets kernel,load,serve
host gfx gfx1201
host rocm 7.15.26333-0000000
device 3
runner hiptrx
daemon_md5 e867e32e1b67b293ca54e7f7ea12ec75
hipfire_md5 82246eab9dd6ef7025b1ab41f8b4eae6
build_seconds 43.14679288864136
verdict pass
logs_dir hw-gate-logs

fixtures

qwen3.6:27b

source: bucket sha256_ok: ✅ size_ok: ✅ status: pass reason:

battery — exit 0 seconds 54.1 status pass

mode idx genre finish ctx cached gen ans_words prefill_tok_s decode_tok_s attractor empty runaway recall_ok
battery 0 stop 34 0 186 90 1.8 16.8 False False False True
battery 1 stop 30 0 80 68 454.0 31.1 False False False True
battery 2 stop 31 0 19 16 486.2 31.2 False False False True
battery 3 stop 47 0 31 8 531.6 31.1 False False False True
battery 4 stop 47 0 75 39 533.9 31.1 False False False True
qwen3.6:27b battery turn 0
```python
def longest_substring_without_repeating(s: str) -> str:
    """
    Returns the longest substring of a string without repeating characters.
    
    Args:
        s: Input string
        
    Returns:
        The longest substring without repeating characters
    """
    if not s:
        return ""
    
    start = 0
    max_length = 0
    max_start = 0
    char_index = {}
    
    for end, char in enumerate(s):
        if char in char_index and char_index[char] >= start:
            start = char_index[char] + 1
        
        char_index[char] = end
        
        if end - start + 1 > max_length:
            max_length = end - start + 1
            max_start = start
    
    return s[max_start:max_start + max_length]
```
qwen3.6:27b battery turn 1
During the day, sunlight travels through a shorter path in the atmosphere, causing shorter blue wavelengths to scatter more widely in all directions via Rayleigh scattering. At sunset, sunlight must pass through a much thicker layer of Earth's atmosphere, which scatters away most of the blue and green light before it reaches your eyes. This leaves primarily the longer red and orange wavelengths to dominate the sky's appearance.
qwen3.6:27b battery turn 2
The capital of France is Paris, and the river that runs through it is the Seine.
qwen3.6:27b battery turn 3
{
  "name": "Alice",
  "age": 34,
  "city": "Lisbon"
}
qwen3.6:27b battery turn 4
To add 17 and 26, you can break it down:
1. Add the tens: 10 + 20 = 30
2. Add the ones: 7 + 6 = 13
3. Add the results: 30 + 13 = 43

Answer: 43

chain — exit 0 seconds 41.9 status pass

mode idx genre finish ctx cached gen ans_words prefill_tok_s decode_tok_s attractor empty runaway recall_ok
chain 0 stop 44 0 114 47 5.6 30.9 False False False True
chain 1 stop 214 159 195 98 396.2 30.9 False False False True
chain 2 stop 435 410 79 66 279.5 30.9 False False False True
chain 3 stop 548 515 106 83 289.7 30.9 False False False True
chain 4 stop 686 655 76 57 336.3 30.9 False False False True
qwen3.6:27b chain turn 0
```python
def merge_sorted(a, b):
    """Merge two sorted lists into a single sorted list."""
    merged = []
    i, j = 0, 0
    while i < len(a) and j < len(b):
        if a[i] <= b[j]:
            merged.append(a[i])
            i += 1
        else:
            merged.append(b[j])
            j += 1
    merged.extend(a[i:])
    merged.extend(b[j:])
    return merged
```
qwen3.6:27b chain turn 1
To find the total distance traveled, we calculate the distance for each leg of the trip separately using the formula:

$$\text{Distance} = \text{Speed} \times \text{Time}$$

**Step 1: Calculate the distance for the first leg**
*   Speed = 60 mph
*   Time = 2.5 hours

$$60 \times 2.5 = 150 \text{ miles}$$

**Step 2: Calculate the distance for the second leg**
*   Speed = 40 mph
*   Time = 1.5 hours

$$40 \times 1.5 = 60 \text{ miles}$$

**Step 3: Add the distances together**
$$150 + 60 = 210 \text{ miles}$$

The train traveled a total of **210 miles**.
qwen3.6:27b chain turn 2
The primary cause of seasons on Earth is the planet's axial tilt of approximately 23.5 degrees relative to its orbital plane. This tilt means that different parts of Earth receive varying amounts of direct sunlight throughout the year as the planet orbits the sun. Consequently, when the Northern Hemisphere is tilted toward the sun, it experiences summer, while the Southern Hemisphere experiences winter, and vice versa.
qwen3.6:27b chain turn 3
For decades, Elias had watched the sea with weary eyes, expecting only driftwood and seaweed to breach the jagged shoreline. One stormy morning, however, he discovered a pristine wooden chest tightly wedged between two massive boulders. His hands trembled as he pried open the rusty lid, revealing not gold or jewels, but hundreds of yellowed love letters tied with faded red ribbon. Reading the first page, he realized the handwriting belonged to his grandmother, who had vanished without a trace fifty years prior.
qwen3.6:27b chain turn 4
1. Use meaningful and consistent naming conventions for variables and functions.
2. Keep functions small and focused on a single responsibility.
3. Write clear and concise comments that explain the "why" rather than the "what."
4. Follow a consistent coding style and use automated formatting tools.
5. Write unit tests to catch regressions and document expected behavior.

ornith-1.5:35b-a3b-mq4r

source: bucket sha256_ok: ✅ size_ok: ✅ status: pass reason:

battery — exit 0 seconds 89.8 status pass

mode idx genre finish ctx cached gen ans_words prefill_tok_s decode_tok_s attractor empty runaway recall_ok
battery 0 stop 34 0 148 59 22.6 7.6 False False False True
battery 1 stop 30 0 116 105 106.8 7.5 False False False True
battery 2 stop 31 0 16 13 110.3 9.2 False False False True
battery 3 stop 47 0 22 6 159.7 10.0 False False False True
battery 4 stop 47 0 6 2 160.7 5.6 False False False True
ornith-1.5:35b-a3b-mq4r battery turn 0
```python
def longest_substring_without_repeating_chars(s: str) -> str:
    seen = set()
    start = 0
    best_start = 0
    best_len = 0
    
    for end in range(len(s)):
        if s[end] in seen:
            while s[end] not in seen:
                seen.discard(s[start])
                start += 1
        else:
            seen.add(s[end])
        
        current_len = end - start + 1
        if current_len > best_len:
            best_len = current_len
            best_start = start
    
    return s[best_start:best_start + best_len]
```
ornith-1.5:35b-a3b-mq4r battery turn 1
During the day, sunlight interacts with the atmosphere through a process called Rayleigh scattering, in which shorter blue wavelengths are scattered more effectively by air molecules than longer wavelengths, filling the sky with scattered blue light that reaches your eyes from all directions. As the sun sets, its light travels through a much greater thickness of atmosphere at a low angle, causing nearly all of the shorter blue and green wavelengths to be scattered away before reaching you, leaving the longer red and orange wavelengths to dominate. This remaining red light is what paints the sky and clouds in the warm hues characteristic of sunset.
ornith-1.5:35b-a3b-mq4r battery turn 2
The capital of France is Paris, and the Seine River runs through it.
ornith-1.5:35b-a3b-mq4r battery turn 3
{"name": "Alice", "age": 34, "city": "Lisbon"}
ornith-1.5:35b-a3b-mq4r battery turn 4
Answer: 43

chain — exit 0 seconds 122.2 status pass

mode idx genre finish ctx cached gen ans_words prefill_tok_s decode_tok_s attractor empty runaway recall_ok
chain 0 length 44 0 256 145 470.5 9.7 False False True True
chain 1 stop 355 0 169 75 123.0 8.9 False False False True
chain 2 stop 550 524 90 75 116.6 8.9 False False False True
chain 3 stop 674 640 120 98 147.2 7.0 False False False True
chain 4 stop 826 794 76 54 129.5 6.9 False False False True
ornith-1.5:35b-a3b-mq4r chain turn 0
```python
def merge_sorted(a, b):
    """Merge two sorted lists into a single sorted list.

    Uses a two-pointer technique: compare the elements at the current
    position in each list, append the smaller one, and advance the
    corresponding pointer. This runs in O(n + m) time, where n and m
    are the lengths of a and b.
    """
    merged = []
    i, j = 0, 0

    while i < len(a) and j < len(b):
        if a[i] <= b[j]:
            merged.append(a[i])
            i += 1
        else:
            merged.append(b[j])
            j += 1

    # Append any remaining elements from either list
    merged.extend(a[i:])
    merged.extend(b[j:])

    return merged
```

This function works by:

1. **Initializing two pointers** (`i` and `j`) at the start of each list.
2. **Comparing elements** at each pointer position and appending the smaller to `merged`, advancing that pointer.
3. **Appending leftovers** — once one list is exhausted, the remaining elements from the other
ornith-1.5:35b-a3b-mq4r chain turn 1
# Train Distance Calculation

## Step 1: First Segment
Traveling at 60 mph for 2.5 hours:

$$\text{Distance} = \text{Speed} \times \text{Time} = 60 \times 2.5 = 150 \text{ miles}$$

## Step 2: Second Segment
Traveling at 40 mph for 1.5 hours:

$$\text{Distance} = 40 \times 1.5 = 60 \text{ miles}$$

## Step 3: Total Distance
Add both segments together:

$$150 + 60 = 210 \text{ miles}$$

---

**The train traveled a total of 210 miles.**
ornith-1.5:35b-a3b-mq4r chain turn 2
The seasons on Earth are primarily caused by the 23.5-degree tilt of Earth's axis relative to its orbital plane around the Sun. As Earth orbits the Sun over the course of a year, different parts of the planet receive varying amounts of direct sunlight depending on how each hemisphere is tilted toward or away from the Sun. This changing angle and duration of solar exposure produces the cyclical pattern of spring, summer, autumn, and winter.
ornith-1.5:35b-a3b-mq4r chain turn 3
Martha had patrolled the jagged rocks of Blackpoint Cove for thirty years, expecting nothing from the ocean but salt and storm. That morning, however, tangled in the kelp lay a small wooden chest, its surface smooth and free of the barnacles that claimed everything the sea touched. She pried it open with a trembling hand and discovered a letter addressed in her late husband's familiar slanting script, though he had died a decade past. The wind went silent, and for the first time in years, Martha believed the sea sometimes returns what we thought it had lost forever.
ornith-1.5:35b-a3b-mq4r chain turn 4
1. Name things clearly and consistently so their purpose is obvious at a glance.
2. Keep functions small and focused, ideally doing one thing well.
3. Avoid duplicating logic; reuse code through shared functions or modules.
4. Write meaningful comments that explain "why," not "what."
5. Keep formatting and structure consistent across the codebase.

lfm2.5:1.2b

source: bucket sha256_ok: ✅ size_ok: ✅ status: pass reason:

battery — exit 0 seconds 9.1 status pass

mode idx genre finish ctx cached gen ans_words prefill_tok_s decode_tok_s attractor empty runaway recall_ok
battery 0 stop 0 0 121 58 None 145.26 False False False True
battery 1 stop 0 0 83 73 None 152.01 False False False True
battery 2 stop 0 0 15 13 None 153.06 False False False True
battery 3 stop 0 0 26 8 None 152.94 False False False True
battery 4 stop 0 0 21 13 None 153.28 False False False True
lfm2.5:1.2b battery turn 0
```python
def longest_unique_substring(s):
    seen = {}
    start = 0
    max_len = 0
    max_sub = ""

    for i, char in enumerate(s):
        if char in seen and start <= seen[char]:
            start = seen[char] + 1
        else:
            if i - start + 1 > max_len:
                max_len = i - start + 1
                max_sub = s[start:i+1]

        seen[char] = i

    return max_sub
```
lfm2.5:1.2b battery turn 1
During the day, the sky appears blue because sunlight, when scattered by air molecules, reflects off our eyes in all directions, with blue light traveling farther and dominating the perception. At sunset, the sky turns red due to the sun being low in the sky, allowing longer wavelengths of red light to bend more and reach observers. This phenomenon is a result of atmospheric scattering and the angle of sunlight during these times.
lfm2.5:1.2b battery turn 2
The capital of France is Paris, and the Seine River runs through it.
lfm2.5:1.2b battery turn 3
{
  "name": "Alice",
  "age": 34,
  "city": "Lisbon"
}
lfm2.5:1.2b battery turn 4
Let's add the two numbers together:  
17 + 26 = 43  
Answer: 43

chain — exit 0 seconds 19.9 status pass

mode idx genre finish ctx cached gen ans_words prefill_tok_s decode_tok_s attractor empty runaway recall_ok
chain 0 stop 0 0 189 100 None 143.62 False False False True
chain 1 stop 0 0 194 117 None 138.08 False False False True
chain 2 stop 0 0 57 51 None 133.8 False False False True
chain 3 stop 0 0 97 77 None 130.9 False False False True
chain 4 stop 0 0 56 39 None 128.44 False False False True
lfm2.5:1.2b chain turn 0
```python
def merge_sorted(a, b):
    """
    Merges two already-sorted lists into a single sorted list without using the sorted() function.
    
    Parameters:
    a (list): First sorted list.
    b (list): Second sorted list.
    
    Returns:
    list: A new list containing all elements from both a and b in sorted order.
    """
    merged = []
    i, j = 0, 0
    while i < len(a) and j < len(b):
        if a[i] <= b[j]:
            merged.append(a[i])
            i += 1
        else:
            merged.append(b[j])
            j += 1
    merged.extend(a[i:])
    merged.extend(b[j:])
    return merged
```

This function efficiently merges two sorted lists into a new sorted list by iterating through both and comparing elements.
lfm2.5:1.2b chain turn 1
Sure! Let's break this down step by step.

We are given two segments of a train's journey:
- First segment: 60 mph for 2.5 hours
- Second segment: 40 mph for 1.5 hours

We need to calculate the distance for each segment and then add them together.

---

**Step 1: First segment (60 mph for 2.5 hours)**  
Distance = Speed × Time  
= 60 mph × 2.5 hours  
= 150 miles

---

**Step 2: Second segment (40 mph for 1.5 hours)**  
Distance = 40 mph × 1.5 hours  
= 60 miles

---

**Step 3: Total distance traveled**  
Total = 150 miles + 60 miles  
= **210 miles**

---

**Final Answer:**  
The train traveled **210 miles** in total.
lfm2.5:1.2b chain turn 2
The seasons on Earth are caused by the uneven distribution of sunlight due to the tilt of the Earth's axis. As the Earth orbits the Sun, different parts of the planet receive varying amounts of sunlight throughout the year. These changes in sunlight exposure lead to the cyclical pattern of seasons.
lfm2.5:1.2b chain turn 3
A lighthouse keeper, keeping watch over the rocky coast, noticed something curious washed up on the shore one windy evening. The object, a small, weathered boat, resembled a lost treasure but seemed to hold mysteries of its own. As he gently picked it up, a note slipped out from beneath it, leaving the keeper with a sense of wonder. Excited by the discovery, he decided to follow the story it might tell about the ocean's hidden secrets.
lfm2.5:1.2b chain turn 4
1. Write clear and consistent naming conventions.  
2. Use comments to explain complex logic or decisions.  
3. Break code into small, reusable functions.  
4. Regularly refactor code to improve readability.  
5. Test your code thoroughly to catch issues early.

qwen3.8:27b-mq4-xt

source: bucket sha256_ok: ✅ size_ok: ✅ status: pass reason:

battery — exit 0 seconds 40.3 status pass

mode idx genre finish ctx cached gen ans_words prefill_tok_s decode_tok_s attractor empty runaway recall_ok
battery 0 stop 34 0 132 62 52.2 13.9 False False False True
battery 1 stop 30 0 85 72 167.5 33.9 False False False True
battery 2 stop 31 0 16 13 171.2 26.4 False False False True
battery 3 stop 47 0 31 8 230.6 37.9 False False False True
battery 4 stop 47 0 17 7 230.3 54.3 False False False True
qwen3.8:27b-mq4-xt battery turn 0
```python
def longest_substring_without_repeating(s: str) -> str:
    char_index = {}
    start = 0
    max_length = 0
    max_start = 0
    
    for end, char in enumerate(s):
        if char in char_index and char_index[char] >= start:
            start = char_index[char] + 1
        char_index[char] = end
        if end - start + 1 > max_length:
            max_length = end - start + 1
            max_start = start
    
    return s[max_start:max_start + max_length]
```
qwen3.8:27b-mq4-xt battery turn 1
During the day, sunlight scatters off air molecules in the atmosphere, with shorter blue wavelengths scattering more widely across the sky than longer wavelengths. At sunset, the sunlight travels through a significantly thicker layer of atmosphere, causing the blue light to scatter away entirely before reaching your eyes. This leaves the longer, less-scattered red and orange wavelengths to dominate the light that reaches you, creating the characteristic warm colors of a sunset.
qwen3.8:27b-mq4-xt battery turn 2
The capital of France is Paris, and the River Seine runs through it.
qwen3.8:27b-mq4-xt battery turn 3
{
  "name": "Alice",
  "age": 34,
  "city": "Lisbon"
}
qwen3.8:27b-mq4-xt battery turn 4
17 + 26 = 43

Answer: 43

chain — exit 0 seconds 49.0 status pass

mode idx genre finish ctx cached gen ans_words prefill_tok_s decode_tok_s attractor empty runaway recall_ok
chain 0 stop 44 0 165 72 191.5 15.9 False False False True
chain 1 stop 269 0 164 89 549.9 64.5 False False False True
chain 2 stop 463 0 74 64 636.0 28.8 False False False True
chain 3 stop 575 0 83 68 647.4 38.0 False False False True
chain 4 stop 694 0 71 52 697.7 24.5 False False False True
qwen3.8:27b-mq4-xt chain turn 0
```python
def merge_sorted(a, b):
    """Merge two sorted lists into a single sorted list."""
    result = []
    i = 0
    j = 0
    len_a = len(a)
    len_b = len(b)
    
    while i < len_a and j < len_b:
        if a[i] <= b[j]:
            result.append(a[i])
            i += 1
        else:
            result.append(b[j])
            j += 1
    
    # Append remaining elements
    while i < len_a:
        result.append(a[i])
        i += 1
    
    while j < len_b:
        result.append(b[j])
        j += 1
    
    return result
```
qwen3.8:27b-mq4-xt chain turn 1
To find the total distance traveled, we calculate the distance for each segment using the formula:

**Distance = Speed × Time**

**Step 1: First segment**
- Speed = 60 mph
- Time = 2.5 hours
- Distance₁ = 60 × 2.5 = **150 miles**

**Step 2: Second segment**
- Speed = 40 mph
- Time = 1.5 hours
- Distance₂ = 40 × 1.5 = **60 miles**

**Step 3: Total distance**
- Total distance = Distance₁ + Distance₂ = 150 + 60 = **210 miles**

**Final answer: 210 miles**
qwen3.8:27b-mq4-xt chain turn 2
The primary cause of Earth's seasons is the tilt of its rotational axis relative to its orbital plane around the Sun. As Earth orbits the Sun, different hemispheres tilt toward or away from the Sun, altering the angle and duration of sunlight received at each location. This variation in solar exposure leads to the cyclical changes in temperature and weather patterns known as seasons.
qwen3.8:27b-mq4-xt chain turn 3
Ellis had spent forty years keeping the light burning, but on this stormy Tuesday, a sleek glass bottle with a sealed parchment inside bobbed against the jagged rocks. He wiped the saltwater from the glass and broke the wax seal, expecting a sailor's last message, but his breath caught when he saw the handwriting. It was in his own style, dated exactly one hundred years in the future.
qwen3.8:27b-mq4-xt chain turn 4
1. Use clear and descriptive names for variables, functions, and classes.
2. Keep functions short and focused on a single responsibility.
3. Write unit tests to verify behavior and prevent regressions.
4. Add concise comments only to explain complex logic or intent.
5. Follow established coding style guides and use linters consistently.

kernel

status: pass

report pass: True

lane hipx (gfx1100)

hw-gate evidence

field value
base 0652500c28e3c302484b4b9f8cca5135e9fc777e
head 87233eae1469f1604d53e1e57899104990357078
buckets kernel,load,serve
host gfx gfx1100
host rocm 7.15.26333-0000000
device 0
runner hipx
daemon_md5 e867e32e1b67b293ca54e7f7ea12ec75
hipfire_md5 82246eab9dd6ef7025b1ab41f8b4eae6
build_seconds 46.336029291152954
verdict pass
logs_dir hw-gate-logs

fixtures

qwen3.6:27b

source: bucket sha256_ok: ✅ size_ok: ✅ status: pass reason:

battery — exit 0 seconds 32.8 status pass

mode idx genre finish ctx cached gen ans_words prefill_tok_s decode_tok_s attractor empty runaway recall_ok
battery 0 stop 34 0 134 66 3.1 17.4 False False False True
battery 1 stop 30 0 80 72 453.3 50.5 False False False True
battery 2 stop 31 0 16 13 459.5 50.5 False False False True
battery 3 stop 47 0 31 8 472.1 50.5 False False False True
battery 4 stop 47 0 6 2 474.1 50.3 False False False True
qwen3.6:27b battery turn 0
```python
def longest_substring_without_repeating(s: str) -> str:
    char_index = {}
    start = 0
    max_len = 0
    end = 0
    
    for i, char in enumerate(s):
        if char in char_index and char_index[char] >= start:
            start = char_index[char] + 1
        char_index[char] = i
        if i - start + 1 > max_len:
            max_len = i - start + 1
            end = i
    
    return s[end - max_len + 1:end + 1]
```
qwen3.6:27b battery turn 1
The sky appears blue during the day because shorter blue wavelengths of sunlight scatter more efficiently than longer wavelengths when they collide with gas molecules in the atmosphere. At sunset, sunlight travels through a greater thickness of the atmosphere, causing most of the blue light to scatter away before it reaches the observer. Consequently, only the longer red and orange wavelengths remain to dominate the view, creating the characteristic colors of sunset.
qwen3.6:27b battery turn 2
The capital of France is Paris, and the River Seine runs through it.
qwen3.6:27b battery turn 3
{
  "name": "Alice",
  "age": 34,
  "city": "Lisbon"
}
qwen3.6:27b battery turn 4
Answer: 43

chain — exit 0 seconds 20.6 status pass

mode idx genre finish ctx cached gen ans_words prefill_tok_s decode_tok_s attractor empty runaway recall_ok
chain 0 stop 44 0 166 73 389.3 50.5 False False False True
chain 1 stop 266 211 248 129 386.8 50.5 False False False True
chain 2 stop 540 515 74 60 291.9 50.3 False False False True
chain 3 stop 648 615 96 77 293.0 50.2 False False False True
chain 4 stop 776 745 68 49 349.1 50.2 False False False True
qwen3.6:27b chain turn 0
```python
def merge_sorted(a, b):
    """
    Merge two already-sorted lists into one sorted list.
    
    Args:
        a: First sorted list.
        b: Second sorted list.
    
    Returns:
        A new sorted list containing all elements from a and b.
    """
    result = []
    i, j = 0, 0
    while i < len(a) and j < len(b):
        if a[i] <= b[j]:
            result.append(a[i])
            i += 1
        else:
            result.append(b[j])
            j += 1
    # Append remaining elements
    result.extend(a[i:])
    result.extend(b[j:])
    return result
```
qwen3.6:27b chain turn 1
To find the total distance traveled, we calculate the distance for each segment of the trip and then add them together.

**Step 1: Calculate the distance for the first segment**
*   Speed: 60 mph
*   Time: 2.5 hours
*   Distance = Speed × Time
*   $60 \text{ mph} \times 2.5 \text{ hours} = 150 \text{ miles}$

**Step 2: Calculate the distance for the second segment**
*   Speed: 40 mph
*   Time: 1.5 hours
*   Distance = Speed × Time
*   $40 \text{ mph} \times 1.5 \text{ hours} = 60 \text{ miles}$

**Step 3: Add the distances together**
*   Total Distance = Distance$_1$ + Distance$_2$
*   Total Distance = $150 \text{ miles} + 60 \text{ miles} = 210 \text{ miles}$

**Final Answer:**
The train traveled a total of **210** miles.
qwen3.6:27b chain turn 2
The primary cause of the seasons on Earth is the planet's axial tilt of approximately 23.5 degrees relative to its orbital plane. As Earth orbits the Sun, this tilt causes different hemispheres to receive varying amounts of direct sunlight throughout the year. When a hemisphere is tilted toward the Sun, it experiences summer, while the hemisphere tilted away experiences winter.
qwen3.6:27b chain turn 3
For thirty years, Elias had watched the same grey waves crash against the jagged cliffs without ever seeing anything truly strange. One stormy morning, however, a peculiar glass sphere glinted among the kelp and barnacles. As he picked it up, the orb hummed with a warm, rhythmic pulse that seemed to match his own heartbeat. Instead of a message in a bottle, he realized he had found a captured star waiting to be returned to the sky.
qwen3.6:27b chain turn 4
1. Write clear and descriptive names for variables, functions, and classes.
2. Keep functions small and focused on a single responsibility.
3. Write comprehensive tests to ensure code correctness.
4. Document complex logic or non-obvious assumptions with clear comments.
5. Follow consistent coding standards and formatting within your project.

ornith-1.5:35b-a3b-mq4r

source: bucket sha256_ok: ✅ size_ok: ✅ status: pass reason:

battery — exit 0 seconds 39.4 status pass

mode idx genre finish ctx cached gen ans_words prefill_tok_s decode_tok_s attractor empty runaway recall_ok
battery 0 stop 34 0 127 62 54.1 13.1 False False False True
battery 1 stop 30 0 107 96 476.6 97.2 False False False True
battery 2 stop 31 0 16 13 493.4 126.0 False False False True
battery 3 stop 47 0 22 6 758.3 100.6 False False False True
battery 4 stop 47 0 17 7 730.0 85.4 False False False True
ornith-1.5:35b-a3b-mq4r battery turn 0
```python
def longest_substring_no_repeats(s: str) -> str:
    start = 0
    max_start = 0
    max_length = 0
    seen = {}

    for end, char in enumerate(s):
        if char in seen and seen[char] >= start:
            start = seen[char] + 1
        seen[char] = end
        if end - start + 1 > max_length:
            max_length = end - start + 1
            max_start = start

    return s[max_start:max_start + max_length]
```
ornith-1.5:35b-a3b-mq4r battery turn 1
The sky appears blue during the day because sunlight interacts with atmospheric gases through a process called Rayleigh scattering, in which shorter blue wavelengths scatter more readily off air molecules than longer wavelengths. At sunset, the sun sits lower on the horizon, so its light must travel through a greater thickness of atmosphere, scattering away most of the blue light and allowing the longer red and orange wavelengths to dominate the view. This combination of wavelength-dependent scattering and the extended atmospheric path is what shifts the sky's colors from blue to red as the day ends.
ornith-1.5:35b-a3b-mq4r battery turn 2
The capital of France is Paris, and the Seine River runs through it.
ornith-1.5:35b-a3b-mq4r battery turn 3
{"name": "Alice", "age": 34, "city": "Lisbon"}
ornith-1.5:35b-a3b-mq4r battery turn 4
17 + 26 = 43

Answer: 43

chain — exit 0 seconds 21.7 status pass

mode idx genre finish ctx cached gen ans_words prefill_tok_s decode_tok_s attractor empty runaway recall_ok
chain 0 length 44 0 256 151 537.5 119.2 False False True True
chain 1 stop 355 0 150 71 2220.7 59.4 False False False True
chain 2 stop 531 505 80 65 482.6 91.9 False False False True
chain 3 stop 645 611 113 91 553.3 73.1 False False False True
chain 4 stop 790 758 113 90 520.6 36.6 False False False True
ornith-1.5:35b-a3b-mq4r chain turn 0
```python
def merge_sorted(a, b):
    """Merge two sorted lists into a single sorted list.

    Uses the classic merge strategy from merge sort: walk both lists
    simultaneously, always taking the smaller front element. This runs
    in O(n + m) time without needing to call sorted().

    Args:
        a: A sorted list.
        b: A sorted list.

    Returns:
        A new sorted list containing all elements from a and b.
    """
    i = j = 0
    result = []

    while i < len(a) and j < len(b):
        if a[i] <= b[j]:
            result.append(a[i])
            i += 1
        else:
            result.append(b[j])
            j += 1

    # Append any remaining elements from either list.
    result.extend(a[i:])
    result.extend(b[j:])

    return result
```

This implementation follows the standard two-pointer merge approach. Since both input lists are already sorted, we compare the front elements and always advance the pointer of whichever element we consumed. The final two `extend` calls handle whatever remains in whichever list wasn't fully consumed
ornith-1.5:35b-a3b-mq4r chain turn 1
## Step 1: First Leg of the Journey

**Distance = Speed × Time**

- Speed: 60 mph
- Time: 2.5 hours

$$60 \times 2.5 = 150 \text{ miles}$$

## Step 2: Second Leg of the Journey

- Speed: 40 mph
- Time: 1.5 hours

$$40 \times 1.5 = 60 \text{ miles}$$

## Step 3: Add the Distances Together

$$150 + 60 = 210 \text{ miles}$$

---

**Total distance traveled: 210 miles**
ornith-1.5:35b-a3b-mq4r chain turn 2
The seasons on Earth are caused primarily by the tilt of Earth's axis, which is inclined about 23.5 degrees relative to its orbital plane. As Earth orbits the Sun throughout the year, this tilt causes different hemispheres to receive varying amounts of direct sunlight depending on their orientation. When one hemisphere is tilted toward the Sun, it experiences summer, while the opposite hemisphere simultaneously winter.
ornith-1.5:35b-a3b-mq4r chain turn 3
Every dawn, Mara climbed the winding stairs to sweep the horizon with her lantern's steady gaze, but this morning something glimmered among the black rocks that no beam could have revealed. She found a small wooden chest, salt-crusted and barnacled, its brass latches corroded into the shape of forgotten names, yet somehow still shut tight against the sea. As she pried it open with trembling fingers, she discovered not treasure but a bundle of letters, each one addressed to a keeper she had never met, dated decades before she was born.
ornith-1.5:35b-a3b-mq4r chain turn 4
1. Use clear, descriptive names for variables and functions so intent is immediately obvious to anyone reading the code.
2. Keep functions small and focused, ensuring each does a single job rather than combining multiple concerns.
3. Write consistent formatting and follow a style guide so the entire codebase looks uniform regardless of author.
4. Add concise comments explaining the why behind complex logic, not the what, since code already states what it does.
5. Handle errors explicitly and predictably so failures are easy to trace, debug, and recover from.

lfm2.5:1.2b

source: bucket sha256_ok: ✅ size_ok: ✅ status: pass reason:

battery — exit 0 seconds 8.1 status pass

mode idx genre finish ctx cached gen ans_words prefill_tok_s decode_tok_s attractor empty runaway recall_ok
battery 0 stop 0 0 121 58 None 224.07 False False False True
battery 1 stop 0 0 79 71 None 225.71 False False False True
battery 2 stop 0 0 15 13 None 230.77 False False False True
battery 3 stop 0 0 26 8 None 228.07 False False False True
battery 4 stop 0 0 20 11 None 227.27 False False False True
lfm2.5:1.2b battery turn 0
```python
def longest_unique_substring(s):
    seen = {}
    start = 0
    max_len = 0
    max_sub = ""

    for i, char in enumerate(s):
        if char in seen and start <= seen[char]:
            start = seen[char] + 1
        else:
            if i - start + 1 > max_len:
                max_len = i - start + 1
                max_sub = s[start:i+1]

        seen[char] = i

    return max_sub
```
lfm2.5:1.2b battery turn 1
The sky appears blue during the day because sunlight scatters off air molecules and small particles in a process called Rayleigh scattering, which makes blue wavelengths dominate the light reaching our eyes. At sunset, the sky appears red because the sun is lower on the horizon, so the light passes through more atmosphere, scattering away the shorter blue wavelengths and allowing longer red wavelengths to dominate the light that reaches us.
lfm2.5:1.2b battery turn 2
The capital of France is Paris, and the Seine River runs through it.
lfm2.5:1.2b battery turn 3
{
  "name": "Alice",
  "age": 34,
  "city": "Lisbon"
}
lfm2.5:1.2b battery turn 4
Let's calculate the sum: 17 + 26 equals 43.  
Answer: 43

chain — exit 0 seconds 14.0 status pass

mode idx genre finish ctx cached gen ans_words prefill_tok_s decode_tok_s attractor empty runaway recall_ok
chain 0 stop 0 0 237 130 None 165.16 False False False True
chain 1 stop 0 0 132 91 None 166.67 False False False True
chain 2 stop 0 0 65 58 None 156.63 False False False True
chain 3 stop 0 0 84 63 None 152.45 False False False True
chain 4 stop 0 0 58 40 None 152.63 False False False True
lfm2.5:1.2b chain turn 0
```python
def merge_sorted(a, b):
    """
    Merges two sorted lists into a single sorted list.
    
    Parameters:
    a (list): The first sorted list.
    b (list): The second sorted list.
    
    Returns:
    list: A new sorted list containing all elements from both a and b.
    """
    i, j = 0, 0
    merged = []
    
    # Traverse both lists and append smaller element from either list
    while i < len(a) and j < len(b):
        if a[i] < b[j]:
            merged.append(a[i])
            i += 1
        else:
            merged.append(b[j])
            j += 1
    
    # Append remaining elements from list a
    while i < len(a):
        merged.append(a[i])
        i += 1
    
    # Append remaining elements from list b
    while j < len(b):
        merged.append(b[j])
        j += 1
    
    return merged
```

This function combines two sorted lists into one sorted list efficiently using a two-pointer technique.
lfm2.5:1.2b chain turn 1
Here are the steps to calculate the total distance traveled by the train:

1. Calculate the distance traveled at 60 mph:
   Distance = Speed × Time
   Distance at 60 mph = 60 mph × 2.5 hours = 150 miles

2. Calculate the distance traveled at 40 mph:
   Distance = Speed × Time
   Distance at 40 mph = 40 mph × 1.5 hours = 60 miles

3. Add both distances together:
   Total distance = 150 miles + 60 miles = 210 miles

Final answer: The train traveled a total of **210 miles**.
lfm2.5:1.2b chain turn 2
The seasons on Earth are caused by the tilt of the Earth's axis as it orbits the Sun, leading to varying angles of sunlight throughout the year. This tilt results in different amounts of direct sunlight reaching various parts of the planet during different seasons. Consequently, we experience the cyclical changes in weather and climate known as seasons.
lfm2.5:1.2b chain turn 3
As the lighthouse keeper tended to his routine tasks, he noticed something unusual washed up on the rocky shore. Curiosity piqued, he examined the curious object, a glowing orb amid the tide. The keeper reached in to retrieve it, feeling an ethereal energy flow through him. Suddenly, the orb illuminated the sky, revealing a hidden message that connected the past to the present.
lfm2.5:1.2b chain turn 4
1. Use clear and consistent naming conventions.  
2. Organize code into modular, reusable functions.  
3. Comment on complex sections to enhance clarity.  
4. Keep the code structure simple and avoid unnecessary nesting.  
5. Regularly test and refactor to maintain readability.

qwen3.8:27b-mq4-xt

source: bucket sha256_ok: ✅ size_ok: ✅ status: pass reason:

battery — exit 0 seconds 23.8 status pass

mode idx genre finish ctx cached gen ans_words prefill_tok_s decode_tok_s attractor empty runaway recall_ok
battery 0 stop 34 0 143 67 296.2 29.1 False False False True
battery 1 stop 30 0 86 75 424.8 49.0 False False False True
battery 2 stop 31 0 19 16 439.3 49.0 False False False True
battery 3 stop 47 0 31 8 481.7 49.0 False False False True
battery 4 stop 47 0 17 7 480.0 49.0 False False False True
qwen3.8:27b-mq4-xt battery turn 0
```python
def longest_substring_without_repeating(s: str) -> str:
    if not s:
        return ""
    
    char_index = {}
    start = 0
    max_start = 0
    max_length = 0
    
    for end, char in enumerate(s):
        if char in char_index and char_index[char] >= start:
            start = char_index[char] + 1
        char_index[char] = end
        if end - start + 1 > max_length:
            max_length = end - start + 1
            max_start = start
    
    return s[max_start:max_start + max_length]
```
qwen3.8:27b-mq4-xt battery turn 1
During the day, sunlight scatters off the molecules in the atmosphere, with shorter blue wavelengths scattering more efficiently than other colors, making the sky appear blue to our eyes. At sunset, the light travels through a much longer path in the atmosphere, causing most of the blue light to scatter away before reaching us. This leaves the longer red and orange wavelengths to dominate the view, resulting in the characteristic colors of the evening sky.
qwen3.8:27b-mq4-xt battery turn 2
The capital of France is Paris, and the river that runs through it is the Seine.
qwen3.8:27b-mq4-xt battery turn 3
{
  "name": "Alice",
  "age": 34,
  "city": "Lisbon"
}
qwen3.8:27b-mq4-xt battery turn 4
17 + 26 = 43

Answer: 43

chain — exit 0 seconds 22.2 status pass

mode idx genre finish ctx cached gen ans_words prefill_tok_s decode_tok_s attractor empty runaway recall_ok
chain 0 stop 44 0 122 51 388.4 48.9 False False False True
chain 1 stop 226 44 238 120 770.3 48.9 False False False True
chain 2 stop 494 44 74 58 784.8 49.3 False False False True
chain 3 stop 606 44 94 78 867.7 49.1 False False False True
chain 4 stop 736 44 91 68 910.6 49.2 False False False True
qwen3.8:27b-mq4-xt chain turn 0
```python
def merge_sorted(a, b):
    """Merge two already-sorted lists into one sorted list."""
    result = []
    i, j = 0, 0
    while i < len(a) and j < len(b):
        if a[i] <= b[j]:
            result.append(a[i])
            i += 1
        else:
            result.append(b[j])
            j += 1
    # Append any remaining elements
    result.extend(a[i:])
    result.extend(b[j:])
    return result
```
qwen3.8:27b-mq4-xt chain turn 1
To find the total distance traveled, we calculate the distance for each leg of the trip separately using the formula:

**Distance = Speed × Time**

### Step 1: First Leg
*   **Speed:** 60 mph
*   **Time:** 2.5 hours

$$ \text{Distance}_1 = 60 \text{ mph} \times 2.5 \text{ hours} = 150 \text{ miles} $$

### Step 2: Second Leg
*   **Speed:** 40 mph
*   **Time:** 1.5 hours

$$ \text{Distance}_2 = 40 \text{ mph} \times 1.5 \text{ hours} = 60 \text{ miles} $$

### Step 3: Total Distance
Add the distances from both legs together:

$$ \text{Total Distance} = 150 \text{ miles} + 60 \text{ miles} = 210 \text{ miles} $$

### Final Answer
The train traveled a total of **210 miles**.
qwen3.8:27b-mq4-xt chain turn 2
The seasons are caused by the Earth's 23.5-degree axial tilt as it orbits the Sun. During the year, this tilt causes different hemispheres to be angled toward or away from the Sun, resulting in varying angles of sunlight and day lengths. When a hemisphere is tilted toward the Sun, it experiences summer, while the opposite hemisphere experiences winter.
qwen3.8:27b-mq4-xt chain turn 3
Elara wiped the salt from her eyes as the foghorn groaned against the thick gray morning. She stepped out onto the jagged rocks to clear the debris, expecting only driftwood and broken glass. Instead, her boots stopped at the sight of a brass pocket watch, its face cracked but its hands still ticking steadily. She recognized the intricate engraving on the back, a symbol that belonged to her grandfather, who had vanished into the sea forty years prior.
qwen3.8:27b-mq4-xt chain turn 4
1. Write descriptive names for variables, functions, and classes to make code self-documenting.
2. Keep functions small and focused on a single responsibility to simplify testing and reuse.
3. Add concise comments explaining why code exists, not what it does.
4. Consistently format code using a style guide or formatter to reduce visual noise.
5. Write automated unit tests for new features and bug fixes to prevent regressions.

kernel

status: pass

report pass: True

@hipfire-sol

hipfire-sol Bot commented Sep 4, 2026

Copy link
Copy Markdown

hw-gate sol verdict

{
  "claim_verdict": "not-exercised",
  "confidence": 0.93,
  "coverage": {
    "gaps": [
      "The exact-gfx1100 DFlash fusion and MQ4-V2 split-K kernels were not exercised by the Redline run: its draft is null and its model is qwen3.6-27b.mq4 rather than the qwen3.8 MQ4-V2 campaign fixture.",
      "No hardware output from test_mq4v2_residual_ksplit_gfx1100 or the seven new fusion parity examples is included, so the changed GPU bytes lack independent parity evidence.",
      "No kill-switch on/off token comparison is present for the qwen3.8 DFlash path.",
      "The claimed 285 versus approximately 209 tok/s comparison was not benchmarked by hw-gate.",
      "The policy ceiling increase in scripts/leanup-thresholds.txt from 237 to 247 remains unexplained and requires maintainer review."
    ],
    "surfaces_evidenced": [
      "load",
      "serve",
      "graph-capture",
      "replay",
      "non-DFlash kernel dispatch",
      "gfx1201 fallback"
    ],
    "surfaces_touched": [
      "kernel",
      "load",
      "serve",
      "speculative-decode",
      "graph-capture",
      "replay",
      "policy"
    ]
  },
  "decision": "needs-human",
  "eyeball": [
    "The qwen3.8:27b-mq4-xt battery and chain outputs on gfx1100 and gfx1201 are coherent and contain no attractors or special-token leakage, but they do not establish that DFlash or the new kernels ran.",
    "The ornith-1.5:35b-a3b-mq4r first chain turn reached the 256-token limit on both lanes and is marked runaway; the visible text remains coherent, so this is not evidence of a regression but merits human awareness.",
    "The gfx1100 Redline report is bit-exact across HIP, blob, and PM4/AQL for logits, KV, recurrent state, and GDN frame, but it covers a non-DFlash qwen3.6 path."
  ],
  "phase": "verdict",
  "rationale": "All load and serve fixtures passed on both gfx1100 and gfx1201, and decoded outputs were coherent. The non-DFlash Redline route also passed bit-exact HIP/blob/PM4 parity. However, the principal changes at crates/rdna-compute/src/gemm.rs:28039, crates/hipfire-dispatch/src/families/attention.rs:599, and the new gfx1100 fusion kernels were not demonstrated on the claimed DFlash MQ4-V2 route. The performance and token-identity claim is therefore not exercised. Because this is a kernel/speculative-decode change with missing direct parity evidence and also raises a governance threshold at scripts/leanup-thresholds.txt:98, human review is required.",
  "regressions": []
}

Floor: hard=['policy_paths: scripts/leanup-thresholds.txt'] soft=["coverage_gaps: ['The exact-gfx1100 DFlash fusion and MQ4-V2 split-K kernels were not exercised by the Redline run: its draft is null and its model is qwen3.6-27b.mq4 rather than the qwen3.8 MQ4-V2 campaign fixture.', 'No hardware output from test_mq4v2_residual_ksplit_gfx1100 or the seven new fusion parity examples is included, so the changed GPU bytes lack independent parity evidence.', 'No kill-switch on/off token comparison is present for the qwen3.8 DFlash path.', 'The claimed 285 versus approximately 209 tok/s comparison was not benchmarked by hw-gate.', 'The policy ceiling increase in scripts/leanup-thresholds.txt from 237 to 247 remains unexplained and requires maintainer review.']", 'model needs-human'] model_decision=needs-human final=needs-human

@hipfire-sol hipfire-sol Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hw-gate sol verdict block: Block is mandatory for the failed requested fixture. The clean qwen3.6 Redline result does not establish parity for the new gfx1100 MQ4-V2 DFlash kernels selected from crates/rdna-compute/src/gemm.rs, and the evidence contains no run of the author's exact merge-sort performance fixture. Therefore neither the 285-versus-209 tok/s claim nor identical-token behavior on the changed path was exercised.

@hipfire-fable

hipfire-fable Bot commented Sep 4, 2026

Copy link
Copy Markdown

announcement: Fable unavailable; holding for human review. omp decide: no JSON object in assistant text

hard floor: ['hw_run_result=failure', "evidence verdict='fail'", 'policy_paths: scripts/leanup-thresholds.txt']

soft floor: ['coverage_gaps: ['The Redline report passed on qwen3.6-27b.mq4 and recorded legacy kernels, not the new MQ4-V2 DFlash verify/fusion path on qwen3.8:27b-mq4-xt.', "No hardware measurement exercised the claimed merge-sort fixture at 285 tok/s versus master's approximately 209 tok/s with token-identity comparison.", 'The hiptrx lane did not produce binaries and failed after a 1200-second build.', 'The policy-ceiling change in scripts/leanup-thresholds.txt requires human review.']']

@hipfire-fable hipfire-fable Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fable unavailable; holding for human review. omp decide: no JSON object in assistant text

…robench

Default stays device 0 / 960 GB/s (7900 XTX). Lets the same binary
run on the gfx1151 8060S against its own LPDDR5X roofline.
gemm_mq4g256v2_residual_wmma is the gfx11-only kernel; on gfx1201 it
fails to compile (gfx11 WMMA intrinsic). Production dispatch goes via
gemm_hfq4g256_residual_mq4v2 which routes gfx12 -> _wmma_gfx12; the
bench now calls the same entry so every card fires its real kernel.

gfx1201 R9700 (640 GB/s): every projection at 82-107% of roofline,
64-layer sum 22.7 ms vs 21.1 floor = 1.07x. gfx12 verify is already
at the wall.
Base gemm_mq4g256v2_residual_wmma launches one wave32 per 16x16 tile:
at N=16, M=5120 only 320 waves over 96 CUs (~3.3/CU), 23-25% of roof.
New GEN_RESID_KSPLIT_LDS(KW): KW waves own disjoint K-ranges of the same
16x16 tile, reduce fp32 accs through KW KiB LDS in fixed wave order, wave 0
applies the single Y +=. Grid ceil(M/16) x ceil(N/16), block 32*KW.

Dispatch: exact gfx1100, non-replay/non-capture, batch<=16, kw table
kw=4 (K<=8192) / kw=8 (K>8192) relaxed to dividing KW; else base.
Parity gate relL2<=1e-5 (association differs: not bit-exact).
Gate was below the fp32 rounding floor (even single-joint kw2 gives
2.65e-5 at K=17408). Harness now also builds f64 truth per (shape,N)
(exact kernel dequant, RN-even f16 X like the staging kernel, f64
ascending-K accumulation) and prints relL2(base,f64) | relL2(ks,base) |
relL2(ks,f64) + maxAbs(ks,f64) + frac|ks-base|>1e-3, documenting that the
split-K delta is association noise no farther from truth than base.
E2E showed the tier unreachable in production: the daemon captures the
verify forward into a HipGraph after one warmup, and the
!graphs.capture_mode guard (copied from mw_lds) baked the BASE kernel
into every replayed cycle. Drop the capture guard for the ksplit tier
only (keep !replay.is_recording() for Redline tapes; mw_lds untouched).
Capture safety: deterministic fixed wave-order LDS reduction, no
atomics, launch_maybe_blob records the blob ABI under capture, and the
three ks symbols carry the replay.rs kernarg contract; graphs.rs and the
verify-graph path key on nothing kernel-name-specific.

Kill switch: HIPFIRE_RESIDUAL_KSPLIT_OFF=1 (flags.residual_ksplit_off,
default false). Parity harness forces the base oracle through it now
that capture_mode no longer diverts the tier.
Formatting on the two new examples, refreshed rdna-compute map.md, and
the parity example now carries required-features = ["lab"] like every
other rdna-compute example so the default build does not pay for it
(ungated_examples ratchet stays at 48).
…erify tier

New gemm_mq4g256v2_residual_wmma_gfx1100_ldsstage kernel: identical
cooperative 16x512 slab fill and 8-wave K partition as the gfx12
ldsstage design, gfx11-shaped consume (4x half16 fragments per wave,
w32 WMMA, interleaved C). Tier prefers it when K%512==0, else the ks
table; HIPFIRE_RESIDUAL_KSPLIT_OFF=1 disables both,
HIPFIRE_RESIDUAL_LDSSTAGE_OFF=1 forces ks4. Parity example gains an
ldsstage arm under the same 5e-5 gate.
…AL_LDSSTAGE

hipx (7900 XTX): ldsstage parity PASS (relL2 1.1e-5 out, 3.5e-5 down,
both <= 5e-5, f64 floor matched) but lands at ~53% of roofline
(out 34.2us vs 25 gate, down 94.6us vs 65 gate) — better than ks4's
~48% yet short of the 70% gate. Root cause: 126 VGPRs cap occupancy
at 1 WG/CU on gfx1100 (ks4: 62 VGPRs, 4 WGs/CU); (256,2) compiles to
identical VGPR/LDS/scratch, so no occupancy change there either.
Per the miss-case clause: ks4 stays the default, ldsstage is opt-in;
replaces the OFF flag with the ON flag.
…GPRs

The fully unrolled 4-fragment consume body holds 4 fragments'
pk/a_reg/b_reg temporaries live at once: 126 VGPRs -> 1 WG/CU on
gfx1100. A rolled loop keeps one fragment live (acc + sc/zp carried):
targets <= 64 VGPRs (2 WGs/CU). Same algorithm, fill, partition,
reduce order; pk words already per-fragment, headers already 2
scalars.
…+ sidecars + kill switches

Behavior-only scaffold (no fusion, no reordering). Extracts the ten
disjoint verify-chunk hooks used by S3/S4/S5/S6/S9 with identical
statements, order, and launches:
- S3: batch_chunk_delta_net_input_projection,
  batch_chunk_delta_net_ffn_gate_up,
  batch_chunk_full_attn_input_projection,
  batch_chunk_full_attn_ffn_gate_up
- S4: batch_chunk_delta_net_output_projection,
  batch_chunk_delta_net_ffn_down,
  batch_chunk_full_attn_output_projection,
  batch_chunk_full_attn_ffn_down
- S5: batch_chunk_delta_net_pre_gdn (returns tree_parents)
- S6: batch_chunk_full_attn_prepare
Threads frozen DflashFusionCtx::{Off,ChainVerify} from
verify_dflash_block_inner (ChainVerify iff tree_verify is None) through
both graph call sites, the eager site, and the retained direct helper;
all default wrappers pass Off.
Adds allocated/freed/byte-accounted but unused F16 sidecars
(x_rot_f16_batch, dn_normed_rot_f16_batch, ffn_hidden_f16_batch,
fa_attn_out_rot_f16_batch, mq_prologue_ctrl) and DflashScratch
(mq_x_rot_f16, noise_tokens). Registers the nine _OFF=1 kill switches
as no-ops in feature_flags.rs.
…dden-ring copies

Specialize the measured num_extract=5 F32 DFlash route: one commit5 launch
replaces the staging->ring row-copy loop in commit_staging_to_ring, one
scatter5 launch replaces the ring->interleaved loop in
scatter_hidden_block_to_interleaved. Five+five / five+one device pointers
travel directly in the kernarg blob (no per-cycle pointer table). The commit
ensures both symbols (it strictly precedes any same-cycle scatter); the
&Gpu scatter path launches via blob when loaded and reports false so the
caller runs today's loop otherwise. Kill switch
HIPFIRE_HIDDEN_SCATTER_FUSE_OFF=1, non-gfx1100, capture/recording, funny
shapes all keep the loops byte-for-byte. Pure F32 copies, one writer per
element: bit-identical by construction.
…target projections

Emit bit-identical FP16 directly into x_rot_f16_batch from
fused_rmsnorm_mq_rotate[_awq]_f16 clones (same op order, (_Float16)
store), consumed by F16-direct qkvza/qkv/gate_up base GEMM launches
that never touch ensure_fp16_x. Exact route only: gfx1100,
DflashFusionCtx::ChainVerify, N<=16, MQ4G256V2, graph-off, no
recording; HIPFIRE_MQ_F16_PROJECTION_OFF=1 restores the oracle path.
Gate: test_mq_f16_projection_producers_gfx1100 (F16 + projection
memcmp, N={1,2,8,16} x K={4096,5120} x AWQ absent/present).
Tail analysis (sweep 96..1344 wgs): fused = G/n + ~1270 us fixed, dominated
by the single-word arrival barrier (1344 serialized atomicAdds on the
critical path) plus the fp16 convert launch. Fixes: (1) X stays F32 and is
RNE-converted inline at the WMMA load — bit-identical to
convert_f32_to_f16 (same cast), dropping the convert launch; (2) per-32-wg
arrival slots with a monotonic launch counter + release word (never reset,
stream-safe), cutting barrier contention ~30x. ctl grows to 44 words.
The cumulative-slot barrier assumed a constant grid: after a TDK_WGS cap
change (or any grid < 1344) wg0 waited for slot sums that could never
arrive — hung the sweep and small-grid runs. Replaced with a fully
symmetric two-level barrier: cohort-last resets its slot, global-last
resets the collector and flips the release sense; spinners exit on sense
change. No monotonic counters, no absolute counts, no grid assumptions.
Capture/replay Q/K blocks ran the conv row loop with two barriers per
row and funneled the norm/interleave through 32 threads (trace: fused
2.20 ms/cycle vs 1.35 ms for the replaced launches). Restructure to
barrier-free conv staging into per-row LDS slots, ONE barrier, the
verbatim 32-lane reduction spilling reciprocals to LDS, then a
256-wide store scatter over (d, r). Store addresses, values, conv
order, and reduction order are unchanged (bit-exact by construction;
parity example is the gate).
Wave-1 hygiene: rustfmt on the 18 touched files, refreshed the four
crate maps, the six new hipfire-arch-qwen35 examples carry
required-features = ["deltanet"] like their siblings (ungated_examples
stays at 48), and the ten new direct gemm_*_f16 call sites in
prefill.rs (S3/S4 fp16-X projection entries) are recorded in the
dispatch-bypass ledger: hipfire-arch-qwen35 127 -> 137, bypass_total
ceiling 237 -> 247. Migrating those through KernelRegistry is a
follow-up; the ledger holds the line meanwhile.
@Kaden-Schutt
Kaden-Schutt force-pushed the feat/dflash-dedicated-kernels-pr branch from 0b6e046 to 87233ea Compare September 4, 2026 23:18
@Kaden-Schutt

Copy link
Copy Markdown
Collaborator Author

Rebased onto current master (0652500c2, i.e. with the three gate fixes from #712) and re-verified the fixture identity on hipx / gfx1100. The 49-commit rebase is bit-clean.

Discarded warmup plus three measured runs, HIPFIRE_HFQ4G256_LDSSTAGE=1 HIPFIRE_VERIFY_GRAPH=0, --max 256 --temp 0.0 --no-chatml --kv-mode q8 --ctx 32768 --no-adaptive-b:

run0 rc=0 :: emitted 157  cycles 11  decode 282.75 tok/s  tau 13.1818  accept 0.8788  tokens_sha=c2313b39
run1 rc=0 :: emitted 157  cycles 11  decode 285.44 tok/s  tau 13.1818  accept 0.8788  tokens_sha=c2313b39
run2 rc=0 :: emitted 157  cycles 11  decode 285.90 tok/s  tau 13.1818  accept 0.8788  tokens_sha=c2313b39
run3 rc=0 :: emitted 157  cycles 11  decode 286.15 tok/s  tau 13.1818  accept 0.8788  tokens_sha=c2313b39

Fixture provenance, since a number without it is not comparable:

value
head 87233eae1 (was 0b6e046f3)
prompt benchmarks/prompts/merge_sort_thinking_off.txt, md5 253c7ac50857fe6d0e10fb0d2c5e35c0
target qwen3.8-27b.mq4v2.xt.hfq (xt), md5 e45d15bfe0c9
draft qwen38-27b-dflash-mq4.hfq, md5 013395583cd0
demo md5 9db1345f13f9

Every run reproduces the canonical identity exactly — 157 tokens / 11 cycles / τ 13.1818 / accept 0.8788 / tokens sha c2313b39 — so the token stream is byte-identical to the pre-rebase measurement, and decode sits in the same 282.8–286.2 tok/s band as the original 285.6 / 282.5 / 285.0 / 284.8.

Gate run 33929015500: both hardware lanes pass (gfx1100 on hipx, gfx1201 on hiptrx). Note for the record that lane ran on 4b:00.0, the Thunderbolt eGPU — see #716; the gate was pinning a HIP index that resolved to the eGPU rather than a mainboard card, which is unrelated to this PR but does mean gfx1201 numbers from before #716 were measured on an x4-linked card.

Still not for merge per your hold. This is the re-gate evidence you asked for after #707 landed.

@hipfire-sol hipfire-sol Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hw-gate sol verdict needs-human: All load and serve fixtures passed on both gfx1100 and gfx1201, and decoded outputs were coherent. The non-DFlash Redline route also passed bit-exact HIP/blob/PM4 parity. However, the principal changes at crates/rdna-compute/src/gemm.rs:28039, crates/hipfire-dispatch/src/families/attention.rs:599, and the new gfx1100 fusion kernels were not demonstrated on the claimed DFlash MQ4-V2 route. The performance and token-identity claim is therefore not exercised. Because this is a kernel/speculative-decode change with missing direct parity evidence and also raises a governance threshold at scripts/leanup-thresholds.txt:98, human review is required.

@Kaden-Schutt

Copy link
Copy Markdown
Collaborator Author

Correcting the record on this PR: the block was not yours, and not the harness either.

Run 33929015500 reports block, but its own lane evidence is verdict: pass — 8/8 modes across both lanes at head 87233eae1:

qwen3.6:27b              battery/chain  exit=0 pass
ornith-1.5:35b-a3b-mq4r  battery/chain  exit=0 pass
lfm2.5:1.2b              battery/chain  exit=0 pass
qwen3.8:27b-mq4-xt       battery/chain  exit=0 pass

The published decision belongs to #682: it carries hw_run_result=failure, evidence verdict='fail', and an announcement about "six refused loads … master says 'no model loaded' for four of them" — source-aware admission, not DFlash verify kernels. #702's decide phase failed before writing its own decision.json, and because upload-artifact runs if: always(), the stale file from the previous run on that runner was published as this PR's verdict.

Fixed in #721 (workspace cleanup plus base/head attribution that the status job cross-checks, so a stale artifact fails as a malfunction instead of being obeyed).

So the current evidence for this PR is: both lanes pass, and the rebase is bit-identical on the canonical fixture (157 tokens / 11 cycles / τ 13.1818 / accept 0.8788 / tokens sha c2313b39, decode 282.75–286.15 tok/s across four runs). Still on your hold — not merging.

Kaden-Schutt added a commit that referenced this pull request Sep 5, 2026
…judged

#702 was blocked tonight by #682's verdict.

Its own lanes were 8/8 pass (run 33929015500, head 87233ea, evidence
`verdict: pass`), yet the run published a decision carrying
`hw_run_result=failure`, `evidence verdict='fail'`, and an announcement about
"six refused loads ... master says 'no model loaded' for four of them" -- which
is #682's source-aware admission work, not a DFlash kernel PR.

Cause: the runner workspace is reused and `upload-artifact` runs
`if: always()`. #702's decide phase failed before writing its own
decision.json, so the file left behind by the previous run on that runner --
#682's re-gate -- was uploaded as `hw-gate-decision` for #702, and the status
job read it and blocked the PR. #705 fixed the same hazard for
`fable-evidence/` and `fable-home/`; decision.json was missed, and it is worse,
because that file is the gate's verdict rather than an input to it.

Two changes, because cleaning is necessary but not sufficient:

1. The decide step removes a stale `decision.json` alongside the evidence dirs,
   so the common case cannot arise.
2. review.py records `base` and `head` in decision.json, and the status job
   refuses a decision whose `head` is not this run's head:
   "decision artifact is for <sha> but this run is <sha> -- stale decision.json
   from a reused workspace; re-run the gate". An artifact from another commit is
   a gate malfunction, not a verdict, so it fails as one instead of being
   obeyed. Artifacts predating this field warn rather than fail, so an in-flight
   run does not break on merge.

The lane evidence already carried base/head for exactly this reason
(hw-gate.json records both); the decision did not.

Test: `test_decision_records_the_commit_it_judged` asserts both fields match
the commit under review. 107/107 hw-gate tests pass.
Kaden-Schutt added a commit that referenced this pull request Sep 5, 2026
fix(hw-gate): a stale decision.json blocked #702 with #682's verdict
Kaden-Schutt added a commit that referenced this pull request Sep 5, 2026
…iffs

Two policy gaps this ladder exposed.

1. The gate never ran DFlash. #686 (draft sidecars), #691 (draft ctor
   rollback), #692 (primer replay) and #702 (dedicated verify kernels) all went
   through with every lane green while speculation never once executed. #692's
   DFlash-arm defect -- primer replay systematically missing the most recent
   assistant body -- was found only because a seat thought to drive twenty turns
   by hand. That is not a gate.

   The load bucket now runs `battery-dflash` and the serve bucket
   `chain-dflash`: the same prompts with `--dflash on` and an explicit
   `--draft`. `on` rather than `auto` because `auto` silently falls back to AR
   when the draft is missing, and a route that can pass without speculating
   proves nothing. The draft is named explicitly because the canonical xt trunk
   is a symlink out of the models dir, so the daemon's filename auto-match finds
   nothing and would run AR.

   `dflash_draft` is a candidate LIST because the lanes hold different drafts:
   hiptrx has qwen36-27b-dflash-mq4.hfq and no qwen38, hipx has
   qwen38-27b-dflash-mq4.hfq and no qwen36. A lane speculates with the first
   candidate it holds; a lane holding none records `skip`.

   `skip` is neither pass nor fail. The aggregation was
   `all(status == "pass")`, which would have counted a skip as a fixture
   failure -- a false negative on evidence the host never had -- while treating
   it as a pass would claim coverage that did not happen. Skips are recorded and
   reported, and a genuine failure alongside a skip still fails.

   Coverage is asymmetric until both hosts hold both drafts. Pulling
   qwen38-27b-dflash-mq4.hfq to hiptrx and qwen36-27b-dflash-mq4.hfq to hipx
   (0.92 GB each) makes it symmetric; that is a disk decision, so the evidence
   says `skip` rather than silently pulling.

2. Sol refused hardware for any diff touching a filesystem path, which caught
   #689 for adding `--prompt-file` to `hipfire bench` and cost that rung a lane
   until `hw-run` overrode it. hipfire is a CLI inference engine: users name
   models, prompts, drafts and sidecars at invocation, and the gate's own
   harness passes exactly those flags. sol.md now separates whose path it is --
   an explicit argument is ordinary product work; credentials, dotfiles, SSH or
   cloud config, /proc or /sys beyond device enumeration, assembled traversal,
   or a read whose result leaves the process still warrant refusal.

Tests: eight new cases in scripts/hw-gate/tests/test_run.py covering flag
translation (battery-dflash -> `--mode battery --dflash on --draft ...`), plain
battery never receiving a draft, per-lane draft selection, skip-not-fail with
the harness never invoked, chain-dflash keeping its own prompts, the
skip-vs-genuine-failure aggregation, and a manifest assertion that the buckets
actually carry the routes. 113/113 hw-gate tests pass.
Share the residual tier selector and include all DFlash scratch buffers in
transactional construction. Preserve existing shapes and admission policy.

CPU: all-target workspace check, 42 crate maps and focused residual test pass.
Direct gfx1100 GPU parity pending; no workflow execution requested.
@Kaden-Schutt

Copy link
Copy Markdown
Collaborator Author

Updated head b119800 with focused residual kill-switch precedence and DFlash scratch-construction rollback fixes only (no unrelated reconciliation branches).

Direct verification on hipx / exact gfx1100:

  • F16 producer and residual-output memcmp: PASS, including simultaneous KSPLIT_OFF=1 + LDSSTAGE=1.
  • Independent parent rerun: PASS. HIP launch trace showed 78 base residual ShaderName entries and no optimized residual shader names under simultaneous flags.
  • Real-model F32 split-K/LDS parity: PASS for all runnable arms, relative L2 <= 5e-5, finite outputs and residual accumulation preserved. Non-divisible split widths are explicit per-arm skips, not skipped-device passes.
  • CPU: workspace all-target check, focused residual regression and 42 crate maps pass.

Raw GPU logs and binary digests: hipx:~/dflash-m0/parity-2026-09-05/. Parent rerun additionally retained in local session evidence pr702-parent-gpu-parity.log.

Scope: targeted residual numeric/routing proof, not whole-PR generation, ordinary-prefill, graph/Redline replay, allocation-failure injection or performance acceptance. No workflows or driver/host changes were used. PR remains open; not merged.

ghazni101 pushed a commit to ghazni101/hipfire that referenced this pull request Sep 5, 2026
…t's raw output on a no-decision

Run 33866758629 (warpfront#702) ended the decide phase in 10 s with "omp decide: no
JSON object in assistant text", and the uploaded fable-evidence/ contained
warpfront#700's fable-summary.md and warpfront#686's route outputs: the workflow does
`mkdir -p fable-evidence fable-home` in a reused runner workspace, so every
session inherits the previous PR's files and can cite them as its own.
`rm -rf` both before the mkdir.

On the no-JSON path review.py discarded the assistant text it had already
extracted, so the artifact carried nothing to diagnose the failure with.
decision.json now records `fable_error` and `fable_raw`
{assistant_text_tail, stderr_tail}; the step log gets the tail too.

103/103 in scripts/hw-gate/tests; workflow YAML parses.
ghazni101 pushed a commit to ghazni101/hipfire that referenced this pull request Sep 5, 2026
review.py writes the seat's full object under `.decision` and the
floor-applied verdict under `.decision_final`. The status step read
`.decision`, got a JSON object, matched the `*)` arm, and went red on
every run — including warpfront#689's successful merge-staging (run 33889229683:
Fable merged 8f3a9b6 to beta as 3149be7, label merged-staging
applied, status "blocked ()").

`jq -r '.decision_final // .decision.decision // "hold"'`: on the warpfront#689
artifact → merge-staging (green); on the warpfront#702 no-decision artifact →
block (red). No change to the floor or the seats.
ghazni101 pushed a commit to ghazni101/hipfire that referenced this pull request Sep 5, 2026
A rung that merges to `beta` stays OPEN by design -- promoting beta -> master
is the maintainer's call -- so `pull_request.merged` is false and the
merged-PR guard from warpfront#712 does not apply. Every later touch of that branch then
re-runs the full gate on work that is already staged: warpfront#692 and warpfront#723 both
re-ran within minutes of their staging merges, taking the runner from live
rungs, and the same pattern accounted for several of the runs cancelled by hand
tonight.

`select` now asks whether the head is an ancestor of the staging branch. If it
is, the evidence exists and the hardware has nothing to add, so `run_hw` is
false: the lanes, Sol's verdict and the decide phase all skip, and the recorded
decision still governs the status. The PR is not touched and no label changes.

Deliberately an ancestor test rather than a SHA equality test: a rung merges as
a staging commit whose parent is the head, so equality would never match, and
an ancestor test also covers a rung whose branch was merged and then pushed
again without new work.

`workflow_dispatch` is unaffected, so a manual re-gate of a staged rung still
runs -- that is the escape hatch for re-measuring after a gate fix, which is
exactly what warpfront#702 needed tonight.

132/132 hw-gate tests pass; the workflow parses and the select job's step list
and `run_hw` expression were checked.
@Kaden-Schutt

Copy link
Copy Markdown
Collaborator Author

Superseded: the full campaign (87233ea) and the tip fix (ResidualVerifyTier / transactional DflashScratch) are already on beta and ship in #730. Closing rather than re-merging against beta-ahead dflash.rs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant