Skip to content

Refactor: unify golden's entry point and derive specs from the artifact - #1100

Merged
zhangqi-chen merged 8 commits into
hw-native-sys:mainfrom
zhangqi-chen:golden-refact
Sep 1, 2026
Merged

Refactor: unify golden's entry point and derive specs from the artifact#1100
zhangqi-chen merged 8 commits into
hw-native-sys:mainfrom
zhangqi-chen:golden-refact

Conversation

@zhangqi-chen

@zhangqi-chen zhangqi-chen commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

The golden harness restated in its specs what the compiled program
already declares, and split one pipeline across two entry points. Both
now come from the artifact and from a single run.

  • Stamp each TensorSpec's direction from the artifact's ParamDirection
    instead of restating it as an is_output= argument, so init_value
    means initial content alone and a pure Out may carry one. Removes 459
    is_output= arguments across 150 files, including a DSpark prefill
    helper that read spec.is_output off a freshly built spec -- which now
    raises, since nothing has stamped it yet.
  • Bind L3 dispatch args by position, as L2 already did: drop the
    name-keyed reorder and apply the parameter-order ABI check to L3, so a
    spec list that drifted from its kernel signature is rejected instead of
    silently rebound by name.
  • Pair freqs_cos_local with freqs_cos in the decode_swa / decode_hca /
    decode_csa host signatures, matching both the order their fixtures emit
    and the position_ids_local / position_ids pairing beside them. The
    reorder had been absorbing this.
  • Merge run_jit into run, dispatching on the kernel object: a
    JITFunction exposes compile(); a @pl.program class evaluates to an
    ir.Program, which does not. Rewrites its 172 call sites.
  • Fold the pipeline the two entry points duplicated -- spec validation,
    runtime_dir reuse, ABI check, input generation, golden, dispatch,
    validation, benchmark -- into _run_pipeline. Each entry supplies only
    a compile closure and an optional prologue.
  • Share the runner tests' doubles: one recording _ResidentRT in place
    of five hand-rolled fake workers, a build_dir fixture and an
    _artifact() helper for the scaffolding repeated across 39 tests.
  • Rework the guides that described two entry points, and the ones that
    contrasted their compile_cfg fields, to describe the two kernel forms
    one run accepts.

This is a breaking API change: golden.run_jit and the is_output=
argument no longer exist, and no aliases are kept.

@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 167 files, which is 67 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 4281260a-03e9-4a46-a0b2-d50ab3ef79be

📥 Commits

Reviewing files that changed from the base of the PR and between 7f8d7ea and f23eee8.

📒 Files selected for processing (167)
  • .claude/skills/fmt-coding-style/SKILL.md
  • .claude/skills/test-with-golden/SKILL.md
  • docs/debug-and-tune/debugging.md
  • docs/debug-and-tune/performance-tuning.md
  • docs/debug-and-tune/precision-tuning.md
  • docs/debug-and-tune/ring-heap-and-scope-stats.md
  • docs/get-started/first-kernel.md
  • docs/get-started/installation.md
  • docs/models/deepseek_v4_pro/index.md
  • docs/pypto-coding/distributed-programming.md
  • docs/pypto-coding/pypto-coding-style.md
  • docs/run-and-validate/compile-runtime-workflow.md
  • docs/run-and-validate/golden-harness.md
  • docs/run-and-validate/index.md
  • docs/run-and-validate/save-and-replay.md
  • examples/advanced/allreduce.py
  • examples/advanced/gemm_eltwise.py
  • examples/advanced/multi_proj.py
  • examples/advanced/topk.py
  • examples/beginner/hello_world.py
  • examples/beginner/matmul.py
  • examples/intermediate/gemm.py
  • examples/intermediate/layer_norm.py
  • examples/intermediate/rms_norm.py
  • examples/intermediate/rope.py
  • examples/intermediate/softmax.py
  • golden/__init__.py
  • golden/runner.py
  • golden/spec.py
  • models/deepseek_v4_flash_dspark/decode_compressor_ratio128.py
  • models/deepseek_v4_flash_dspark/decode_compressor_ratio4.py
  • models/deepseek_v4_flash_dspark/decode_cp_token_allgather.py
  • models/deepseek_v4_flash_dspark/decode_csa.py
  • models/deepseek_v4_flash_dspark/decode_fwd.py
  • models/deepseek_v4_flash_dspark/decode_hca.py
  • models/deepseek_v4_flash_dspark/decode_indexer.py
  • models/deepseek_v4_flash_dspark/decode_indexer_compressor.py
  • models/deepseek_v4_flash_dspark/decode_layer.py
  • models/deepseek_v4_flash_dspark/decode_metadata.py
  • models/deepseek_v4_flash_dspark/decode_o_proj.py
  • models/deepseek_v4_flash_dspark/decode_sparse_attn_csa.py
  • models/deepseek_v4_flash_dspark/decode_sparse_attn_hca.py
  • models/deepseek_v4_flash_dspark/decode_sparse_attn_swa.py
  • models/deepseek_v4_flash_dspark/decode_swa.py
  • models/deepseek_v4_flash_dspark/dspark_attention.py
  • models/deepseek_v4_flash_dspark/dspark_context_kv.py
  • models/deepseek_v4_flash_dspark/dspark_drafter.py
  • models/deepseek_v4_flash_dspark/dspark_markov.py
  • models/deepseek_v4_flash_dspark/dspark_prefill.py
  • models/deepseek_v4_flash_dspark/dspark_proj.py
  • models/deepseek_v4_flash_dspark/expert_routed.py
  • models/deepseek_v4_flash_dspark/expert_shared.py
  • models/deepseek_v4_flash_dspark/gate.py
  • models/deepseek_v4_flash_dspark/hc_head.py
  • models/deepseek_v4_flash_dspark/hc_post.py
  • models/deepseek_v4_flash_dspark/hc_pre.py
  • models/deepseek_v4_flash_dspark/lm_head.py
  • models/deepseek_v4_flash_dspark/lookup_embedding.py
  • models/deepseek_v4_flash_dspark/markov_head.py
  • models/deepseek_v4_flash_dspark/moe.py
  • models/deepseek_v4_flash_dspark/prefill_compressor_ratio128.py
  • models/deepseek_v4_flash_dspark/prefill_compressor_ratio4.py
  • models/deepseek_v4_flash_dspark/prefill_cp_token_allgather.py
  • models/deepseek_v4_flash_dspark/prefill_csa.py
  • models/deepseek_v4_flash_dspark/prefill_fwd.py
  • models/deepseek_v4_flash_dspark/prefill_hca.py
  • models/deepseek_v4_flash_dspark/prefill_indexer.py
  • models/deepseek_v4_flash_dspark/prefill_indexer_compressor.py
  • models/deepseek_v4_flash_dspark/prefill_layer.py
  • models/deepseek_v4_flash_dspark/prefill_metadata.py
  • models/deepseek_v4_flash_dspark/prefill_sparse_attn.py
  • models/deepseek_v4_flash_dspark/prefill_swa.py
  • models/deepseek_v4_flash_dspark/qkv_proj_rope.py
  • models/deepseek_v4_flash_dspark/rmsnorm.py
  • models/deepseek_v4_flash_mtp/decode_compressor_ratio128.py
  • models/deepseek_v4_flash_mtp/decode_compressor_ratio4.py
  • models/deepseek_v4_flash_mtp/decode_csa.py
  • models/deepseek_v4_flash_mtp/decode_fwd.py
  • models/deepseek_v4_flash_mtp/decode_fwd_mtp.py
  • models/deepseek_v4_flash_mtp/decode_hca.py
  • models/deepseek_v4_flash_mtp/decode_indexer.py
  • models/deepseek_v4_flash_mtp/decode_indexer_compressor.py
  • models/deepseek_v4_flash_mtp/decode_layer.py
  • models/deepseek_v4_flash_mtp/decode_mtp.py
  • models/deepseek_v4_flash_mtp/decode_sparse_attn_csa.py
  • models/deepseek_v4_flash_mtp/decode_sparse_attn_hca.py
  • models/deepseek_v4_flash_mtp/decode_sparse_attn_swa.py
  • models/deepseek_v4_flash_mtp/decode_swa.py
  • models/deepseek_v4_flash_mtp/expert_routed.py
  • models/deepseek_v4_flash_mtp/expert_shared.py
  • models/deepseek_v4_flash_mtp/gate.py
  • models/deepseek_v4_flash_mtp/hc_head.py
  • models/deepseek_v4_flash_mtp/hc_post.py
  • models/deepseek_v4_flash_mtp/hc_pre.py
  • models/deepseek_v4_flash_mtp/lm_head.py
  • models/deepseek_v4_flash_mtp/lookup_embedding.py
  • models/deepseek_v4_flash_mtp/moe.py
  • models/deepseek_v4_flash_mtp/mtp_projection.py
  • models/deepseek_v4_flash_mtp/prefill_compressor_ratio128.py
  • models/deepseek_v4_flash_mtp/prefill_compressor_ratio4.py
  • models/deepseek_v4_flash_mtp/prefill_cp_csa_draft.py
  • models/deepseek_v4_flash_mtp/prefill_cp_fwd_draft.py
  • models/deepseek_v4_flash_mtp/prefill_cp_hca_draft.py
  • models/deepseek_v4_flash_mtp/prefill_cp_layer_draft.py
  • models/deepseek_v4_flash_mtp/prefill_cp_swa_draft.py
  • models/deepseek_v4_flash_mtp/prefill_cp_zigzag.py
  • models/deepseek_v4_flash_mtp/prefill_csa.py
  • models/deepseek_v4_flash_mtp/prefill_fwd.py
  • models/deepseek_v4_flash_mtp/prefill_hca.py
  • models/deepseek_v4_flash_mtp/prefill_indexer.py
  • models/deepseek_v4_flash_mtp/prefill_indexer_compressor.py
  • models/deepseek_v4_flash_mtp/prefill_layer.py
  • models/deepseek_v4_flash_mtp/prefill_mtp.py
  • models/deepseek_v4_flash_mtp/prefill_sparse_attn.py
  • models/deepseek_v4_flash_mtp/prefill_swa.py
  • models/deepseek_v4_flash_mtp/qkv_proj_rope.py
  • models/deepseek_v4_flash_mtp/rmsnorm.py
  • models/deepseek_v4_flash_mtp/sample.py
  • models/deepseek_v4_pro/decode_attention_csa.py
  • models/deepseek_v4_pro/decode_attention_hca.py
  • models/deepseek_v4_pro/decode_attention_swa.py
  • models/deepseek_v4_pro/decode_compressor_ratio128.py
  • models/deepseek_v4_pro/decode_compressor_ratio4.py
  • models/deepseek_v4_pro/decode_fwd.py
  • models/deepseek_v4_pro/decode_indexer.py
  • models/deepseek_v4_pro/decode_indexer_compressor.py
  • models/deepseek_v4_pro/decode_layer.py
  • models/deepseek_v4_pro/decode_mtp.py
  • models/deepseek_v4_pro/decode_sparse_attn.py
  • models/deepseek_v4_pro/decode_sparse_attn_hca.py
  • models/deepseek_v4_pro/decode_sparse_attn_swa.py
  • models/deepseek_v4_pro/expert_routed.py
  • models/deepseek_v4_pro/expert_shared.py
  • models/deepseek_v4_pro/gate.py
  • models/deepseek_v4_pro/hc_head.py
  • models/deepseek_v4_pro/hc_post.py
  • models/deepseek_v4_pro/hc_pre.py
  • models/deepseek_v4_pro/input_pack.py
  • models/deepseek_v4_pro/lm_head.py
  • models/deepseek_v4_pro/moe.py
  • models/deepseek_v4_pro/mtp_projection.py
  • models/deepseek_v4_pro/prefill_attention_csa.py
  • models/deepseek_v4_pro/prefill_attention_hca.py
  • models/deepseek_v4_pro/prefill_attention_swa.py
  • models/deepseek_v4_pro/prefill_compressor_ratio128.py
  • models/deepseek_v4_pro/prefill_compressor_ratio4.py
  • models/deepseek_v4_pro/prefill_fwd.py
  • models/deepseek_v4_pro/prefill_indexer.py
  • models/deepseek_v4_pro/prefill_indexer_compressor.py
  • models/deepseek_v4_pro/prefill_layer.py
  • models/deepseek_v4_pro/prefill_mtp.py
  • models/deepseek_v4_pro/prefill_sparse_attn.py
  • models/deepseek_v4_pro/qkv_proj_rope.py
  • models/deepseek_v4_pro/rmsnorm.py
  • models/deepseek_v4_pro/synthetic_token_loop.py
  • models/deepseek_v4_pro/utils.py
  • models/qwen3_14b/decode_fwd.py
  • models/qwen3_14b/decode_tq_draft.py
  • models/qwen3_14b/greedy_sample.py
  • models/qwen3_14b/prefill_fwd.py
  • models/qwen3_14b/prefill_tq_draft.py
  • models/qwen3_14b/test_paged_attention_cce.py
  • models/qwen3_14b/test_paged_attention_pypto.py
  • models/qwen3_14b/topk_select.py
  • tests/contract/test_deepseek_v4_pro_moe_protocol.py
  • tests/golden/test_runner.py
  • tests/golden/test_spec.py

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

The kernel signature declares every parameter's direction and the harness
already reads it back off the compiled program. TensorSpec restated it as
is_output, and the missing Out-vs-InOut bit rode on init_value, so
init_value could not mean "initial content" alone.

- Drop is_output; add a non-init `direction` stamped from the artifact's
  ParamDirection in _validate_compiled_spec_abi, before any tensor is
  allocated. Direction is no longer compared, so a spec cannot declare one.
- Derive is_output / is_input from it. Reading either before the stamp
  raises instead of silently reporting "not an output", which would drop
  the tensor from validation.
- Route the four init_value-as-direction decisions through is_input:
  _required_files, both _prepare_inputs branches, and _compute_golden.
- Keep a direction check for scalars: a ScalarSpec must be In.
- Remove 432 is_output= arguments across 144 spec builders, six helper
  parameters that only forwarded it, and the two loops left empty.
- Invert two contract assertions: they pinned the duplicated declaration,
  and now guard against it returning.

A pure Out may now carry an init_value, which the old ABI check rejected as
an InOut mismatch. A golden can use it to mark the regions a kernel does not
define, for ignore_nan.
The harness carried two mechanisms for one job. L2 built its positional
arg list straight from `specs` and required the spec names to equal the
compiled parameter names element by element; L3 built a name->value map
and reordered it to the artifact's parameter order, checking only that
the name sets matched. With the order check active the reorder is the
identity, so it did work only where that check was disabled -- and there
it absorbed three spec lists that had drifted from their kernel
signature.

- Drop _l3_ordered_args, _l3_ordered_names and _validate_l3_arg_names;
  all four dispatch paths now share _ordered_args, which walks `specs`
  and emits ctypes scalars for execute_compiled or 0-dim value tensors
  for an L3 dispatch
- Apply the _validate_compiled_spec_abi parameter-order check to L3 too,
  so a mis-ordered spec list fails before any tensor is allocated rather
  than being rebound by name
- Pass `specs` to _run_l3_resident, which read the artifact's parameter
  names only because the interleaved tensor/scalar order was lost
- Pair freqs_cos_local with freqs_cos in the decode_swa / decode_hca /
  decode_csa host signatures, matching both the order their fixtures
  emit and the position_ids_local / position_ids pairing beside them
- Rework TestL3ParameterAbi onto the ABI gate, including a case for the
  same-names-wrong-order list the reorder used to rescue
`run` and `run_jit` differed only in how they produced the compiled
program; the ~135 lines around it -- spec validation, runtime_dir reuse,
ABI check, input generation, golden, dispatch, validation, benchmark --
were duplicated verbatim, and had already begun to drift (only run_jit
carried the comment on its L3 dispatch branch).

- Add _run_pipeline holding that shared body. It normalizes the config
  dicts, then calls an entry-supplied compile closure (`ir.compile` vs
  `JITFunction.compile`) with them, so neither entry point repeats the
  preamble or captures the un-normalized dicts
- Give the pipeline an optional prologue for entry-specific spec
  validation, run inside the block that turns a ValueError into a failed
  RunResult. run_jit uses it to load its effective scalars and reject a
  benchmark_step scalar that is not compile_runtime; its return value is
  threaded to the compile closure, so no mutable cell spans the two
- Collapse the two duplicated PASS returns into one _pass helper and the
  L2/L3 benchmark branch into a single call
- Document the shared arguments once on run_jit; run now states only its
  own program/compile_cfg contract
- Label run's stage "Program compile" against run_jit's "JIT compile", so
  a runtime_dir replay says which kind of build it is reusing
- Read boolean env knobs through one _env_flag, resolve `is this L3` for
  _try_l3_dispatch through _is_l3, and import os at module scope instead
  of inside three functions
- Trim docstring passages that recount how the code used to behave
  (_stale_cpps, _report_effective, _resident_loop_sizes,
  _report_l3_per_rank, _run_l3_resident) and drop upstream PR numbers
  that name nothing a reader can act on

golden/runner.py 1897 -> 1776 lines, behaviour unchanged.
Every kernel under examples/ and models/ dispatches through
`golden.run_jit`; `golden.run` has no call site there. Both guides
presented `run` as the path a reader is on.

- Replace "Most examples and model harnesses use golden.run" with the
  actual split, and make the "typical model __main__ block" example call
  run_jit(fn=...) rather than run(program=...)
- Reorder the debugging playbook's compile-failure and PTOAS bullets to
  state run_jit's behaviour first, so a reader debugging a model kernel
  does not wait on a passes_dump/ that only run writes by default
- State skip_ptoas as an ir.compile kwarg before naming which entry point
  accepts it

The run-vs-run_jit compile-configuration tables are unchanged: they are
symmetric reference material, not a recommended path.
The harness exposed two entry points that differed only in how they
produced the compiled program, and `run` -- the `@pl.program` one -- had
no call site left in examples/ or models/. `run` now takes a kernel of
either form and picks the compile path from it.

- Dispatch on the kernel object: a JITFunction exposes `compile()` and
  goes through `JITFunction.compile`; a `@pl.program` class evaluates to
  an `ir.Program`, which does not, and goes to `pypto.ir.compile`
- Split the two compile paths into _jit_entry / _program_entry, each
  returning the (compile_step, prologue, label) triple _run_pipeline
  already consumed, so the shared body is untouched
- Drop run_jit from golden/__init__ and rewrite its 163 call sites; the
  `fn=` keyword is unchanged, and the tests' `program=` becomes `fn=`
- Rework the guides that contrasted the two entry points to contrast the
  two kernel forms instead: golden-harness's "Choose run or run_jit"
  section, the compile_cfg tables in compile-runtime-workflow, and the
  skip_ptoas note in debugging

This is a breaking API change: golden.run_jit no longer exists and no
alias is kept.
Direction is stamped from the compiled artifact, so `is_output=` is no
longer a TensorSpec constructor argument.

- Point the `resident` docstring at declaring the parameter Out / InOut
- Rebuild the style skill's line-length example on `init_value`, which is
  still an argument, and correct its column counts
Each test rebuilt the doubles it needed, so the resident-path tests alone
carried five copies of a fake DistributedWorker and the file repeated the
compiled-artifact namespace 39 times.

- Add one recording `_ResidentRT`: every worker call lands in `ops`, so a
  test asserts on what happened instead of embedding assertions inside
  the fake. With `_resident_dcp` / `_resident_modules` / `_NullCapture` /
  `_stub_l3_helpers`, TestResidentPath drops from 516 lines to 235
- Replace the repeated `tmp_path / "build"` pair with a `build_dir`
  fixture, and the repeated metadata namespace with `_artifact()`
- Rename TestRunJitCompileRuntime to TestJitCompilePath, the entry point
  it now exercises

117 collected tests before and after; 2760 -> 2493 lines.
Kernels added since this branch forked still used the two arguments it
removes.

- Call `run` in prefill_metadata, which was still on `run_jit`
- Drop `is_output=` from prefill_metadata's request_ids spec and from the
  spec-replacement helper in prefill_hca / prefill_csa / prefill_swa.
  That helper read `spec.is_output` off a freshly built spec, which now
  raises: direction is stamped from the compiled artifact, so the
  replacement only has to carry `resident`.
- Name `run` in the three deepseek_v4_pro attention comments
@zhangqi-chen
zhangqi-chen merged commit c96cb94 into hw-native-sys:main Sep 1, 2026
8 of 11 checks passed
@zhangqi-chen
zhangqi-chen deleted the golden-refact branch September 1, 2026 06:21
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