Skip to content

Fix UT capture losing loader-set dispatch metadata; gate the baseline leg on meta.device_kernel - #464

Open
yueliu14 wants to merge 16 commits into
mainfrom
fix/ut-capture-dispatch-fidelity
Open

yueliu14 wants to merge 16 commits into
mainfrom
fix/ut-capture-dispatch-fidelity

Conversation

@yueliu14

@yueliu14 yueliu14 commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator

An extracted kernel task can be named after one GPU kernel and measure another, end to end, with every existing gate passing.

The hole

capture_shapes._snapshot recorded a fixed field list (data/dtype/shape/device/contiguous) and nothing from x.__dict__. Several backends keep their dispatch decision there rather than in the data: aiter's fused-MoE gate is use_mxfp4_flydsl = (... and is_shuffled and ...), where is_shuffled is a plain Python attribute the weight loader attaches with setattr. torch.save does not persist it, and .to(device) returns a fresh tensor with an empty __dict__, so the replayed oracle fell into the CK branch while the captured server had run FlyDSL.

Correctness cannot catch this: the golden is frozen from that same baseline leg, so it grades the wrong branch against its own output and agrees with itself. On the Qwen3.8-2.4T MoE head kernel this produced a 1.55x isolated "win" whose e2e was 1.0034x — the speedup was the branch flip, not the patch.

What changes

Preserve the dispatch metadata (capture_shapes, harness_lib)

  • _snapshot records JSON-safe loader-set tensor attributes under attrs; reconstruct_captured re-applies them after the device move. Values that cannot round-trip (tensors, modules, callables) are dropped rather than repr'd — a restored repr string still reads truthy to a getattr(w, "...", False) gate, which is worse than an absent attribute.
  • meta.capture_env records the dispatch-steering env of the capturing process (tuned-config tables, backend enables, arch pins), for comparison only and never re-exported: replaying with a tuned table the captured server did not have is its own infidelity. Credential-looking names are recorded with the value <redacted> — this runs inside the serving process.

Prove the baseline leg is deployment (harness_lib, leg_runner)

  • leg_runner --mode dispatch reports the GPU kernels a leg actually launches, read off a one-shot torch.profiler trace.
  • assert_baseline_dispatch, called from measure_legs, refuses to measure unless the baseline leg launches meta.device_kernel. Never the candidate — changing which kernel runs is what a candidate is for.
  • A mismatch raises HarnessIncompleteError (exit 3, "regenerate the UT"), never a correctness FAIL: it is a UT-generation defect, not a reason to reject a kernel. The message warns against "fixing" it by exporting a tuned config the captured server did not have.
  • It degrades to {"checked": False, "why": ...} — never to a verdict — when evidence cannot be gathered: no device_kernel, kernel_selection.py not vendored, an empty profile, or a dispatch leg that does not run.
  • Name matching reuses kernel_selection.kernel_matches, which must not drift from canonicalDeviceKernel in e2e_workflow.js.

Retrofit for oracles already on disk (harness_lib)
The flag is not in existing .pt files and cannot be recovered from them, so without this every pre-existing oracle could only fail the new gate with no remedy short of recapturing from a server that may be gone. apply_declared_attrs applies meta.live_tensor_attrs = {operand: {attr: value}} to a rehydrated bundle, addressing operands by kwarg name or "pos[<i>]". It is also the answer when a rehydrator cannot preserve attrs even from a fresh capture: a packed-fp4 operand is materialized by .view(dt)/.set_(), each returning a fresh tensor with an empty __dict__.

iter_eager_cases_from_oracle/eager_cases_from_oracle take an optional meta so the declaration reaches the frozen correctness cases too — applying it to only the timing legs would have correctness grading CK while timing measured FlyDSL, the very split this closes. A declaration matching no tensor operand raises: a near-identical helper already shipped hand-written in one task's cases.py, returned early on an empty spec, and had therefore never once executed.

Do not blame the candidate for the baseline's own nondeterminism (harness_lib)
Following this PR's remedy on the motivating task turns a green UT red. The fixed baseline runs FlyDSL MoE, which accumulates with atomics and does not reproduce itself: recording it twice at the same seed on gfx950 differs by 1.5e-05 absolute on prefill_M16384, and correct's atol = tol*RMS(ref) inflates that into a 0.5594 "relative error" on near-zero elements — exactly the number the candidate was failed for.

baseline_noise_floor records the baseline a second time at the same seed and scores it with the metric the candidate is judged by; check_random_vs_baseline passes (and labels) a case that misses tol but stays inside noise_margin (2x) of that floor. Absent a floor the gate is exactly as strict as before. Cost: one extra oracle leg, ~15-25 s.

Extractor role (kernel_extractor.md)
Vendor kernel_selection.py; require cases.py to rehydrate via h.reconstruct_captured instead of hand-rolling the walk — a hand-written rehydrator is exactly how the attribute is lost. The exit-code contract now covers both raisers: measure_legs is a second source of HarnessIncompleteError, but the documented main() wrapped only run_correctness, so a dispatch mismatch would have escaped as a traceback and scored exit 1 — the code that drops the head — instead of exit 3.

Verification

Unfixed vs fixed against the motivating task, same candidate:

isolated speedup correctness
unfixed (baseline dispatches to CK) 1.5470 PASS
fixed (baseline dispatches to FlyDSL) 1.0605 FAIL, 1 draw of 18

The win collapses, which is the point. The residual FAIL was reproduced with no candidate in the comparison at all — two baseline recordings at the same seed differ by 0.5594 on the same draw, while the CK baseline's own spread is ~8x quieter (max_abs 1.9e-06). Replaying the gate over those two real recordings: the false FAIL goes away with noise_floor on, no other case changes verdict, and an injected uniform 5%-of-RMS error still fails every case.

Report-only sweep, nine existing task dirs (gfx950, sglang v0.5.18, 7-86 s each):

verdict tasks what it means
PASS 2 Qwen MoE controls carrying live_tensor_attrs the fix holds
PASS, but vacuous 1 TileLang DS-V4 task its device_kernel is main_kernel, which TileLang gives every jitted prim_func
raised 3 Qwen MoE tasks without the declaration the bug: baseline runs ck::kernel_moe_mxgemm, meta names the FlyDSL kernel. One was not previously known to be affected
raised 2 tasks (Qwen t32x64x256, MiniMax t64x128x256) same kernel family, different tile: the oracle's shapes never reach the bucket the name came from. Real infidelity the message's causes did not cover — fixed in 614c3c4
unchecked 1 Gemma task its cases.py cannot call the target under a current image, so the leg does not run and the gate degrades instead of blocking — intended behaviour, on a real failure

Five of nine would exit 3 on their first run after this lands; all five are genuine.

End to end against a live server, not a replayed artifact: Qwen3.8-2.4T MXFP4 on gfx950, TP=8/EP=8, capture overlay on aiter.fused_moe:fused_moe. The server loads, decode CUDA-graph capture completes (258.77 s), the benchmark runs to usable_for_acceptance=true, and the capture flushes 4 cases across prefill and decode with oracle_complete=true. With no hand-written live_tensor_attrs, the oracle carries w1/w2 attrs: {is_shuffled: True} straight off the loader. Replaying record 0 on one GPU:

replay arm MoE kernel actually launched
as captured mfma_moe1_silu_mul_afp4_wfp4_bf16_t32x128x256_pm1_async_v32 (+ the matching mfma_moe2_*) — FlyDSL
recorded attrs stripped (pre-fix behaviour) ck::kernel_moe_mxgemm<...> ×2 — CK

The only difference between the arms is that attribute. _env_snapshot inside the sglang image: 22 vars, all dispatch-relevant, an injected GEAK_KB_STORE_TOKEN came back <redacted>.

Getting that run to exist took two further fixes, both of which are "the overlay cannot observe an MXFP4 server it breaks or silently misses":

  • Sub-byte dtypes could not be copied at all (8428dc92). ROCm torch 2.9 has no copy_kernel for float4_e2m1fn_x2, so _snapshot's D2H raised, the blanket except swallowed it, and an MXFP4 capture recorded zero cases while reporting success. Both directions now copy through a uint8 view.
  • The overlay perturbed what it measured (609d81b8). install() runs from the overlay's sitecustomize, i.e. during interpreter startup, and used to import the target module there to wrap it — reordering every later import in the process. Pulling aiter.fused_moe in that early makes FlyDSL's JIT abort the server with LLVM ERROR: Do not know how to expand this operator's operand! on a kernel the identical un-overlaid run compiles fine. Reproduced standalone (one GPU, no model, ~90 s) and bisected to that single import. install() now validates eagerly on what needs no import and arms a sys.meta_path shim that binds when the application imports the module; the non-Python-callable refusal moves to bind time and still raises loudly rather than letting a native callable SIGSEGV the server.

Two deliberate limits: a task passes if any case launches the named kernel (tile selection is shape-dependent, so per-case strictness would reject correct tasks) — uncovered cases are reported in unmatched_cases; and a generic device_kernel such as main_kernel makes the check vacuous rather than wrong.

Also in this PR: the head that never reached a measurement

Everything above fixes a head that measured the wrong kernel. Two further commits fix the other half of the same session. In the 20260907 Qwen3.8-2.4T-A95B-Quark-MXFP4 run, four heads were extracted and one reached the optimization lane (63 min); moe1_silu spent 165 min over 6 attempts and gemm 816 min — 13 h 34 m — over 7 attempts, neither producing a candidate.

A mis-transcribed kernel name was diagnosed as a wrong seam (8d681cfa). kernel_selection.py had one failure code for two unrelated defects. A marker that launched no GPU work means the seam is wrong and the extractor should descend. A marker that demonstrably launched kernels, none matching the declared name, means the seam is live and what is wrong is the hand-transcribed device_kernel string — one _HA_S_ typed as _AS_ is invisible to every other check. Both took the same corrective: descend, carrying ATTEMPTED_TARGET_CALLABLES with "Do not return any value again." That ban is the amplifier — it permanently forbids the correct seam from attempt 2 on, leaving the retry loop with no terminating condition. gemm's selection_validation.json shows the seam it re-hunted for 13.6 h was already right on attempt 1.

  • device_kernel_not_under_target (descend) is now distinct from device_kernel_name_mismatch and device_kernel_not_in_profile (keep the seam, fix the name).
  • A name-only defect no longer bans the seam; the corrective quotes both the kernels the seam launched and the names in PROFILE_TOPN.
  • --check-device-kernel runs before capture: the declared name must appear in a profiler row. No GPU, no server, no capture needed to reject a typo. Same matcher as the run-time gate, so there is still one copy.

Extraction had no wall-clock bound at all (e362c900). A retry count does not bound cost. The real envelope is a product never multiplied out: BASELINE_EXTRACT_RETRIES (3, so 4 invocations) × safeAgent's internal tries (3) × AGENT_TIMEOUT_MS (2 h with no global budget) = 24 h on one head — and the global ELAPSED clock is only armed when time_budget_s is passed, so a budget-less run has no guard at all.

  • One wall-clock budget per head, armed before the first attempt and spanning every retry including safeAgent's internal ones. Default 120 min via args.capture_budget_s, ~1.9× the only extraction in that session that succeeded.
  • Each invocation is capped at what is left (timeoutCapMs); otherwise one invocation could run the full 2 h hung-guard and blow a 2 h budget by itself.
  • The budget is checked before paying for an attempt, and capture_min_attempt_s (default 15 min, a measured server boot) refuses to start one it cannot finish.
  • A head cut by the budget lands on the normal failure path carrying capture_budget_spent, so "ran out of time" is never read as "unextractable".
  • The stopwatch reads elapsed from setTimeout rungs armed at absolute offsets and taken as a monotonic max, because Date.now() / new Date() / Math.random() all throw in a Workflow script.

The three durations are read off the session's logs and selection_validation.json. That 8d681cfa would have cut gemm's 13.6 h, and the ~12.3 h e362c900 would have saved, are inferences over three observation points — neither is a measurement. moe1_silu's 165 min is a third root cause neither commit addresses: 5 of its 6 retries are host OOM materializing a 23 GB recorded oracle. Out of scope here.

Tests

python3 -m unittest discover -s e2e_workflow/scripts/tests: 1255 tests, all pass (one pre-existing collection error from a pytest import in test_e2e_store.py, unrelated). All 8 JS suites pass.

test_selection_name_mismatch.js (11) and test_capture_budget.js (19) extract the real definitions out of e2e_workflow.js — a Workflow script, so it cannot be require()d — and execute them, so editing a test alone cannot satisfy them. The budget tests build the stopwatch over an injected setTimeout and fire the rungs by hand; without that, a stopwatch whose elapsed never updates passes everything else and silently restores the 24 h behaviour.

9e9c6ed0 covers the dispatch-evidence path itself: observed_device_kernels against hand-written chrome traces (only cat: kernel rows are read — cpu_op/ac2g rows carry kernel-ish names and would let any seam certify itself), --mode dispatch profiling the compiled callable when the deployment compiles one, and profile_kernel_names over all four topN document shapes (reading only one yields an empty list, which fails the pre-capture check OPEN).

Migration note for reviewers

assert_baseline_dispatch only fires for tasks whose meta.device_kernel is set and whose dir vendors kernel_selection.py — freshly extracted tasks. Older task dirs degrade to unchecked. Pre-PR oracles that do get regenerated are repaired either by recapturing (preferred — a fresh capture now records attrs on its own) or by declaring meta.live_tensor_attrs with the deployment value; the role doc requires recording why that value is deployment's (a server.log line, a profile), since the gate proves only that the result reaches the right kernel, not that the declared value is right.

Regenerating a UT against the dispatch gate should wire baseline_noise_floor at the same time: the gate's own remedy is what exposes an atomics-nondeterministic baseline, and without a floor that lands as exit 1 on the next author.

… leg

An extracted kernel task can be NAMED after one GPU kernel and MEASURE another,
end to end, with every existing gate passing.

capture_shapes._snapshot recorded a fixed field list (data/dtype/shape/device/
contiguous) and no `x.__dict__`. Several backends keep their dispatch DECISION
there rather than in the data: aiter's fused-MoE gate is
`use_mxfp4_flydsl = (... and is_shuffled and ...)`, where `is_shuffled` is a
Python attribute the weight loader attaches with setattr. torch.save does not
persist it, so the replayed oracle fell into the CK branch while the captured
server had run FlyDSL. `.to(device)` returns a fresh tensor whose __dict__ is
empty, so harness_lib.reconstruct_captured could not have restored it either.

Correctness could not catch this, because the golden is frozen from that same
baseline leg: it grades the wrong branch against its own output and agrees with
itself. On the Qwen3.8-2.4T MoE head kernel that produced a 1.55x isolated
"win" whose e2e was 1.0034x -- the speedup was the branch flip, not the patch.

  * capture_shapes: record JSON-safe loader-set tensor attributes under
    `attrs`, and record the dispatch-steering env under meta.capture_env
    (comparison only -- never re-exported, since replaying with a tuned table
    the captured server did not have is its own infidelity). Values that cannot
    round-trip are dropped rather than repr'd: a repr string still reads truthy
    to a `getattr(w, ..., False)` gate.
  * harness_lib: re-apply `attrs` AFTER the device move in
    reconstruct_captured, and add assert_baseline_dispatch -- the baseline leg
    must launch meta.device_kernel or measure_legs refuses to run. It raises
    HarnessIncompleteError (exit 3, "regenerate the UT"), never a correctness
    FAIL, and stays unchecked when the profile yields no kernels. Kernel-name
    matching reuses kernel_selection.kernel_matches rather than a second copy,
    which must not drift from canonicalDeviceKernel in e2e_workflow.js.
  * leg_runner: new `dispatch` mode reporting the kernels a leg launches.
  * kernel_extractor: vendor kernel_selection.py, and require cases.py to
    rehydrate via h.reconstruct_captured instead of hand-rolling the walk.

Verified on gfx950 with real torch: the attribute is confirmed lost across
torch.save/load and restored by reconstruct_captured onto a cuda tensor, and
observed_device_kernels reads back the kernel a matmul launched with the
matcher recognising it and rejecting an unrelated declared name.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@yueliu14 yueliu14 changed the title Fix UT capture losing loader-set dispatch metadata; gate the baseline… Fix UT capture losing loader-set dispatch metadata Sep 11, 2026
yueliu14 and others added 2 commits September 11, 2026 07:10
…attrs

The previous commit made capture_shapes record loader-set tensor attributes and
made the baseline-leg dispatch gate fail loudly when the leg does not launch
meta.device_kernel. That leaves the oracles already on disk: the flag is not in
the file and cannot be recovered from it, so every one of them can only fail the
gate, with no remedy short of recapturing from a server that may be long gone.

apply_declared_attrs applies meta.live_tensor_attrs = {operand: {attr: value}} to
a rehydrated args bundle, addressing operands by kwarg name or "pos[<i>]". It is
also the answer for a rehydrator that CANNOT preserve attrs even from a new
capture: a packed-fp4 operand is materialized by .view(dt) or .set_(), each of
which returns a fresh tensor with an empty __dict__, so the attribute has to be
re-applied by name after the walk rather than inside it.

A near-identical helper already shipped hand-written in one task's cases.py. It
returned early on an empty spec, its meta field was never populated, and so it
had never once executed — a stale or typo'd operand name reads exactly like
"nothing to restore". apply_declared_attrs therefore RAISES HarnessIncompleteError
on a declaration that matches no tensor operand: a declaration that does not land
restores nothing, and the leg goes on quietly measuring the wrong backend, which
is the very failure this mechanism exists to prevent.

Verified on gfx950 against the oracle that motivated it
(Qwen3.8-2.4T-A95B-MXFP4_mfma_moe1_silu_mul_afp4_wfp4_bf16): declaring
w1/w2.is_shuffled=True moves the baseline leg off ck::kernel_moe_mxgemm onto
mfma_moe1_silu_mul_afp4_wfp4_bf16_t{32,64}x128x256_pm1_async_v32, reproducing the
capture run's "no tuned FlyDSL config ..., using heuristic FlyDSL fallback" line,
and assert_baseline_dispatch goes from raising to passing on decode_M1/decode_M64.
… own leg

Two defects in the two commits above, both found by reading the new code back
against where it actually runs.

capture_shapes runs INSIDE the serving process, and `_ENV_CAPTURE_RE` is broad by
design: `GEAK_KB_STORE_TOKEN` matches `^GEAK_`. meta.json travels with the task
dir into the KB, so the capture would have published the pipeline's own store
token. Credential-looking names are now recorded with the value replaced by
"<redacted>" -- that a variable was SET is dispatch-relevant, its value is not.

assert_baseline_dispatch called `_run_leg` bare, so a leg that could not run at
all -- a task dir vendored before `--mode dispatch` existed rejects it at argparse,
a box without torch.profiler raises on import -- came out as a RuntimeError from
`measure_legs`, not as the "unchecked" its own docstring promises. A leg that
never ran is not evidence that the baseline launched the wrong kernel. It now
degrades to {"checked": False, "why": ...}, same as an empty profile: this gate
must not become a new way for a correct task to fail to measure.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@yueliu14 yueliu14 changed the title Fix UT capture losing loader-set dispatch metadata Fix UT capture losing loader-set dispatch metadata; gate the baseline leg on meta.device_kernel Sep 11, 2026
yueliu14 and others added 5 commits September 11, 2026 07:57
…it code

apply_declared_attrs read only the {"pos": [...], "kw": {...}} split. That is what
the generated tasks happen to build, but the role sketch spells `call` as
`fn(**args)` and `iter_eager_cases_from_oracle` yields a flat mapping -- and on
either of those every declared name landed in `missing` and the helper raised
"is not a tensor operand of this call", sending the author to audit a meta key
that was correct. Both shapes are accepted now, plus a bare positional sequence.

iter_eager_cases_from_oracle/eager_cases_from_oracle take an optional `meta` and
apply the declaration to the cases they yield. Without it the retrofit reached the
TIMING legs only -- cases.py applies it there -- so correctness graded the CK
branch while timing measured FlyDSL. Two gates on two backends is the very split
this mechanism exists to close. Omitting meta leaves the old behaviour.

measure_legs is now a second raiser of HarnessIncompleteError, but the extractor's
exit-code contract wrapped only run_correctness. A dispatch mismatch would have
escaped as an uncaught traceback and scored exit 1 -- the one code reserved for a
genuine kernel failure, which drops the head -- instead of exit 3 "regenerate the
UT". The template now wraps both calls, and the regenerate instruction tells the
reader to branch on WHICH defect the sentinel names.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
No behaviour change beyond two small cleanups: _kernel_matcher registers
kernel_selection in sys.modules only after exec_module succeeds, so a failed
import cannot leave a half-built module that every later call then trusts; and
_ATTR_SKIP drops to the six names that actually collide with first-class snapshot
keys.

Comments and docstrings say the is_shuffled story once each instead of restating
it in five places, and the three apply_declared_attrs "declaration lands on
nothing" cases (unknown name, non-tensor, out-of-range index) are one loop.
Non-test additions: 348 -> ~295 lines.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A report-only sweep of the gate over nine existing task dirs (gfx950, sglang
v0.5.18) raised on five. Three are the bug this PR is about -- the baseline
leg runs ck::kernel_moe_mxgemm where meta names the FlyDSL kernel. The other
two are the same kernel FAMILY at a different tile: the oracle's shapes never
reach the bucket device_kernel was taken from. None of the three causes the
message listed covers that, and the suggested remedies are all wrong for it.

The gate matches if ANY case launches the named kernel, which is right --
tile selection is shape-dependent and one bucket reaching another tile is not
a dispatch flip. But it does mean a passing task can still be timing buckets
its name does not describe, so say which ones.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The baseline leg does not reproduce itself. Recording it twice at the same
seed on gfx950 (FlyDSL MoE, `mfma_moe1_*_persist_cu*`, atomic accumulation)
gives max_abs 1.5e-05 on prefill_M16384 -- and `correct`'s `atol = tol*RMS(ref)`
turns that into a 0.5594 "relative error" on near-zero elements. That is
exactly the 0.55941 that failed run_win_fixed.log with no candidate involved.

So the dispatch fix in this PR, followed to its own remedy, lands the next
author in a false exit-1 correctness FAIL. `baseline_noise_floor` measures the
floor with the metric the candidate is judged by; a case that misses `tol` but
stays inside `noise_margin` x the floor passes and is labelled. Absent a floor
the gate is exactly as strict as before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@yueliu14
yueliu14 marked this pull request as ready for review September 14, 2026 08:47
yueliu14 and others added 8 commits September 14, 2026 16:47
…ng seam

A declared device kernel is hand-transcribed prose. When it matched nothing the
selected seam launched, kernel_selection.py reported `device_kernel_not_under_target`
-- a verdict that indicts the SEAM. The extract retry loop then told the agent the
seam was wrong, banned it via ATTEMPTED_TARGET_CALLABLES, and re-captured.

Against a name typo that repair is unfixable by construction: the one correct seam
is banned after attempt 1 and the search has no terminating condition. One gemm head
spent 13.6h and seven captures there. `aiter.tuned_gemm:gemm_a16w16` was the live seam
from the first attempt and its marker launched the profiled kernel 48 times; the
declared name had been typed `Bias_AS_SAV` for a profile that spells it `Bias_HA_S_SAV`.

Split the verdict so it says WHICH thing to fix:

  device_kernel_not_under_target  the marker launched nothing -- the seam is wrong,
                                  descend (unchanged behaviour)
  device_kernel_name_mismatch     the marker launched kernels but none match the
                                  declared name -- the seam is LIVE, fix the name
  device_kernel_not_in_profile    the name appears in no profiler row at all

Both still fail closed; only the corrective differs. The verdict now also lists what
the seam actually launched (`kernels_under_target`, truncated at 20 with the dropped
count stated, never silently) and the profile's own spellings, so the agent has
something to copy rather than retype.

`--check-device-kernel` runs the last check before any capture: no server, no GPU, no
trace. The extractor role now gates on it, and every kernel_extractor call site is
handed PROFILE_TOPN so it can.

Not fixed here: requiredDeviceKernel prefers the agent-authored h.device_kernel over
the profiler's own entity_evidence.matched_profiled_kernel, so the typo passed that
gate typo-to-typo. The pre-capture check stops it earlier; the precedence is still
backwards.

Tests: 581 python (kernel_selection/capture_shapes/harness_lib/op_bench) + a new
test_selection_name_mismatch.js that extracts the nameOnly predicate from the source
and executes it, so editing the test alone cannot satisfy it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
BASELINE_EXTRACT_RETRIES counts invocations, which is not what extraction costs.
The real envelope is the product of three limits that were never multiplied out:

  BASELINE_EXTRACT_RETRIES (3 -> 4 invocations)
    x safeAgent's internal tries (3)
      x AGENT_TIMEOUT_MS (2h when no global budget is set)
  = up to 24h on a single head

and agentTimeoutFor() only tightens when time_budget_s was passed -- the whole
ELAPSED clock is unarmed otherwise, so a budget-less run has no guard at all.

That envelope was not hypothetical. In the 20260907 session one gemm head spent
13h34m over 7 captures and one moe head 2h45m over 6; NEITHER ever reached the
optimization lane. ~16h of the run produced no kernel work. The only extraction
that did reach the lane took 63min over 3 attempts.

Bound the thing that costs: wall-clock per head, spanning every attempt.

- stopwatch(budgetMs): a relative clock built the same way as the global ELAPSED
  clock (absolute rungs, monotonic max) because Date.now() is unavailable here.
  Unarmed without setTimeout, and then reports Infinity -- never abort work you
  cannot time.
- agentBounded honours opts.timeoutCapMs; safeAgent honours opts.abortIf. Both
  are additive: absent the opt, the cap is Infinity and behaviour is unchanged
  at every existing call site. The abortIf hook is what makes safeAgent's three
  internal tries visible to a caller for the first time.
- extractWithBaseline arms one budget for the whole extraction, caps each attempt
  at what is LEFT (a single invocation could otherwise blow the budget by itself),
  and checks BEFORE paying for a retry rather than after.

Default 120min = ~1.9x the one observed success, and would have cut ~12h off that
session. A head that exhausts it is not silently dropped: it lands on the existing
extraction-failure path, so a dominant head is still flagged and surfaced. The
verdict carries capture_budget_spent and names args.capture_budget_s, because "cut
at the budget" and "unextractable" are not the same failure -- only one is raised
with a knob.

Tests: test_capture_budget.js drives the rungs through an injected setTimeout, so
advancement, monotonicity-under-lateness and reaching zero are actually exercised
rather than assumed; the default is asserted against the three measured runs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The dispatch gate is only as good as the evidence it rules on, and neither the
reader nor the leg mode that feeds it had a test: `observed_device_kernels`
reads GPU kernel names out of a chrome trace, where reading the wrong rows
(`cpu_op`/`ac2g` rows carry kernel-ish names) or losing the per-case keying both
produce a well-formed verdict that nothing downstream can question.

  harness_lib  : only `cat: kernel` rows are read; per-sig keying; dedup in
                 launch order; warmup before profiling (profiling the first call
                 of a JIT op records the tuner's trial kernels); sync on both
                 sides; both activities; the bare-list trace shape; an
                 unreadable trace degrades to "no evidence", never an error;
                 the trace file does not outlive the read. Plus `_kernel_matcher`
                 degrading to None when the vendored kernel_selection.py is
                 absent or fails to load, leaving nothing half-built registered.
  leg_runner   : `--mode dispatch` reports kernels per bucket plus the leg
                 identity, filters on --bucket, calls `c["args"]`, and profiles
                 the COMPILED callable when the deployment compiles one --
                 otherwise it certifies a kernel the timing leg never runs.
  kernel_selection : all four topN document shapes parse (reading only one
                 yields an empty name list, which fails the check OPEN); stray
                 rows are skipped rather than crashing an extraction that runs
                 the check with `|| exit 1`; and an empty profile refuses the run
                 with exit 2 instead of certifying the name it cannot check.

Coverage: harness_lib 30 -> 4 uncovered statements, kernel_selection 9 -> 5,
leg_runner 3 -> 1, which clears the 97% gate.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…an empty profile

Four extractWithBaseline call sites retyped the same ~10-key Inputs object. PROFILE_TOPN
is the load-bearing key -- it is what the new pre-capture --check-device-kernel reads --
so a site that dropped it lost the check silently. extractorInputs()/extractOpInputs()
build it once; the sites shrink to a single call.

test_selection_name_mismatch.js could only assert this by counting two unrelated literals
across the whole file, which any other role's Inputs could satisfy. It now requires every
kernel_extractor call site to build its Inputs through the helper, and the helper to carry
PROFILE_TOPN. Verified by mutation: removing the key from the helper fails the test.

PROFILE_TOPN is empty on a run resumed from a state that predates the profile, and
kernel_selection.py --check-device-kernel then exits 2 via parser.error -- which the role's
`|| exit 1` turned into an aborted extraction for every head. The role now runs the check
only when the file is non-empty and reports the skip, while the CLI keeps failing loudly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ROCm torch 2.9 has no `copy_kernel` for `float4_e2m1fn_x2`, so
`_snapshot`'s D2H raises NotImplementedError. The capture hook's blanket
except swallows it and the run records ZERO cases -- silently, and for
exactly the MXFP4 MoE seams this harness exists to capture. The same
storage copied through a uint8 view needs no per-dtype kernel and is
bitwise-equal; `reconstruct_captured` needs the mirror to get the oracle
back onto the GPU.

Verified on gfx950 / torch 2.9.1+rocm7.2.0: both directions bitwise-equal,
and the full snapshot -> save -> load -> reconstruct round trip keeps the
loader-set `is_shuffled` label on a real fp4 tensor.

An unrelated copy failure (OOM, non-contiguous) re-raises its own cause
rather than the view's, so it stays diagnosable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
install() runs from the overlay's sitecustomize, i.e. during interpreter
startup. It used to import the target module right there to wrap it, which
reorders every later import in the process.

That is not a hypothetical cost. Pulling aiter.fused_moe in from
sitecustomize makes FlyDSL's JIT abort the server with

  LLVM ERROR: Do not know how to expand this operator's operand!

while compiling flydsl_moe1_afp4_wfp4_bf16_t32x128x256_w2 -- a kernel the
identical un-overlaid run compiles fine. Reproduced standalone on gfx950
(no model, one GPU) and bisected to that single import. An instrumentation
hook must not perturb what it observes.

install() now validates eagerly on the things that need no import (byte
budget, persist policy, module root exists) and arms a sys.meta_path shim
that binds the wrapper when the application itself imports the module. The
non-Python-callable refusal necessarily moves to bind time, and still
raises loudly rather than letting a native callable SIGSEGV the server.

Verified end to end against a live Qwen3.8-2.4T MXFP4 server (TP8, EP8):
server loads, decode graph capture completes, benchmark runs to
usable_for_acceptance=true, 0 LLVM errors, and the capture flushes 4 cases
across both regimes with oracle_complete=true. Replaying that oracle
dispatches mfma_moe1_silu_mul_afp4_wfp4_bf16_t32x128x256_pm1_async_v32 --
the FlyDSL kernel the server ran -- while the control arm that strips the
recorded attrs falls to ck::kernel_moe_mxgemm, which is the bug this PR
exists to fix.
RemoteKBStore.materialize() refuses a session whose knowledge document names an
artifact the service's manifest does not hold. That refusal is right: handing an
agent a patch_path that resolves to nothing is worse than a loud failure.

But it was raised from inside cmd_resolve_remote's per-candidate loop, so a
SESSION-level defect became a PAGE-level one, and main()'s never-crash-the-caller
handler turned it into {"read_reason": "exception: ...", "candidates": []} with
exit 0 — indistinguishable from a page holding nothing, so the lane cold-starts
on a kernel it has experience for.

Observed live on geak:kernel:gfx950:fused_moe_kernel:triton:rocm:7.2, where one
2026-08-30 upload that committed patch.diff but not report.md made the page
answer zero candidates. Eight healthy sessions were unreadable, and the ones it
cost were those ranked below the broken record.

Drop the offender, record it under filtered.unusable_sessions, keep reading.
The summary now counts what was offered rather than what was ranked. A page
where every candidate is unusable reports all_candidates_unusable instead of
reading as empty — the two look the same from outside and want opposite fixes.

Caught as (KBStoreError, OSError): the store plane refuses an uncommitted
manifest with the former, the local plane fails mid-copy on a manifest naming a
file that is gone with the latter. Neither is broad enough to swallow a
programming error in the loop.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.

2 participants