Skip to content

[TRTLLM-16460][feat] agent-flow: trtllm_modeling_v2 workflow for gated ModelingV2 onboarding and perf tuning - #20145

Draft
Wanli-Jiang wants to merge 70 commits into
NVIDIA:mainfrom
Wanli-Jiang:user/williamj/staircase-polish-pr
Draft

Wanli-Jiang wants to merge 70 commits into
NVIDIA:mainfrom
Wanli-Jiang:user/williamj/staircase-polish-pr

Conversation

@Wanli-Jiang

@Wanli-Jiang Wanli-Jiang commented Oct 12, 2026 •

Copy link
Copy Markdown
Collaborator

@coderabbitai summary

Description

What trtllm_modeling_v2 is

trtllm_modeling_v2 (previously staircase-onboard; renamed following review) is an agent-flow workflow with two stages:

  • onboard takes one Hugging Face checkpoint to a gated ModelingV2 target: a flat, self-contained forward at tensorrt_llm/_torch/_experimental/modeling_v2/models/<family>/<checkpoint>__<arch>__<parallel>/, built from catalog entries and the target's own ops/. The target is trusted because it passes accuracy gates, not because it shares abstractions with other models.
  • tune makes a delivered target fast without making it less correct: a config ladder, then a campaign of agent-written candidates, each measured end to end against a same-host control and kept only if it beats the measured noise floor and passes the accuracy gate.

The modeling_v2 catalog, targets and router are already in tree (#19977); this PR is the agent half. An onboard run has five phases:

  1. Preflight. Survey the checkpoint and the launch environment.
  2. Plan. A drafter proposes a staircase of units (core first, then one feature per unit) and a cross-model reviewer reviews it.
  3. Assemble. For each unit, an assembler writes the target, and kernel and modeling smiths fill catalog gaps.
  4. Gate. Boot, accuracy, acceptance and witness gates run at every parallel member.
  5. Deliver. An auditor runs a bounded remediation cycle, then delivery checks run.

Everything is driven by one task.yaml; perf.enabled: true chains tune after delivery, and trtllm-modeling-v2 tune runs it standalone on a delivered target.

Why: onboard

The workflow has onboarded two checkpoints end to end. A MiMo-V2.6 run produced findings F001–F011 and a retrospective; a DeepSeek-V4.1-Flash-NVFP4 run (8 units, about 51 h) produced F001–F051 and a reflection.

In the second run, 9 defects escaped every gate and were found later by hand:

  • Silent accuracy shift. A position defect shifted accuracy on every member. The witnesses compared the engine with itself, and the floor was anchor − 5, about 7 standard errors (F050).
  • Crashes outside the tested shapes. An import-time capacity constant, an int32 overflow, and a recompute past 16K escaped because the tuple the gates ran was treated as the certified set (F045, F047).
  • Untested deployment path. HTTP 400 on every image request through trtllm-serve (F040).
  • No performance gate. A +19% prefill regression went through (F048).
  • Unrepresentative gate environment. One defect was hidden by an autotuner cache the gates never had; one OOM/hang only appeared right after another engine exited.
  • Noisy acceptance gate. 4 prompts reported findings that a 32-prompt paired test showed were noise (F051).

The run also cost 6 session deaths, lock starvation on the shared GPU slots, and about 30 manual claim/dispatch/unlock interventions (F010–F012, F025, F031–F032, F044, F046). Records contradicted each other (F033), and commits carried sandbox placeholders and DCO identity mismatches (F002, F022, F043).

This PR ships the workflow together with the fixes for those findings, condensed into LESSONS.md: each lesson with its symptom, its cause, the in-tree mechanism that now prevents it, and any gap still open.

Why: tune, and what it did on one model

A correct target is not a fast one: the onboarded Qwen3.8-Flash-Next-NVFP4 target (1× GB300, ISL 8192 / OSL 1024, CUDA graphs on, MTP off) started at 0.83× the in-tree model at concurrency 1 (both on their default kernels). The tune stage then ran on it for about 28 h: 30 candidates, 19 kept, 2 delivered as kernel entries. Every keep passed the target's test suite, the modeling_v2 contract tests and gsm8k (anchor 96.36; kept scores 95.91–96.66).

A concurrency sweep afterwards, all three variants on each of 3 hosts (output tok/s/GPU, max_batch_size 128):

concurrency in-tree model (modeling_v2: off, default kernels) target before tune target after tune after / in-tree
1 119.3 99.2 272.0 2.28×
8 712.9 546.5 1,206.2 1.69×
32 1,628.5 1,345.2 2,589.4 1.59×
128 2,675.3 2,243.6 4,318.4 1.61×

The in-tree model in this sweep runs the engine's default kernel switches: moe_config.backend: AUTO, which picks the CUTLASS MoE for this checkpoint, and TRTLLM_LOW_M_GEMM_BACKEND off. With moe_config.backend: TRTLLM and TRTLLM_LOW_M_GEMM_BACKEND=auto, the kernel families the tuned target also uses, the in-tree model reaches 245.6 tok/s/user at concurrency 1 and 3,342 tok/s/GPU at 128 (gsm8k 95.94). Measured on 3 hosts with the tuned target on each (the last row on 2 of them); the ratios are same-host:

in-tree model concurrency 1, tok/s/user concurrency 128, tok/s/GPU after / in-tree
default kernels 119.6 2,672 2.28× / 1.60×
moe_config.backend: TRTLLM and TRTLLM_LOW_M_GEMM_BACKEND=auto 245.6 3,342 1.11× / 1.28×

So most of the gap to the default in-tree model is its kernel selection; what the in-tree model cannot switch to (the target's fusions and kernels below) is worth 1.11× at concurrency 1 and 1.28× at 128. The tune stage does not yet search the reference model's own switches; that is a follow-up below.

Most of the gain is fusion (hyper-connection sites, MoE routing/finalize into neighbouring kernels, PLE), kernel sourcing (FlashInfer GDN and low-M GEMMs, a row-tiled sparse-attention prefill kernel) and one config-ladder rung. The tuned target code is not part of this PR; it lives on its own branch.

What changed (by area)

# Area Main points
1 Workflow core The orchestrator, its six roles plus runner, prompts, the materialized skills, and the gates and witnesses. It also adds the agent-flow runtime package: turn executors (in-process, file dispatch) and command executors (local, slurm, spool, delegated).
2 Envelope and certification serving_envelope and feature_matrix in task.yaml; the certified set is derived from them, not from the gate tuples. A capacity-constant audit (F045); integer-width probes in kernel-verify and a smith brief per call site (F042, F047); a typed certification_gap decision fanned out to verify smiths (F019, F020, F026, F028); early delivery checks as warnings (F041); a preflight refusal of any speculation algorithm the launch path cannot run.
3 Upstream adaptation, no model specifics Per-role backend and model routing through an agents: block (#19522), with Codex roles fixed in-process. Prompt snapshots (#19715), the spill check (#19766), duplicate request ids in file dispatch fixed. Model specifics live in examples/, which a run never materializes.
4 Commit hygiene, pre-merge, embargo commit.sh commits and signs off as the repo user and refuses symlinks, placeholders and out-of-policy paths (F002, F022, F043). trtllm-modeling-v2 premerge lint|ci|copyright|hygiene|split|resign|pr-open|pack; source_embargo enforced with PreToolUse/PostToolUse hooks and an attempt log; opt-in --overlap-units (F027); a delivery tail that audits the run's commits.
5 Ledger and reports An append-only evidence ledger; a verdict goes stale when a later commit touches the paths it covered, and stale verdicts are re-run. The final regression is bound to the delivered tree. Progress and report tables come from the ledger; decision files are never overwritten (F033); journal ordinals are atomic (F013, F014).
6 Gates Accuracy floors of anchor − k·SE and a cross-member finding (F050); a per-prompt paired acceptance gate on natural text (F051, F040, F029, F024); a scheduler-equivalence witness; boot workloads matched on generated text, with a real image for multimodal (F034, F037, F049); a launch-path accuracy smoke through trtllm-serve and the disagg proxy; witnesses at every member; trtllm-modeling-v2 gate <name>.
7 Execution substrate A spool scheduler (priority queue, device slots, wall and memory limits, MPI environment scrubbed) replaces the flock protocol (F046, F011, F012, F031, F032); --tree jobs with mixed-checkout results refused (F044); atomic native rebuilds (F025); sessions declared in task.yaml with planned hand-over; deadlines from job start plus a watchdog; multi-node mn_* launchers; the external-transport driver trtllm-modeling-v2 driver (F010, F017, F030).
8 modeling_v2 as merged (#19977) Catalog entries are OpWrapper classes called through __call__ with every argument at the call site; CELLS and ARCHS are the executable contract, read by the survey and checked by delivery (shared catalog and a target's own ops/). The catalog is its entry files (no index). Delivery checks the core's _select_target over plain PrefillTarget / DecodeTarget classes, a W-row weight table with MODEL_WEIGHTS, and routing that returns the target class. Target selection is the LLM-API argument modeling_v2; gates pass it through the harness and set TRTLLM_MODELING_V2_VALIDATE=1 for the step-contract check.
9 FlashInfer as a sourcing tier Tier 3 of the sourcing ladder is a FlashInfer callable called directly from an entry's __call__. The survey reads the installed package's public API off disk (no import, no GPU) and records which callables the engine already references. Against flashinfer-python 0.6.18: 558 public callables, 510 referenced nowhere in the engine.
10 tune stage tune/: ground truth (baseline, in-tree reference, identity repeats as the noise floor), the config ladder, and the candidate campaign (one hypothesis = one worktree = one tuner turn; same-host controls; stacked evaluation of compatible winners and of near misses; speculative rebases; the keep gate = target suite + contract tests + gsm8k). bench.py (LLM-API yaml configs, --nsys session-mode capture), nsys_summary.py (per step class, CUDA-graph replays placed at their launch), microbench.py, a FlashInfer/kernel-ledger roadmap requirement, and the perf tooling CLI.
11 Docs README (including the tune stage), TROUBLESHOOTING, BUILD_AND_TEST and LESSONS.md; a short "environment failures that read as model failures" table in AGENTS.md.

Outside agent-flow/agent_flow/workflows/trtllm_modeling_v2/ and its tests, the PR touches only:

  • agent-flow/agent_flow/runtime/ (new package; the old runtime.py becomes runtime/portal.py) and agent-flow/tests/runtime/;
  • agent-flow/pyproject.toml: the trtllm-modeling-v2 entry point, package-data, and an E501 per-file ignore for prompt tables;
  • agent-flow/README.md: one sentence;
  • AGENTS.md: one table.

There are no changes under tensorrt_llm/, cpp/ or tests/, and no new dependencies.

Naming

Following review, the workflow is trtllm_modeling_v2 (package), trtllm-modeling-v2 (CLI), TrtllmModelingV2Workflow, and skills trtllm-modeling-v2-* (the repo's trtllm- skill prefix). The workflow's own environment variables use MV2FLOW_*, so they never share a namespace with the engine's TRTLLM_MODELING_V2* switches (and stay clear of MVAPICH2's MV2_*). In the code, "staircase" now appears only in two quoted historical error messages; in prose it is just the shape of a plan (core first, then one feature per unit).

How to run

pip install -e agent-flow                       # provides the trtllm-modeling-v2 CLI
cp agent-flow/agent_flow/workflows/trtllm_modeling_v2/task.example.yaml task.yaml   # then edit it

# 1. Cheapest check first: preflight, envelope derivation and environment probe; no agent turn
trtllm-modeling-v2 --task task.yaml --workspace ws/ --dry-run
trtllm-modeling-v2 --task task.yaml --workspace ws/      # the run (resumable: re-run the same command)

# 2. Performance: chained (perf.enabled: true in task.yaml), or on a delivered target
trtllm-modeling-v2 tune --task task.yaml --workspace ws/
trtllm-modeling-v2 perf ladder run --spec tune.yaml      # tooling: the ladder alone
trtllm-modeling-v2 perf table --baseline A A B C         # a curve table of label dirs

# 3. Where the orchestrator cannot authenticate an agent (sandbox, rotating tokens):
trtllm-modeling-v2 --task task.yaml --workspace ws/ --agent-transport external
trtllm-modeling-v2 driver --workspace ws/ wait        # in the driver session: NEW <id> | ORCHESTRATOR_EXITED | ...
trtllm-modeling-v2 driver --workspace ws/ prompt <id> --claim

# 4. One gate or witness on its own, against a tree
trtllm-modeling-v2 gate <name> --task task.yaml --unit <unit> --member <member> --tree <checkout>

# 5. Before a delivered branch becomes a PR (nothing in the pack pushes)
trtllm-modeling-v2 premerge pack --base origin/main   # lint x2, DCO hygiene, copyright, CI lines as one report

Test Coverage

All tests are CPU-only and need neither GPUs nor model weights. Pass PYTHONPATH=agent-flow when an editable install points at another checkout.

  • pytest agent-flow/tests/workflows/trtllm_modeling_v2: 1870 passed, 2 skipped, including the tune suites (test_tune_stage, test_tune_ladder, test_tune_bench, test_tune_nsys_summary, test_tune_worktree_parallel, ...), the gate, ledger and substrate suites (with the substrate's fault injection), test_delivery against the in-tree gpt_oss and DeepSeek-V3 targets, and test_prompts, which refuses the pre-merge modeling_v2 names in any role prompt.
  • pytest agent-flow/tests (all agent-flow workflows, guarding the shared runtime package): 3524 passed, 5 skipped.
  • Lint: the repo's .pre-commit-config.yaml over every file this PR changes (origin/main..HEAD): all hooks pass.

GPU validation. The tune stage ran end to end on Qwen3.8-Flash-Next-NVFP4 (above) and was started on gpt-oss-120b (one keep, gsm8k pass, before it was stopped). The onboard gates were exercised end to end by the two onboarding runs that produced the findings; the historical-defect replay and a pilot onboarding run on this branch are follow-ups.

Known limitations and follow-ups

  • Historical-defect replay and pilot run of the onboard stage on this branch (targets at least 7 of the 9 escaped defects; pilot compared with the 51 h DeepSeek-V4.1 run).
  • Performance is measured, not gated. The per-commit prefill/decode regression gate (F048) is a follow-up; tune measures but never blocks delivery.
  • The reference model's switches are not tuned. The config ladder skips module knobs for a target, which pins its kernels, but it also never tries them, or engine environment switches such as TRTLLM_LOW_M_GEMM_BACKEND, for the in-tree reference. A reference-side ladder, gated on accuracy, is a follow-up.
  • tune substrate. The spool runs pending jobs in name order, not submission order; long campaigns depend on 4 h interactive sessions being re-submitted; a stopped run has no tune --stop that cancels its jobs and writes the partial summary.
  • No concurrent witness leg yet (batch 1 only); envelope probes use the aggregated quickstart boot.
  • Embargo enforcement applies only to in-process roles whose backend runs SDK hooks; Codex roles and external-transport turns get it as a prompt instruction.
  • Unverifiable backend on external transport (F008).
  • Opt-in unit overlap (--overlap-units, off by default).
  • No DSpark branch in main's quickstart. A dspark spec stops at preflight with an explicit message.

PR Checklist

Please review the following before submitting your PR:

  • PR description clearly explains what and why. If using CodeRabbit's summary, please make sure it makes sense.

  • PR Follows TRT-LLM CODING GUIDELINES to the best of your knowledge.

  • Test cases are provided for new code paths (see test instructions)

  • If PR introduces API changes, an appropriate PR label is added - either api-compatible or api-breaking. For api-breaking, include BREAKING in the PR title.

  • Any new dependencies have been scanned for license and vulnerabilities

  • CODEOWNERS updated if ownership changes

  • Documentation updated as needed

  • Update tava architecture diagram if there is a significant design change in PR.

  • The reviewers assigned automatically/manually are appropriate for the PR.

  • Please check this after reviewing the above items as appropriate for this PR.

@@ -0,0 +1,129 @@
---
name: staircase-modeling-disagg
description: Load when a target must work under disaggregated serving — prefill on one engine, decode on another, with per-sequence state transferred between them. The modeling duty is that EVERY piece of per-sequence state prefill produces is in the transferable set, which for a hybrid model is not just the attention KV pages.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for putting all these together.

  1. Lets try to rename staircase to "trtllm_modeling_v2"?

  2. One open question. Shall each feature have its own skill or it should be part of the main skill with reference doc on how each feature shall be implemented?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

updated codes and comments in #20145 (comment)

@WeiHaocheng

Copy link
Copy Markdown
Collaborator

I am still understanding and reviewing the code in the workflow section.

Regarding the "skills" section, I do not recommend incorporating these skills into the repo. The previous experience of the modeling agent tells us that, first, detailed skills may limit the model's performance. Second, the large amount of information carried in the skills is difficult to maintain, and errors and outdated information will become difficult to manage. We can first place them in an internal small repo. If there are clear AB tests proving that this is effective, then we can incorporate them into the repo.

…emble, gate and deliver a model onboarding

The staircase-onboard agent-flow workflow: a plan phase that surveys the checkpoint and
drafts a staircase of units, per-unit assembly by an assembler agent with kernel and
modeling smiths, boot/accuracy/acceptance/witness gates at every parallel member, a
bounded remediation cycle, and delivery checks. Includes the agent-flow runtime package
(turn and command executors: in-process, file dispatch, local, slurm, spool, delegated)
that the workflow routes its turns and gate commands through, the role prompts, the
materialized skills, and the package's tests.

Squashed from user/williamj/staircase-polish @ c8109d6f90 (42 commits):
- [feat] agent-flow: staircase-onboard workflow
- [refactor] agent-flow: runtime package for turns and commands
- [refactor] agent-flow: route staircase turns and gate commands through the runtime
- [feat] staircase: close UNCOVERED with a bounded remediation cycle
- [feat] agent-flow: run gates on a cluster only an agent can reach
- [feat] staircase: gate every member, survey the demands, admit a new architecture
- [fix] staircase: a checkpoint carrying its own implementation is an unsupported architecture
- [fix] staircase: the accuracy gate cannot spell the topology the boot gate spells
- [fix] staircase: the acceptance gate measured a speculator the unit was not built for
- [fix] staircase: make the multi-rank launch and the supply survey actually work
- [fix] staircase: the acceptance gate needs a stock path, which a new architecture does not have
- [fix] staircase: see the registry's own unsupported-architecture message
- [perf] staircase: stop spending assembler turns on restarts, and make a gate say what it measured
- [feat] staircase: recover six improvements stranded in a sibling checkout
- [fix] staircase: a member overlay must not be written into the source tree
- [doc] staircase: carry the findings a real run produced
- [chore] staircase: classify the in-tree Triton custom op
- [feat] staircase: host offload names its capturable precedent
- [feat] staircase: dspark, bounded-replay and kv_quant feature kinds
- [fix] staircase: a gate test must not find the checkout that holds TMPDIR
- [fix] staircase: the survey must read the in-tree catalog index
- [fix] staircase: an unknown model_type is a new architecture too
- [feat] staircase: defer feature-only smith failures to their unit
- [fix] staircase: a resume collects the answers the dead process never read
- [fix] staircase-onboard: commit.sh signs off (DCO) under git's own identity
- [fix] staircase-onboard: kernel-source registry claims the run's Triton quantization ops
- [fix] staircase-onboard: disagg equivalence witness runs a real, synchronised leg B (F021a-g)
- [fix] staircase-onboard: a registration shim without a target counts as an unsupported architecture
- [fix] staircase-onboard: an assembler blocked on knowledge_gap or environment can be re-entered
- [fix] staircase-onboard: the acceptance gate measures a declared long-answer workload
- [fix] staircase-onboard: token-comparing witness legs can run at batch 1
- [fix] staircase-onboard: the equivalence witness hands leg B an absolute prompts path
- [feat] staircase-onboard: witness blocks can set an environment for both legs
- [feat] staircase: ask targets for their runtime-value dump on every gate and witness run
- [chore] agent-flow: reword two codespell findings in staircase_onboard
- [chore] agent-flow: one-line docstring summaries in the staircase_onboard tests
- [chore] agent-flow: NVIDIA copyright headers on the staircase_onboard files
- [fix] staircase-onboard: kernel-source registry claims the four new Triton custom ops
- [chore] Apply pre-commit formatting to the DeepSeek-V4.1 changes
- [feat] staircase: place targets at models/<family>/<checkpoint>__<arch>__<parallel>/
- [chore] staircase: stop tracking the sandbox's session placeholders
- [fix] staircase: no committed file names one operator's home or scratch path

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…certification of what a target claims

task.yaml declares a serving envelope and a feature-combination matrix; preflight
derives the gate tuples and the certified set from them (replacing 'the tuples the gates
happened to run'). Adds the capacity-constant audit of the target against the envelope,
the per-call-site smith brief and mandatory integer-width probes in kernel-verify, a
typed certification_gap decision fanned out to verify smiths by the orchestrator, early
delivery checks run as warnings after planning and after every unit, and a preflight
refusal of a speculation algorithm the gates' launch path cannot run.

Squashed from user/williamj/staircase-polish @ c8109d6f90 (7 commits):
- [feat] staircase: declare the serving envelope and feature matrix, derive the certified set from them
- [feat] staircase: audit the target's capacity constants against the serving envelope
- [feat] staircase: smith brief per call site, and mandatory integer-width probes in kernel-verify
- [feat] staircase: typed certification_gap decision, fanned out to verify smiths by the orchestrator
- [feat] staircase: run the delivery checks that need no finished target early, as warnings
- [fix] staircase: envelope follow-ups found replaying the DeepSeek-V4.1 spec
- [feat] staircase: preflight refuses a speculation algorithm the gates' launch path has no branch for

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
… prompt snapshots; no model-specific data in the workflow

Adapts the workflow to upstream agent-flow: per-role backend/model routing through an
agents block (NVIDIA#19522), the backend/model named on externally dispatched turns, composed
role prompts snapshotted into the workspace (NVIDIA#19715), the oversized-system-prompt spill
(NVIDIA#19766). Fixes concurrent file-dispatch turns sharing a request id. Moves the
DeepSeek-V4.1 specifics out of skills, registries and the example spec into a worked
example that is never materialized, and replaces tests that read a model PR's files
with fixtures.

Squashed from user/williamj/staircase-polish @ c8109d6f90 (13 commits):
- [fix] staircase: concurrent dispatch turns never share a request id
- [feat] staircase: per-role backend and model routing through the agents block
- [feat] staircase: a dispatched turn names the backend and model its role is configured for
- [feat] staircase: snapshot the composed role prompts into the workspace
- [test] staircase: a role's oversized system prompt reaches the CLI through the spill
- [test] staircase: check the quickstart DSPARK contract against a fixture
- [fix] staircase: claim tree-local Triton custom-op files by content, not by name
- [chore] staircase: the example spec and the schema's messages name no checkpoint
- [feat] staircase: move DeepSeek-V4.1 specifics out of the feature skills into a worked example
- [fix] staircase: delivery accepts the op-matrix test a multi-rank catalog entry has on main
- [test] staircase: the same-process retry test answers only once the retry holds the request
- [doc] staircase: README sections for the envelope, the evidence ledger and commit hygiene
- [doc] staircase: README sections for the gates and the execution substrate; no placeholder left

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…-embargo hooks, unit overlap and delivery audit

commit.sh commits as the repository user with a matching DCO sign-off and refuses
untracked links, sandbox placeholders and paths outside the policy; the pre-merge pack
(staircase-onboard premerge lint|ci|copyright|hygiene|split|resign|pr-open|pack);
source_embargo enforced by PreToolUse/PostToolUse hooks with an attempt log (prompt
instruction for backends without hooks); opt-in --overlap-units that starts the next
unit's assembler in its own worktree (F027); and a delivery tail that audits the run's
commits and writes the pre-merge pack.

Squashed from user/williamj/staircase-polish @ c8109d6f90 (8 commits):
- [feat] staircase: commit helper signs as the repository user and refuses links, placeholders and stray paths
- [feat] staircase: pre-merge pack as `staircase-onboard premerge <step>`
- [feat] staircase: enforce source_embargo with PreToolUse/PostToolUse hooks and log every attempt
- [feat] staircase: opt-in --overlap-units starts the next unit's assembler in its own worktree (F027)
- [feat] staircase: delivery audits the run's commits and ends with the pre-merge pack
- [doc] staircase: name the worked example's embargo in the package: spelling
- [fix] staircase: package: embargo entries stay inside the package and read as reference material
- [fix] staircase: the AST proof's label for a file that does not parse is spelled "unparsable"

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…dation and reports generated from it

An append-only ledger of gate verdicts keyed by tree, member, config and covered code
paths; verdicts invalidated by later commits are queued for re-run and the final
regression is bound to the delivered tree. progress.json/html and the final report's
gate tables are generated from the ledger. Decision files are <unit>-<role>-<turn>.yaml
and never overwritten (F033), journal ordinals are atomic, and catalog/index.yaml is
generated from per-entry fragments (F013/F014).

Squashed from user/williamj/staircase-polish @ c8109d6f90 (10 commits):
- [feat] staircase: append-only evidence ledger for gate verdicts
- [feat] staircase: stale-verdict invalidation, re-run queue and final-regression binding
- [feat] staircase: generate progress.json/html and the final report's gate tables from the ledger
- [fix] staircase: decision files are <unit>-<role>-<turn>.yaml and never overwritten (F033)
- [fix] staircase: Journal.next_ordinal is atomic across threads and processes
- [feat] staircase: generate catalog/index.yaml from per-entry fragments (F013/F014)
- [feat] staircase: the ledger records envelope probes, early checks and delivery checks
- [feat] staircase: a verdict's config fingerprint includes each role's backend and model
- [feat] staircase: the pre-merge pack states the final-regression binding and how to re-check it
- [fix] staircase: catalog index sync is serialized and never undoes a commit that landed

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
… statistical accuracy, per-prompt acceptance, step witness

Accuracy floors from the anchor's standard error with a cross-member finding; a
per-prompt acceptance gate on a natural-text workload; a scheduler-equivalence witness
with an optional step-trace hook; boot workloads declared in task.yaml and matched on
generated text (a real image for multimodal); launch-path accuracy smoke through each
unit's own deployment entry; token witnesses with declared workloads at every member;
and `staircase-onboard gate <name>` to run one gate or witness standalone.

Squashed from user/williamj/staircase-polish @ c8109d6f90 (10 commits):
- [feat] staircase: statistical accuracy floors and a cross-member finding
- [feat] staircase: per-prompt acceptance gate on a natural-text workload
- [feat] staircase: scheduler-equivalence witness with an optional step-trace hook
- [fix] staircase: the envelope's acceptance evidence follows the speculation predicate
- [feat] staircase: boot workload declared in task.yaml, matched on generated text, with a real image for multimodal
- [feat] staircase: launch-path accuracy smoke through each unit's own deployment entry
- [feat] staircase: token witnesses declare their workload and refuse continuations too short to compare
- [feat] staircase: `staircase-onboard gate <name>` runs one gate or witness standalone
- [feat] staircase: feature witnesses run at every member, cheapest first
- [feat] staircase: delivery re-runs the new gate kinds, and the ledger records the statistical floor

Formatting and lint fixes folded in for this commit's files:
- [chore] staircase: apply pre-commit formatting (4 files)

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
… --tree jobs, deadlines, sessions and external driver

A spool scheduler (priority queue and device slots) replaces the flock protocol, with the
legacy watcher kept behind STAIRCASE_SPOOL_WATCHER=legacy; --tree jobs and refusal of
mixed-checkout results; atomic native rebuilds announced to every session; sessions
declared in task.yaml with planned hand-over; deadlines counted from job start,
no-progress detection, host-memory admission and a watchdog; and the external-transport
driver as `staircase-onboard driver`.

Squashed from user/williamj/staircase-polish @ c8109d6f90 (11 commits):
- [feat] staircase: spool scheduler replaces the flock protocol
- [feat] staircase: --tree jobs and refusal of mixed-checkout results
- [feat] staircase: atomic native rebuild announced on every session
- [feat] staircase: sessions declared in task.yaml, rendered entries and planned hand-over
- [feat] staircase: deadlines from start, no-progress detection, host-memory admission, watchdog
- [fix] staircase: a spool receipt is read only once it holds an exit code
- [feat] staircase: the external-transport driver as `staircase-onboard driver`
- [doc] staircase: execution substrate in README, BUILD_AND_TEST and TROUBLESHOOTING
- [feat] staircase: STAIRCASE_SPOOL_WATCHER=legacy keeps the flock watcher as an escape hatch
- [fix] staircase: the driver names the decision file exactly as the request does, and never overwrites one
- [fix] staircase: only the CLI starts the orchestrator heartbeat thread

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…ayout: OpWrapper entries, a target's own ops/, phase targets

Brings the workflow onto the modeling_v2 conventions of NVIDIA#19977, which this branch sits on.
Catalog entries are OpWrapper classes whose ARCHS and CELLS are the executable contract:
the survey reads certification from them, delivery checks them (and a target's own
ops/<category>/ entries with their tests), and the smith and kernel skills write them, in
the shared catalog or the target's ops/. Delivery checks the target as Prefill/DecodeTarget
over a ModelingV2Core with a ModelWeights table, the modeling skills and the role prompts
describe that target, the gates turn on the step-contract check, and the capacity audit
leaves a target's ops/ to their cells.

Squashed from user/williamj/staircase-polish @ c8109d6f90 (11 commits):
- [fix] staircase: catalog index migration keeps the dividers of categories with no entry yet (NVIDIA#19977 catalog layout)
- [fix] staircase: delivery checks catalog entries as executable contracts, and a target's own ops/ (NVIDIA#19977 catalog layout)
- [fix] staircase: the survey reads an entry's certification from its ARCHS and CELLS, and lists other targets' ops/ as promotable (NVIDIA#19977 catalog layout)
- [fix] staircase: kernel-source registry, smith brief and capacity audit name the entry, not a contract file (NVIDIA#19977 catalog layout)
- [fix] staircase: smith and the kernel skills write OpWrapper entries in the shared catalog or the target's ops/ (NVIDIA#19977 catalog layout)
- [fix] staircase: a smith dispatch names the target whose ops/ an ops/ entry goes in (NVIDIA#19977 catalog layout)
- [fix] staircase: delivery checks the target the NVIDIA#19977 way (NVIDIA#19977 target layout)
- [fix] staircase: modeling skills teach the target layer, bound entries and the weight table (NVIDIA#19977 target layout)
- [fix] staircase: assembler, reviewer, planner and auditor prompts describe the NVIDIA#19977 target (NVIDIA#19977 target layout)
- [fix] staircase: gates turn on the targets' step-contract check (NVIDIA#19977 target layout)
- [fix] staircase: the capacity audit leaves a target's own ops/ to their cells (NVIDIA#19977 target layout)

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
… tier the survey measures

FlashInfer is a pinned dependency, but the tree wraps a handful of its kernels as trtllm
ops, and the workflow saw only those: the sourcing ladder and the survey knew
torch.ops.trtllm and nothing else of the library. Adds tier 3 (a FlashInfer callable
called directly) between the in-tree callable and native torch, a survey that reads the
installed package's public API off disk and records which callables the engine already
references, a flashinfer_api kernel source, and the skills and prompts that search
FlashInfer before a writing tier or a ceiling. Against flashinfer-python 0.6.18: 558
public callables, 510 of them referenced nowhere in the engine.

Squashed from user/williamj/staircase-polish @ c8109d6f90 (1 commits):
- [feat] staircase: FlashInfer's public API is a sourcing tier the survey measures

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…d BUILD_AND_TEST for the polished workflow

Operator documentation for everything above, and LESSONS.md, which replaces the raw
findings of two onboarding runs with 34 lessons, each naming the in-tree mechanism that
now prevents it. Also points the repository guide (AGENTS.md) at the environment
failures that read as model failures.

Squashed from user/williamj/staircase-polish @ c8109d6f90 (4 commits):
- [doc] point the repo guide at the failures that are not the model's
- [doc] staircase: README for per-role routing, prompt snapshots and worked examples
- [doc] staircase: replace the raw run findings with LESSONS.md
- [doc] staircase: LESSONS.md credits the mechanisms that landed with the hygiene and preflight work

Also carries the documentation edits made by the commits squashed into the
earlier commits: BUILD_AND_TEST.md, README.md, TROUBLESHOOTING.md.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…b's session

nsys profile (and any setsid'd server) is re-parented to init once the job's
leader exits; job_processes() then no longer sees it, so a cancel or the
leftover reaper never killed it and the next job ran on a GPU a stranded
server still held. Find such processes by the STAIRCASE_SPOOL_JOB /
STAIRCASE_SPOOL_WATCHER markers in their environment once the verdict is set.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…uner campaign

A performance stage for modeling_v2 targets, chained after deliver
(perf.enabled) or standalone (staircase-onboard tune / --stage tune):
ground truth (target, stock reference, noise repeats), the config ladder
(Python: runtime rungs measured in parallel across spool sessions, judged
against same-host controls, winners stacked), and a campaign of tuner turns
(one hypothesis per worktree; the orchestrator measures e2e, applies the keep
rule and the accuracy gate, and cherry-picks keeps onto tune/best).

Adds the tuner role, prompt and staircase-perf-tuning skill, the perf block,
tune/{bench,ladder,records,campaign,requests,worktree,microbench,
gate_accuracy,stage,cli}.py and staircase-onboard perf {ladder,campaign,table}.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…the LLM-API argument in every gate

Target selection is the LLM-API argument modeling_v2 (default "off"); nothing
in the engine reads TRTLLM_MODELING_V2 any more. The gates only exported the
switch, so boot, acceptance, witness and accuracy gates served the built-in
model while recording the verdict as the target's. eval_command now merges
modeling_v2: <mode> into the member's options YAML and the engine driver
passes it to the quickstart's LLM(...).

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…ked candidates, session-mode nsys

What the first real campaign (Qwen3.8-Flash-Next-NVFP4, 1x GB300) needed:
- judge every measurement against a control from its own host: GB300 nodes
  differed by up to 4% at concurrency 1 for identical configs, and the ladder
  rejected a +4.8% rung on node effect;
- evaluate a candidate stacked on the current best tree (eval worktree),
  re-stacking when a keep moves it; include a parent candidate's commits;
- submissions through an inbox so only the campaign loop writes its state;
  idempotent spool submission; serialized worktree creation;
- nsys session mode (nsys launch + external start/stop) and nsys_summary.py
  for per-step attribution; bench.py tears down its server on SIGTERM and
  refuses a busy device;
- LESSONS 35-39, troubleshooting entries, the perf block in task.example.yaml.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…d host; re-stack on any move

A control of another config (or host) must never stand in for this one: the
control label carries the config digest, a candidate measured at an older
config is re-measured (its measurement kept as attribution only), a missing
same-host control is measured before judging, and a candidate whose best tree
moved is re-stacked before it is queued. Commits the best tree already carries
(by patch identity) are not applied again; eval worktrees are reused instead of
re-created. Test: test_a_config_change_re_measures_against_a_control_of_that_config_and_host.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…-dry-run for the tune entry

The task schema refused a top-level perf block, so the tune stage could not be
configured through task.yaml at all; it is now a known key validated by
tune.stage.validate_perf_block. --dry-run stops after preflight for the tune
entry too. Workflow tests cover the standalone entry, chaining after delivery,
re-entry of a delivered run, and dry-run.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…s with an earlier keep

Candidates written in parallel from one base collide in the forward file once
one is kept; the textual conflict is not a verdict. The stage dispatches one
rebase turn (render_rebase_request) and re-evaluates the rebased candidate on
the best tree. Test: test_a_candidate_that_conflicts_with_a_keep_is_rebased_and_retried.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…est when a keep lands; record the measured tree

A keep moves the best tree; every other candidate measured on the old one
would be re-measured anyway, so its job is cancelled and it re-stacks on the
next pass. bench.py records the tree the scheduler put first on the path
(STAIRCASE_TREE) rather than the --tree argument.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…plays at their launch

Graph-replayed kernels carry no runtime correlation; attributing them by GPU
start charged each replay to whichever step the host was in when it ran and
reported idle that was not there (31% vs a measured 1.7% at batch 128). Group
graph kernels into replays by graphId, place the k-th replay at the k-th
cudaGraphLaunch, and judge a graph step on its replay's span.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…host's control of the new best

The kept candidate's e2e label measured exactly the new best tree at the
current config on its host; register it as that host's control instead of
measuring it again.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…ted; correct spoolctl syntax in the docs

A candidate re-stacked on a new best after passing its gate was kept on the
old gate result, so the combined tree went ungated. Gate results now live
under gates/<slug>-<tree sha>. The request template and the skill reference
spelled 'spoolctl.py launch --spool S'; the global option precedes the
subcommand.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…ee, measure and gate them once

Kept one at a time, each keep forced every other winner to re-measure on the
moved best (four winners: four serial rounds). Winners now wait for the other
measurements on the same best; several are stacked in one eval tree, measured
once against the same-host control and kept together if the stack holds each
metric's best single gain within the loss floor and passes one accuracy gate.
Otherwise the strongest single winner is kept and the rest re-stack.
Test: test_winners_on_one_best_are_stacked_measured_and_gated_once.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…h the largest summed gain; rebase the rest onto the batch while it is measured

Winners written in parallel collide in the forward file. The batch picked
winners greedily by gain, so one large winner could exclude three smaller
ones that stack together. Stacking is now simulated in the object store
(merge-tree + commit-tree, no checkout) and the compatible set with the
largest summed gain is measured. Winners left out are marked conflict with
rebase_onto tune/eval-batch pinned to the batch commit; a rebased candidate
waits for the batch and stacks on the new best once it is kept, or is sent
back to rebase onto tune/best when it is not.

Tuner turn prompts now pin grep/find to explicit search roots so embargoed
lines never surface from a repository-wide search.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…l checkout instead of a fresh worktree

A fresh eval worktree checks out the whole tree (2-4 minutes on Lustre) inside
the campaign step. A kept, reverted or dropped candidate's eval checkout is
moved and re-pointed with checkout -B / reset --hard / clean instead.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…ofiling the moved best tree

The campaign ended when its one roadmap was spent, even with iteration budget
left; the kept candidates had moved the profile it was ranked on. A second
roadmap turn (perf.campaign.max_roadmaps, default 2) re-profiles the best tree
and is told which slugs were tried and where their follow-ups are recorded.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…asurement, behind it on the same node

A new best tree queued a control on every free node before any candidate was
measured (five node-runs for three candidates). A measurement now goes to a
free node whose host already has a control, else behind that node's control;
nodes no measurement needs stay free.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…ates and batch runs by their real job names

Gate jobs are named gate-<slug>-<tree sha> (and gate-batch-<sha>); the resume
path adopted gate-<slug>, so a restarted loop neither waited on nor could cancel
the gates already running.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…re-run, and reused eval checkouts drop ignored caches

qsa-rowtile-union-compaction (WIN +1.8% con128) was reverted because its gate's
test suite failed to collect: the reused eval checkout carried __pycache__ from
its old path and pytest imported stale modules. Reuse now cleans ignored files
(the native links are re-made), and gate_accuracy reports ERROR (pytest rc 2-5)
instead of FAIL, which the campaign re-runs once instead of reverting.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…l name where hypotheses come from

The campaign's sources -- the config ladder, per-step-class profiles, fusion and
ordering patterns, FlashInfer as installed (the preflight's surface.md
inventory), this repository's perf commits on similar modules, the sister
engines, and the recorded kernel choices -- were spread over the stage, the
skill references and the operator's notes. The skill now has one table mapping
each source to where it lives in the stage, and every tuner request carries a
'Sources to check' block with the concrete paths and the git query. The
profiling section reflects session-mode nsys and per-step-class summaries.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…o to the shared catalog

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…refix

A second campaign in one repository collided on tune/best, as the stage did
before it got run-scoped branches; perf.campaign.branch_prefix sets it.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…uments

The gate's trtllm-eval arguments were the Qwen defaults (thinking off, 512 output
tokens). A reasoning model such as gpt-oss-120b scores 53 on gsm8k under them
(answers cut off), against 90 with its own settings. perf.campaign.accuracy.eval_args
(stage) / campaign.eval_args (CLI) passes the model's settings through.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…ecisions record them

The roadmap request now carries the same 'Sources to check' block as a
candidate request (installed FlashInfer inventory, kernel_choices.json,
repository perf commits, sister engines) and asks each roadmap item for
its sources. Decision files carry sources: [{source, ref, outcome}],
kept in the campaign ledger per candidate.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
Covers step classes, graph replays charged to the launching step (not the
step the host is in when the GPU runs them), kernel families and busy time.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…eline is the first control

A follow-up campaign on an already tuned config disables the ladder; its
ground baseline measured the best tree at the same configs, so the campaign
adopts it (and its repeats) as same-host controls.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…s and the embargo

A roadmap turn had to discover the best tree, configs, spools, env script
and model on its own, and its request did not list the source embargo.
It now carries the same facts a candidate request does.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…'s host

Ground spread t-baseline and its repeats across sessions, so the noise
floor measured host-to-host spread: on the Qwen3.8 follow-up it read 0.77%
(keep threshold 2.3%) and a low first run on the second host became that
host's control, inflating a candidate's delta to +2.6% where the same-host
wrap measured +1.3%. The baseline and the stock reference still run side by
side; the repeats then follow the baseline onto its session.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…nel ledger

Every roadmap turn now also writes perf_optimize's kernel ledger: each
kernel down to a GPU-time coverage target answers elimination / faster /
fusion / overlap with a roadmap slug or an evidenced dismissal. The stage
validates it with perf_optimize's own load_ledger + cross_validate, gives
one fix turn carrying the validator's findings, records the coverage in
the campaign ledger, and proceeds either way (campaign.kernel_ledger:
require | off; campaign.kernel_coverage_pct, default 80).

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
… start before its session

With a session_spool environment the task validation requires the spool
directory, so the orchestrator could not be started until its compute
session had imported the image (5-10 min). --wait-for-spool MINUTES waits
for the spool to appear; validation still owns the verdict.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…currency point

The warmup ran 16 prompts at concurrency 16, so the batch shapes of the
con128 point were first built inside its measured window on a fresh
session: on three GB300 sessions the first con128 measurement read 1.5-2.2%
below later ones on the same host while con1 matched. The warmup now runs
at the largest point with twice its prompts (OSL 64).

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…skills copy

Materializing the packaged skills removed and re-copied them on every
start; when the workspace's .claude/skills is read-only to the process
(a sandbox protects it) the silent rmtree left the copy in place and
copytree failed, so the run could not resume. An identical copy is now
kept as is.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…s result is re-queued

An adopted receipt can report rc 0 while the label's result directory is
gone; the stage then failed with 'the baseline could not be measured'. A
missing meta.json now re-queues the label like any other failed run.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…de by side

The campaign created each candidate's worktree in its main loop and git
worktree add held the repo lock through the checkout, so three tuner
turns started minutes apart on a parallel filesystem. Registration
(--no-checkout) keeps the lock; the checkout runs outside it in the
turn's own thread.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
… is rebuilt

An orchestrator stopped mid 'git worktree add' left the tree locked
'initializing' without an index, and the next start handed it to a tuner
as is (no tensorrt_llm/). open_candidate now checks the tree is complete
and otherwise unlocks, removes and re-creates it.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…ed together

A NEUTRAL whose gain is real (some metric above both the noise band and
near_min, default min_gain/4) and that loses nothing is held as 'near'
instead of reverted. When a best tree has no winners and nothing left to
measure, its compatible near misses are stacked through the batch path
and judged by the same keep rule and gate; a stack that does not clear
them reverts its members (no single is gated). campaign.stack_near
(default true) and campaign.near_min configure it.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…t-for-spool

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…lap benches at layer scope

Ground warns when noise_repeats < 2 (two samples read 0.32% at con128
where the host ranged 1.2% over the run). The perf skill's Ordering note
asks overlap candidates to benchmark a whole decoder layer with the other
side-stream users, and to keep side-stream work to few, wide CTAs.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…merged

The delivery audit still checked the pre-merge NVIDIA#19977 contract: entries
defining raw_call, targets deriving from Target, a ModelWeights table,
every entry listed in catalog/index.yaml, and routing naming the target
by its absolute module path. As merged, an entry's op call is __call__,
targets and weight tables have no base class (a class with a WEIGHTS
table, exposed as MODEL_WEIGHTS), there is no catalog index, and routing
imports the target relative to its family package. The real gpt-oss and
DeepSeek targets now pass every check (25 and 43).

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
modeling_v2 as merged keeps no catalog/index.yaml: an entry is one
OpWrapper per file under catalog/<category>/. The staircase still
generated that index from per-entry fragments and synced it before every
turn and at delivery. The generator (catalog_index.py) and its hook are
removed, and the survey probe lists the shared entries from the catalog
files themselves (summary from the module docstring) and reads an
entry's op from __call__. On this tree it reports the 8 shared entries
and 11 target-owned ops with their cells and receipts.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…erged

The smith, assembler, reviewer, auditor and plan prompts now describe the
modeling_v2 layout on main: an entry is one OpWrapper subclass whose
__call__ takes every argument explicitly, the catalog is its entry files,
the core's _select_target picks a plain PrefillTarget or DecodeTarget, and
the weight table is a W role class plus a WEIGHTS table and MODEL_WEIGHTS.
Target selection is the LLM-API argument modeling_v2; the gates keep
exporting TRTLLM_MODELING_V2 and the harness hands it to the constructor.

test_prompts now refuses the retired draft names in any prompt, and the
kernel-source attribution test reads the trtllm ops from the catalog and
target ops/ files instead of skipping for want of an index.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
… as merged

The modeling, kernel and feature skills, their references, and the README,
LESSONS, BUILD_AND_TEST and TROUBLESHOOTING guides now match modeling_v2 on
main: entries are called through __call__ with every argument at the call
site, the catalog is its entry files with no index, the core's
_select_target picks a plain PrefillTarget or DecodeTarget, and the weight
table is a W role class with WEIGHTS and MODEL_WEIGHTS.

Resolution is described as main does it: route returns the target class,
the loader carries it on ModelConfig.modeling_v2_target, and nothing
registers under a synthetic name. Target selection is the LLM-API argument
modeling_v2; the gates export TRTLLM_MODELING_V2 and the harness passes it
on. The multi-rank reference places the topology check in routing.py, since
a target carries no configuration asserts.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
ruff-format over the tune stage and its tests, and the remaining ruff
findings fixed by hand: one-line docstring summaries (D205), wrapped long
lines (E501) and descriptive names for `l` (E741). No behaviour change; the
rendered tuner requests and turn prompt are byte-identical.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
…modeling_v2

Package agent_flow.workflows.trtllm_modeling_v2, CLI trtllm-modeling-v2,
TrtllmModelingV2Workflow, build_trtllm_modeling_v2_prompts, and skills
trtllm-modeling-v2-* (the repo's trtllm- skill prefix). The workflow's own
environment variables become MV2FLOW_*: TRTLLM_MODELING_V2* stays the
engine's and the gates' switches, and MV2_* is MVAPICH2's. Internal temp
dirs, locks, log tags and job names use mv2flow-; delivery branches are
trtllm-modeling-v2/<slug>. "Staircase" remains only as the shape of a plan
(core first, then one feature per unit) and in two quoted historical errors.

Signed-off-by: Wanli Jiang <35160485+Wanli-Jiang@users.noreply.github.com>
@Wanli-Jiang
Wanli-Jiang force-pushed the user/williamj/staircase-polish-pr branch from ad3e732 to 6490d8b Compare October 15, 2026 07:23
@Wanli-Jiang Wanli-Jiang changed the title [TRTLLM-16460][feat] agent-flow: staircase-onboard workflow for gated ModelingV2 onboarding [TRTLLM-16460][feat] agent-flow: trtllm_modeling_v2 workflow for gated ModelingV2 onboarding and perf tuning Oct 15, 2026
@Wanli-Jiang

Wanli-Jiang commented Oct 15, 2026 •

Copy link
Copy Markdown
Collaborator Author

Thanks both for the reviews. I've force-pushed an updated branch: it is rebased onto main now that #19977 has merged (so only this PR's own commits remain), aligned with modeling_v2 as merged, and it adds the tune stage. The description is updated to match.

@litaotju

  1. Rename: done. The workflow is now trtllm_modeling_v2: package agent_flow.workflows.trtllm_modeling_v2, CLI trtllm-modeling-v2, TrtllmModelingV2Workflow, and skills trtllm-modeling-v2-* (following the repo's trtllm- skill prefix). The workflow's own env vars became MV2FLOW_* rather than TRTLLM_MODELING_V2_*, so they can't be mistaken for the engine's TRTLLM_MODELING_V2 / _VALIDATE / _VALUE_DUMP switches. In the code, "staircase" now appears only in two quoted historical error messages.
  2. One skill per feature, or one main skill with per-feature references? Today it is one core skill plus one skill per feature. The reason: a run assembles one unit per feature, and each assembler turn is told to load the core skill plus only its own unit's feature skill (FEATURE_SKILLS in task_schema.py), so a turn never carries the other features' text. A main skill whose references are named per feature would keep that property as long as the turn prompt names the reference to read, so I'm happy to restructure it that way if you prefer it; it would also shrink the surface @WeiHaocheng is concerned about (below).

@WeiHaocheng

Both concerns are fair, and this week gave a concrete example of the second: aligning with modeling_v2 as merged meant rewriting 32 skill documents. Some context on how these skills differ from .claude/skills, then a proposal.

  • They are inputs of this workflow rather than general-purpose skills: they are versioned with the prompts and gates that reference them, packaged with the workflow, and copied into each run's workspace, so a run never depends on whatever a checkout's .claude/skills happens to contain.
  • Part of their correctness is tested: test_skills checks that every repo path a skill names exists, and test_prompts now refuses the pre-merge modeling_v2 names. That catches path-level drift, not semantic drift, which is exactly the staleness you describe.

Proposal, and I'd like your view before I change the code:

  • (a) Slim in tree. Fold the per-feature skills into the core skill's references (answering @litaotju's question 2 at the same time) and cut the content to the rules a gate or delivery check can't enforce on its own. The volume drops and what remains stays versioned with the workflow.
  • (b) Out of tree. Add a skills_dir option to task.yaml, ship only the minimal set the prompts require, and keep the full skills in an internal repo until an A/B (the same onboarding with and without them) shows they help.

I lean towards (a) for this PR plus the A/B as a follow-up, but would go with (b) if you'd rather keep the detailed text out of the repo until there is data. Which do you prefer?

This branch has not been deployed

No deployments
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.

3 participants