Skip to content

feat: model response detokenization in replay - #634

Merged
dreamtalen merged 2 commits into
mainfrom
yongmingd/replay-response-detokenization
Oct 29, 2026
Merged

dreamtalen merged 2 commits into
mainfrom
yongmingd/replay-response-detokenization

Conversation

@dreamtalen

@dreamtalen dreamtalen commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Why and what changed

Engine replay recorded every token and every finished request at the end of the engine pass that produced it, and a closed-loop client sent its next request at that same instant. A served request also pays the server's response path before the client receives its tokens: the serving engine's server processes detokenize each pass's outputs, format streamed chunks and write them to the connections. We found this gap while running the paper's vLLM replay experiments: replay under-predicted TTFT most at high concurrency, where many outputs leave the same pass.

  • engine.detokenization (workers, base_ms, per_output_us) mirrors engine.tokenization. Every token-emitting worker (aggregated, or decode in P/D) has workers detokenizer servers, shared by its attention-DP ranks; a request belongs to one of them by a stable hash of its id. When a pass ends, each server takes that pass's outputs that belong to it as one FIFO job of base_ms + per_output_us × outputs, and the client receives them when the job ends.
  • This follows vLLM v0.28.0: each API server process runs one output handler (AsyncLLM._run_output_handler) that processes one engine step's outputs at a time for the requests it owns, whichever DP rank produced them. workers maps to --api-server-count.
  • Token times, TTFT/TPOT/E2E, throughput and request completion use the client's receive time. A request that waits on a finished response (closed-loop slot, a session's next turn, a dependent agentic request) is released when the client receives the end of that response.
  • A rejection carries no output: it skips detokenization and reaches the client when the engine rejects the request, in both aggregated and disaggregated replay.
  • The SGLang host-loop TTFT breakdown adds a seventh stage, mean_detokenization_ms (first token emitted → received by the client; zero without detokenization), so the stages still sum to TTFT.
  • Off by default; an omitted block and all-zero costs keep outputs request for request. Offline token replay on --stack engine only; worker scaling, AFD, encoder pools and agentic profiles are rejected. Rust: Replayer::with_detokenization.

Review map

  • Risk level: medium (new opt-in timing path in the agg and disagg event loops)
  • Start with: crates/core/src/replay/components/detokenization.rs (DetokenizationLatency, DetokenizationStage::receive_pass), then crates/core/src/replay/agg.rs (receive_pass, process_output_signal, release_received_terminals) and crates/core/src/replay/disagg.rs (receive_decode_pass, notify_received_terminal, awaiting_receipt in quiescence), then crates/core/tests/replay_detokenization.rs.
  • Public or serialized contract changed: yes, additive. engine.detokenization YAML block, Replayer::with_detokenization, mean_detokenization_ms in the TTFT stage breakdown (TTFT_STAGE_COUNT 6 → 7, always present, zero without detokenization).
  • Compatibility or rollback concern: none when unset. Telemetry samples count a completion when the engine finishes the request, before the client receives it (documented).

Evidence

  • Tests (Linux x86 VM, Rust 1.96.1, commit 4f6264f on f45d14a): cargo fmt --all -- --check; cargo test --workspace (core 2,369 passed) and cargo test --workspace --features embed-python,replay-bench with AIC_REQUIRE_EMBEDDED_ROUND_TRIP=1 (core 2,457 passed) pass with no failures; cargo test --manifest-path crates/tests/public-api/Cargo.toml passes (21). ruff check, ruff format --check and scripts/ci/check_packaged_legal_files.py pass. Python tests/ and python/aisimulate/tests -m unit fail exactly the same tests as main on that host (204 and 72; they fail on main too) and run 17 new cases.
  • Fast CI:
  • Full CI:
  • New tests: crates/core/tests/replay_detokenization.rs (aggregated and disaggregated: a lone request's outputs after detokenization, outputs of one pass reach the client together, the closed-loop client sends at receive time, rejections reach the client at engine time and do not delay their pass's outputs, attention-DP ranks share a worker's servers, base_ms occupies the detokenizer, zero costs keep pass-end delivery, the time cap, agentic requests, invalid configs), sglang_ttft_stages_attribute_detokenization_to_its_own_stage, DetokenizationStage unit tests (two servers split a pass and queue independently, a request keeps its server, a pass without outputs takes no server time, atomic rejection of a non-finite job end), Python compiler/config/runner cases and a native end-to-end replay.
  • Calibration (independent of the evaluation sweep): two separate B200 launches of the same vLLM serving stack (MiniMax-M3-NVFP4, TP4, one API server), 10 shapes from c1 to c256 and 512–8k prompts. Each request's client first-token and response-end times were fitted against the engine's batch timestamps with this model: base_ms 2.85, per_output_us 61.6. Mean absolute error per shape is 5.6 ms for the first token and 2.1 ms for the response end; a four-term model (separate first-output and final-output costs) fits 1.1 and 0.9 ms better, and we kept the two-term model for simplicity. No evaluation point was used.
  • Exp1 (MiniMax-M3-NVFP4, TP4 B200, 18 configs, 10,220 requests), MAPE over 9 concurrency points, TTFT mean / p50 / p90 · TPOT mean · throughput, with feat: model vLLM async-scheduling admission in replay #624 applied on both sides, without → with engine.detokenization:
    • G1k: 11.1 / 8.7 / 16.7 · 3.7 · 4.1 → 7.9 / 4.6 / 11.2 · 4.2 · 4.6
    • G8k: 6.3 / 9.2 / 13.7 · 1.5 · 1.7 → 4.4 / 5.9 / 8.8 · 1.5 · 1.6
  • With detokenization off, the 18 Exp1 replays equal main request for request; the numbers above reproduce request for request from the merge of this PR and feat: model vLLM async-scheduling admission in replay #624.
  • Cost: per pass with detokenization, one job per server that has outputs (workers: 1 counts outputs without allocating); nothing without it. Native wall_time_ms, release builds of f45d14a (main) and this PR on an idle VM, paired alternating runs. Off: Exp1 1k c1 / 1k c256 / 8k c64 median ratio to main 1.035 / 0.994 / 0.992 (5 runs). Synthetic 512/128 closed loops of 1k / 4k / 16k and a 400 req/s Poisson overload (3 runs, every request completed, same simulated outcome across variants), host cost per output token main → detokenization (workers: 1) → workers: 4: 0.49 → 0.54 → 0.57, 0.66 → 0.65 → 0.69, 0.72 → 0.67 → 0.70, 0.72 → 0.72 → 0.71 µs. The workers: 4 path allocates two small vectors per pass; its c1024 ratio is 1.17 [1.00, 1.34] and the larger runs are within noise.
  • Reviews: fresh Claude reviews (rudy-review) of the design before and after the switch to engine.detokenization. Fixed: TTFT stage attribution, agg/disagg rejection symmetry, all-zero costs equal omission, unknown rank is an error. Documented: per-pass delivery vs vLLM's 128-output chunks, --api-server-count defaults.

Modeling or data provenance

  • A job's outputs reach the client together. vLLM hands a pass's outputs to the connections in chunks of VLLM_V1_OUTPUT_PROC_CHUNK_SIZE (128 by default), so with more than 128 outputs per server in one pass, replay delivers the earlier chunks somewhat late.
  • Detokenization and tokenization share the API server process in vLLM; replay models them as separate queues.
  • The request-to-server hash stands in for how the kernel spreads connections over API server processes.

Tracking

🤖 Generated with Claude Code

Engine replay recorded every token and every finished request at the end of
the engine pass that produced it, and a closed-loop client sent its next
request at that same instant. A served request also pays the server's
response path before the client receives its tokens: the serving engine's
server processes detokenize each pass's outputs, format streamed chunks and
write them to the connections.

- engine.detokenization (workers, base_ms, per_output_us) mirrors
  engine.tokenization. Every token-emitting worker (aggregated, or decode)
  has `workers` detokenizer servers (vLLM --api-server-count), shared by its
  attention-DP ranks, and each request belongs to one of them by a stable
  hash of its id. When a pass ends, each server takes the pass's outputs that
  belong to it as one job of base_ms + per_output_us x outputs, after its
  earlier jobs, and the client receives them when the job ends. Token times,
  latency metrics, throughput and request completion use the client's
  receive time, and a request that waits on a finished response is released
  when the client receives its end.
- A rejection carries no output: it skips detokenization and reaches the
  client when the engine rejects the request, in both topologies.
- The SGLang host-loop TTFT breakdown adds mean_detokenization_ms, the first
  token's emission to its receipt by the client (zero without
  detokenization), so the stages still sum to TTFT.
- Off by default and keeps outputs request for request. Offline token replay
  on --stack engine only; worker scaling, AFD, encoder pools and agentic
  profiles are rejected. Rust: Replayer::with_detokenization.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Yongming Ding <yongmingd@nvidia.com>
@dreamtalen
dreamtalen requested a review from a team as a code owner October 28, 2026 21:48
@copy-pr-bot

copy-pr-bot Bot commented Oct 28, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 4f6264f and 86795be.

Files selected for processing: 9
  • crates/core/src/replay/agg.rs
  • crates/core/src/replay/components/detokenization.rs
  • crates/core/src/replay/components/mod.rs
  • crates/core/src/replay/disagg.rs
  • crates/core/src/replay/replayer.rs
  • crates/core/tests/replay_detokenization.rs
  • python/aisimulate/src/aisimulate/runner.py
  • python/aisimulate/src/aisimulate/sweeper/replay.py
  • tests/test_runner.py
Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 8 remain after this review.

Recent review details
Context from checks skipped due to timeout: 26
  • GitHub Check: Prediction Regression / Collect prediction snapshot (old)
  • GitHub Check: Prediction Regression / Collect prediction snapshot (new)
  • GitHub Check: Collector Data / Perf data sanity (informational)
  • GitHub Check: Collector Data / Check collector data
  • GitHub Check: Platform Wheels / Build wheels (macosx_arm64)
  • GitHub Check: Platform Wheels / Build wheels (manylinux_2_28_aarch64)
  • GitHub Check: Platform Wheels / Build wheels (manylinux_2_28_x86_64)
  • GitHub Check: readme-commands / README / dynamo
  • GitHub Check: readme-commands / README / source
  • GitHub Check: Application Test Wheel (arm64)
  • GitHub Check: Public API Rust (amd64)
  • GitHub Check: Rust feature modes
  • GitHub Check: Python 3.13 compatibility
  • GitHub Check: Rust (amd64)
  • GitHub Check: Python Dependency Licenses
  • GitHub Check: Engine Golden Regression
  • GitHub Check: Release Artifact Contract (arm64)
  • GitHub Check: Application Test Wheel (amd64)
  • GitHub Check: Public API Rust (arm64)
  • GitHub Check: Release Artifact Contract (amd64)
  • GitHub Check: Python 3.11 compatibility
  • GitHub Check: Rust (arm64)
  • GitHub Check: Build simulation wheel (base)
  • GitHub Check: Build simulation wheel (head)
  • GitHub Check: Forward Prediction Performance (advisory)
  • GitHub Check: CodeRabbit
Additional context used
Code guidelines: 4
crates/core/src/replay/CLAUDE.md — auto-discovered
AGENTS.md — configured
REVIEW.md — configured
python/aisimulate/.claude/rules/repo-guide.md — auto-discovered
Path-based instructions: 8
Check unified CLI, Replay, Sweeper, and orchestration behavior together.

CodeRabbit configuration file

Files:

  • python/aisimulate/src/aisimulate/runner.py
  • python/aisimulate/src/aisimulate/sweeper/replay.py
Preserve deterministic Replay semantics and explicit validation.

CodeRabbit configuration file

Files:

  • crates/core/src/replay/components/mod.rs
  • crates/core/src/replay/replayer.rs
  • crates/core/src/replay/components/detokenization.rs
  • crates/core/src/replay/disagg.rs
  • crates/core/src/replay/agg.rs
Require coverage of the changed behavior and its negative or boundary cases.

CodeRabbit configuration file

Files:

  • tests/test_runner.py
Read REVIEW.md before commenting.

CodeRabbit configuration file

Files:

  • python/aisimulate/src/aisimulate/runner.py
  • python/aisimulate/src/aisimulate/sweeper/replay.py
  • crates/core/src/replay/components/mod.rs
  • crates/core/src/replay/replayer.rs
  • tests/test_runner.py
  • crates/core/src/replay/components/detokenization.rs
  • crates/core/tests/replay_detokenization.rs
  • crates/core/src/replay/disagg.rs
  • crates/core/src/replay/agg.rs
Source excerpt: **Tight-spin/livelock extreme:** do not repeatedly report an effect-free, queued-only zero-duration pass as progress at the same virtual timestamp.

CodeRabbit inference engine (crates/core/src/replay/CLAUDE.md)

Files:

  • crates/core/src/replay/components/mod.rs
  • crates/core/src/replay/replayer.rs
  • crates/core/src/replay/components/detokenization.rs
  • crates/core/src/replay/disagg.rs
  • crates/core/src/replay/agg.rs
Source excerpt: Keep run logs, investigation notes, and benchmark results out of `docs/`; measured evidence belongs under `benchmarks/evidence/`.

CodeRabbit inference engine (AGENTS.md)

Files:

  • python/aisimulate/src/aisimulate/runner.py
  • python/aisimulate/src/aisimulate/sweeper/replay.py
  • crates/core/src/replay/components/mod.rs
  • crates/core/src/replay/replayer.rs
  • tests/test_runner.py
  • crates/core/src/replay/components/detokenization.rs
  • crates/core/tests/replay_detokenization.rs
  • crates/core/src/replay/disagg.rs
  • crates/core/src/replay/agg.rs
Source excerpt: Binary parquet changes require a machine-readable summary of keys, shapes, units, row counts, coverage, and anomalies plus proof that a real consumer reaches the new data.

CodeRabbit inference engine (REVIEW.md)

Files:

  • python/aisimulate/src/aisimulate/runner.py
  • python/aisimulate/src/aisimulate/sweeper/replay.py
  • crates/core/src/replay/components/mod.rs
  • crates/core/src/replay/replayer.rs
  • tests/test_runner.py
  • crates/core/src/replay/components/detokenization.rs
  • crates/core/tests/replay_detokenization.rs
  • crates/core/src/replay/disagg.rs
  • crates/core/src/replay/agg.rs
Source excerpt: **A task stays in its module.**

CodeRabbit inference engine (python/aisimulate/.claude/rules/repo-guide.md)

Files:

  • python/aisimulate/src/aisimulate/runner.py
  • python/aisimulate/src/aisimulate/sweeper/replay.py
Multi-repo context ai-dynamo/dynamo, ai-dynamo/aiconfigurator

Linked repositories findings

ai-dynamo/dynamo

  • Replay configuration clones the normalized engine configuration into the replay rank, so detokenization fields can pass through if accepted by canonical parsing. [::ai-dynamo/dynamo::lib/mocker/src/engine_adapter.rs:34-39] [::ai-dynamo/dynamo::lib/mocker/src/engine_adapter.rs:82-103]
  • Dynamo’s frontend remains responsible for live detokenization; workers emit raw token IDs. The PR’s timing model should remain limited to offline replay. [::ai-dynamo/dynamo::lib/llm/src/entrypoint/input/endpoint.rs:145-149]
  • No downstream Dynamo references to engine.detokenization or mean_detokenization_ms were found.

ai-dynamo/aiconfigurator

  • No references to the new detokenization configuration or TTFT metric were found. The repository identifies active development as having moved to AISimulate and links its migration guide. [::ai-dynamo/aiconfigurator::pyproject.toml:87-88]
📝 Summary

Risk: Medium

Three areas for human attention

  1. Verify FIFO queue timing and client-visible release behavior across aggregated and disaggregated replay.
  2. Verify compatibility limits: active detokenization is rejected for AFD, encoder pools, scaling, and agentic profiles.
  3. Verify the public timing contract: token timestamps and completion use client receipt time when detokenization is active.

Changed behavior and contracts

  • Adds opt-in engine.detokenization configuration and Rust API Replayer::with_detokenization(workers, base_ms, per_output_ms).
  • Models per-worker detokenizer servers as FIFO queues. Each pass creates one job per server with outputs, and clients receive those outputs when the job completes. Finished requests remain in flight until client receipt. Rejections bypass detokenization.
  • Adds mean_detokenization_ms to the TTFT breakdown. With both costs set to zero, outputs retain pass-end timing.
  • Adds Python config compilation, runner capability checks, scoring support, and documentation for the configuration and timing behavior.

Evidence and readiness

The supplied source confirms the queue model, stable request-to-server assignment, and finite completion-time check. The PR summary reports Rust formatting, workspace and public API tests, Ruff, legal-file checks, and 17 new cases. It also reports existing Python test failures matching the main branch. These results are author-reported and were not independently run here.

Review severity counts are unavailable because no current review findings were supplied. The linked comment requests testing; it is not an approval. The reported test outcomes support technical confidence, but merge readiness still requires human validation of the timing and compatibility contracts.

This change adds configurable response detokenization to replay execution. Runtimes schedule client receipt of pass outputs and terminal events. TTFT reporting and Python runner configuration include the new timing model.

Changes: Client-side detokenization

Layer / File(s) Summary
Detokenization model and replay API
crates/core/src/replay/components/detokenization.rs, crates/core/src/replay/components/mod.rs, crates/core/src/replay/replayer.rs, crates/core/tests/replay_detokenization.rs, docs/replay/api/rust.md
The replay API configures detokenization latency. The stage assigns requests to servers, queues pass output jobs, and releases terminals by receipt time. Tests cover timing, queueing, validation, and zero-cost settings.
Python configuration and execution wiring
python/aisimulate/src/aisimulate/config/engine.py, python/aisimulate/src/aisimulate/config/cli.py, python/aisimulate/src/aisimulate/compiler.py, python/aisimulate/src/aisimulate/runner.py, python/aisimulate/src/aisimulate/sweeper/replay.py, python/aisimulate/src/aisimulate/sweeper/score.py, crates/core/src/python.rs, tests/test_runner.py, docs/replay/engine/README.md
Python config validates detokenization settings, compiles active settings into deployment fields, and passes them to compatible offline replay runners. The execution payload accepts settings for aggregated and disaggregated topologies.
Runtime receipt scheduling and delivery
crates/core/src/replay/agg.rs, crates/core/src/replay/disagg.rs, crates/core/src/replay/disagg_tests.rs, crates/core/tests/replay_detokenization.rs
Both runtimes schedule pass outputs and terminal releases at client receipt times. Pending deliveries count as in-flight requests. Rejections bypass detokenization. Tests cover delivery timing, admission progression, and simulation cutoffs.
TTFT reporting and validation
crates/core/src/replay/report.rs, crates/core/src/replay/report/bounded.rs, crates/core/tests/engine.rs, python/aisimulate/src/aisimulate/sweeper/score.py, docs/getting-started/understand-results.md, docs/reference/cli.md, docs/replay/engine/sglang-vl-host-loop.md
TTFT accounting and serialization add a detokenization span. Tests and documentation describe the added metric and client-receipt timestamps.

Priority: Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • ai-dynamo/aisimulate#624: Changes vLLM admission at pass boundaries, which interacts with detokenization-delayed arrivals and terminal release.
  • ai-dynamo/aisimulate#612: Changes mixed prefill/decode pass latency, which affects the pass completion times used to schedule detokenization.
Merge Risk: Low · up to 86795

With detokenization enabled and a simulation time cap that falls between a pass end and its client receipt, an incomplete request can report a first-token time after the cap. Completion counts and closed-loop release are unaffected. This is a bounded reporting edge case, acceptable as a follow-up.

Pre-merge checks: Passed 4 · Failed 2 · Inconclusive 2

Failed Failed checks: 2 warnings · 2 inconclusive

Check name Status Explanation Resolution
Cross-Layer Contract Warning The prior cross-layer failures remain unresolved. docs/replay/features.md:37 is unchanged and still states that native SGLang VL replay has no output-side costs, while this PR adds `engine.detokeniz… Update docs/replay/features.md for optional response detokenization in SGLang host-loop replay. Enforce the documented encoder-pool exclusion at the Rust Replayer/JSON boundary, or remove the exclusion consistently from Python and docum…
Compatibility Boundaries Warning The new Python and Rust defaults are not fully synchronized for inactive detokenization. Python treats engine.detokenization: {} or all-zero costs as inactive (DetokenizationConfig.active and comp… Normalize or test detokenization activity before the Rust agentic-profile rejection. Use base_ms > 0.0 || per_output_ms > 0.0 for the compatibility check, while still passing the block to with_detokenization so invalid workers and non-f…
Modeling And Data Evidence Inconclusive The available evidence does not establish the required modeling/data evidence. The PR adds deterministic formula tests that compare direct and detokenized replay, such as `crates/core/tests/replay_det… Provide the complete PR description or commit reproducible evidence. Include the source and version for the detokenization model, raw machine-readable before/after results, the comparison procedure, and anomaly checks. Unit assertions alone…
Review Evidence Inconclusive The visible PR description names commands and results, identifies a Linux VM run, reports parity with main, and states several rejection boundaries. However, the description is truncated in the eviden… Provide the complete PR description, including the remainder of the Evidence section and all CI/evidence labels. Then verify that each result is explicitly classified as local, fake-runner, parity, or production evidence and that no inactiv…
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title "feat: model response detokenization in replay" states the main behavioral change: replay now models response detokenization. The changeset adds an opt-in engine.detokenization timing model,…
Description check Passed The description follows the template: it covers why and what changed, a review map with risk level, start-with files, and the contract change, plus evidence (commands, test counts, commit, negative ca…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Title check

Explanation

The title "feat: model response detokenization in replay" states the main behavioral change: replay now models response detokenization. The changeset adds an opt-in engine.detokenization timing model, DetokenizationLatency/DetokenizationStage, and the mean_detokenization_ms TTFT stage, all matching the title. The title follows the conventional prefix form and is specific. It does not state the 'precise' behavioral effect (client-receipt timing), but it is related to the main change and is not vague, so it passes.

Full details: Description check

Explanation

The description follows the template: it covers why and what changed, a review map with risk level, start-with files, and the contract change, plus evidence (commands, test counts, commit, negative cases, and calibration data), and a modeling provenance section with units and limitations. Tracking is filled as N/A and related PRs. Two template gaps remain. 'Fast CI' and 'Full CI' are blank. 'CodeRabbit reviewed commit' is missing. 'Codex reviewed commit' is also missing, and the template marks it as required for medium or high risk. The author labels risk as medium, so that field is required. 'Expected-value derivation' is not explicitly addressed for the exact numerical assertions in the new tests.

Resolution

Fill in the blank template fields before merge. Add the Fast CI and Full CI results. Add the CodeRabbit reviewed commit. Add the Codex reviewed commit, which is required for medium-risk changes. Add the expected-value derivation for exact numerical assertions, or state N/A if none apply.

Full details: Cross-Layer Contract

Explanation

The prior cross-layer failures remain unresolved. docs/replay/features.md:37 is unchanged and still states that native SGLang VL replay has no output-side costs, while this PR adds engine.detokenization and SGLang detokenization tests (crates/core/tests/engine.rs:2239-2288). The documented encoder-pool exclusion is not enforced by the Rust API: Python rejects active detokenization with an encoder (python/aisimulate/src/aisimulate/config/engine.py:917-922), but Replayer::run_inner only checks scaling (crates/core/src/replay/replayer.rs:531-537) and passes both encoder and detokenization to the runtimes (:598-600, :676-678). RunnerCapabilities.require_compatible checks only AFD, capability, and offline mode for detokenization (python/aisimulate/src/aisimulate/sweeper/replay.py:572-578); it has no detokenization-specific scaling or agentic-profile checks, and the added tests cover neither combination. BackendDeploymentSpec.detokenization is marked for canonical omission (python/aisimulate/src/aisimulate/sweeper/replay.py:212-214), but the only canonical JSON test still covers tokenization (tests/test_runner.py:2966-2973).

Resolution

Update docs/replay/features.md for optional response detokenization in SGLang host-loop replay. Enforce the documented encoder-pool exclusion at the Rust Replayer/JSON boundary, or remove the exclusion consistently from Python and documentation, and add direct tests. Add RunnerCapabilities preflight rejection and tests for detokenization combined with scaling and agentic_profile. Add canonical JSON tests proving configured detokenization is serialized and unset detokenization is omitted.

Full details: Compatibility Boundaries

Explanation

The new Python and Rust defaults are not fully synchronized for inactive detokenization. Python treats engine.detokenization: {} or all-zero costs as inactive (DetokenizationConfig.active and compiler omission at python/aisimulate/src/aisimulate/config/engine.py:889-890, python/aisimulate/src/aisimulate/compiler.py:215-223). The Rust binding accepts the same defaulted payload, but rejects it with an agentic_profile because it checks serving_path.detokenization.is_some() before Replayer::with_detokenization removes zero-cost latency (crates/core/src/python.rs:2950-2955, crates/core/src/replay/replayer.rs:446-456). This contradicts the documented default that zero costs are equivalent to omission (docs/replay/engine/README.md:237-241) and changes the new public execution boundary. Version pins remain equal at 0.13.0, the release scripts still enforce one aisimulate wheel and one aisimulate-core crate, and no Dynamo dependency was added.

Resolution

Normalize or test detokenization activity before the Rust agentic-profile rejection. Use base_ms &gt; 0.0 || per_output_ms &gt; 0.0 for the compatibility check, while still passing the block to with_detokenization so invalid workers and non-finite costs remain validated. Add a binding test for a defaulted or all-zero detokenization payload with agentic_profile and verify it behaves like an omitted block.

Full details: Modeling And Data Evidence

Explanation

The available evidence does not establish the required modeling/data evidence. The PR adds deterministic formula tests that compare direct and detokenized replay, such as crates/core/tests/replay_detokenization.rs:116-239 and crates/core/tests/engine.rs:2219-2292, but the changed files contain no explained golden diff, independent oracle, held-out comparison, or machine-readable results with anomaly checks. The documentation explicitly says the example timing values are illustrative and must be measured on each deployment (docs/replay/engine/README.md:483-486). The authored PR description is truncated after its evidence section, so omitted provenance or reproducible before/after data cannot be assessed.

Resolution

Provide the complete PR description or commit reproducible evidence. Include the source and version for the detokenization model, raw machine-readable before/after results, the comparison procedure, and anomaly checks. Unit assertions alone do not establish empirical model or performance evidence.

Full details: Review Evidence

Explanation

The visible PR description names commands and results, identifies a Linux VM run, reports parity with main, and states several rejection boundaries. However, the description is truncated in the evidence section after “New tests,” so the required distinction between local, fake-runner, parity, and production evidence cannot be verified. The omitted text may also contain or omit hosted-CI claims; the visible blank “Fast CI” and “Full CI” headings do not resolve that question.

Resolution

Provide the complete PR description, including the remainder of the Evidence section and all CI/evidence labels. Then verify that each result is explicitly classified as local, fake-runner, parity, or production evidence and that no inactive nested workflow is presented as hosted CI evidence.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@tedzhouhk tedzhouhk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed 4f6264f across the aggregated and disaggregated client response paths. No blocking issues found. Local validation: 13 targeted Rust tests and 17 Python tests passed, plus independent probes covering 78 combinations of slow output queues, bounded/detailed report parity, closed-loop concurrency, and completion dependencies. GPU accuracy experiments were not rerun.

Rename client_path.rs to detokenization.rs and ClientPath to
DetokenizationStage, mirroring tokenization.rs, and rename the agg and
disagg fields, helpers and tests that still said client path. No
behavior change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Yongming Ding <yongmingd@nvidia.com>
@dreamtalen

Copy link
Copy Markdown
Contributor Author

/ok to test 86795be

@dreamtalen
dreamtalen enabled auto-merge (squash) October 29, 2026 17:57
@dreamtalen
dreamtalen merged commit 0b18d96 into main Oct 29, 2026
73 checks passed
@dreamtalen
dreamtalen deleted the yongmingd/replay-response-detokenization branch October 29, 2026 18:50
carlory pushed a commit to carlory/aisimulate that referenced this pull request Oct 30, 2026
Signed-off-by: Yongming Ding <yongmingd@nvidia.com>
Co-authored-by: Claude Opus 5.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