Skip to content

WIP (BLOCKED on speculator seam): PD-DFlash Task 6 — engine round-state (byte-demand VERIFY scheduling) - #162

Merged
drunkcoding merged 11 commits into
devfrom
feat/pd-dflash-task6-engine
Aug 15, 2026
Merged

WIP (BLOCKED on speculator seam): PD-DFlash Task 6 — engine round-state (byte-demand VERIFY scheduling)#162
drunkcoding merged 11 commits into
devfrom
feat/pd-dflash-task6-engine

Conversation

@drunkcoding

Copy link
Copy Markdown
Contributor

WIP / DRAFT — do not merge

Stacks on #156 (serving DRAFT/VERIFY scheduler) + #157 (expert_nbytes byte instrumentation).
This branch = feat/pd-dflash-phaseA-runner (#157) with feat/pd-dflash-serving-scheduler (#156) merged in. It must not be merged before both of those, and — see below — not until the Step‑5 seam follow‑up lands.

TL;DR (honest gate)

Task 6 Steps 1–4 are already complete in the #156+#157 stack. The remaining Step 5 (engine DRAFT→VERIFY→DRAFT driving with exact per‑round expert‑byte demand) is BLOCKED: it genuinely requires a public single‑round control seam on DFlashSpeculator that does not exist and that Task 6 does not authorize creating. Per the plan's honest‑gating rule, this PR reports the exact seam instead of hacking one in. The unique change here is:

  • the prepared, conflict‑resolved stacked base, and
  • docs/superpowers/notes/2026-08-14-pd-dflash-task6-step5-seam.md — the exact seam spec.

No production code was changed by this PR beyond the merge itself.

What the stack already provides (verified here)

Piece Where Source
SequenceStatus.DRAFT/VERIFY (Task 4) serving/sequence.py #156
Pure 2‑D deficit admit_verify_demands (Task 5) serving/scheduler.py:50 #156
SchedulerOutput.{draft,verify}_seq_ids, num_verify_{tokens,expert_bytes} (Task 6 S3) serving/batch.py #156
set_verify_demand/clear_verify_demand + _apply_verify_scheduling + engine budget wiring (Task 6 S4) serving/scheduler.py:325, serving/engine.py:135 #156
Task 6 S1 "three speculative sequences" admission (scheduler‑level) tests/python/serving/test_dflash_deficit_scheduler.py:231 #156
ExpertPrefetcher.expert_nbytes_map exact FP4 payload bytes memory/expert_prefetcher.py, runtime/model_offload.py, distributed/expert_executor.py #157

Merge conflicts were limited to two Task‑1 files (benchmarks/dflash/report.py, tests/python/dflash/test_pd_dflash_report.py); resolved KEEP‑BOTH#157's versions are strict supersets of #156's identical Task‑1 contract (verified: zero #156‑unique lines dropped), so both sides' behavior is preserved.

Why Step 5 is blocked (root cause)

Step 5 requires registering a pending verify's exact demand before it runs: set_verify_demand(seq_id, tokens=B, expert_bytes=Σ expert_nbytes[routed union], …), then running VERIFY only for admitted verify_seq_ids. But:

  • The serving engine only exposes the whole‑request loop — _step_speculativespeculator.generate() (all rounds atomically); SpeculativeGenerator Protocol has just generate().
  • DFlashSpeculator runs every round inside _generate_single; per‑round state (target_kv, draft_kv, context_feature, anchor, start, step_trace) is local; _run_drafter/_verify_target_block are private.
  • Route‑ahead is internal to the verify forward (route_ahead_contextDistributedExpertExecutor.dispatch_local), so a verify's exact expert_nbytes sum is only known during/after it runs (surfaced post‑hoc in RouteAheadStats) — never before, which is when admission needs it.

No honest workaround exists: post‑hoc stats can't gate admission; fabricating bytes from expert count is forbidden (plan Step 4 + task); re‑implementing the draft/verify loop in the engine would be a forbidden second router/prefetch path.

The exact seam required (NOT in Task 6's file list)

A public, per‑sequence, single‑round surface on spec_decode/dflash.py that externalizes the _generate_single state, plus a read‑only route projection in distributed/expert_executor.py:

begin_session(prompt_ids, sampling_params, stop_ids) -> SpecSession   # prefill/anchor
draft_round(session)  -> DraftResult   # one _run_drafter; PROJECT routed expert union via the
                                       # same gate/top-k path the verify uses (design §10 BM1),
                                       # no expert exec, no 2nd router; returns tokens=B,
                                       # expert_union, expert_bytes=Σ expert_nbytes_map[union]
verify_round(session) -> VerifyResult  # one _verify_target_block under route_ahead_context;
                                       # accept/commit/rollback; accepted_ids, committed_count, finished

Task 6's authorized files are only serving/{batch,scheduler,engine}.py (+ tests + benchmark) — not spec_decode/dflash.py or distributed/expert_executor.py; and Step 5's wording ("consume the already‑built route‑ahead result", "Do not add another router or prefetch path") describes consuming an artifact, not adding a per‑round draft/verify API. Full detail: docs/superpowers/notes/2026-08-14-pd-dflash-task6-step5-seam.md.

Recommendation: authorize a follow‑up (or amend Task 6's file list) for the dflash.py SpecSession seam + the read‑only route projection, gated behind the BM1 gate+top‑k projection the design already specifies. Then engine.py Step 5 can register EXACT expert_nbytes demand and let the 2‑D scheduler govern VERIFY under concurrency.

Verification (this base)

  • tests/python/serving/test_dflash_deficit_scheduler.py, test_batch.py, test_sequence.py, test_scheduler.py, tests/python/dflash/test_pd_dflash_report.py54 passed
  • tests/python/dflash/test_route_ahead_metrics.py, test_route_ahead_wire.py36 passed
  • gpt‑oss offload no‑regression tests/test_gpt_oss_offload_topology.py5 passed
  • ruff check + ruff‑format + LSP diagnostics on changed/resolved files → clean
  • test_gpt_oss_mxfp4_dispatch.py GPU/native failures are moe_infinity._v4_fp4 not being built in this CPU env (environmental, unrelated to this PR)

No _store/native rebuild: no C++ changed.

drunkcoding added 11 commits August 14, 2026 21:24
Record exact stored FP4/FP8 expert payload bytes through the route-ahead
observer so the measure-first gate can report wasted_prefetch_bytes as bytes,
not an expert count. RouteAheadStats.observe_layer gains an optional
expert_nbytes map and RouteAheadStepSummary/as_dict expose predicted/kept/
wasted byte fields (None when unavailable -- never a fabricated average).
ExpertPrefetcher.expert_nbytes_map is populated at registration time in
model_offload from live params (before offload placeholders erase shape);
the executor seam forwards it None-safely (isinstance-dict guard keeps mocks
and resident runs at None). Strictly additive and off by default.
Opt-in RTX PRO 6000 B0-B3 route-ahead serving runner. The CLI module is
import-safe (torch/moe_infinity imported only inside the GPU path), emits one
JSON row per (model,baseline,B,concurrency,repeat) matching REQUIRED_METRICS,
validates the device is an RTX PRO 6000 (12,0), refuses resident B0/B1/B2, and
blocks B2 as BLOCKED_UNTIL_2D_SCHEDULER until the 2-D scheduler lands. Wraps
draft/router/issue/verify/H2D in the frozen NVTX ranges the BM4 parser keys on.
GPU test is gated on MOE_DFLASH_SERVING_GPU (1 skipped, side-effect free
collection); CPU contract test locks the pure matrix/schema/writer logic.
Add BM1 summarise_row (pass iff t_router < t_verify, ratio + raw terms
retained) and a CPU-safe aggregation CLI: group raw rows into §8 matrices
keyed by (model,block,concurrency), permit blocked B2 via --allow-blocked,
attach BM1, and emit result_matrix.json/CSV/Markdown for validate_result_matrix.
Refactors the per-baseline metric check out of validate_result_matrix
(behavior-preserving).
run_phase_a.sh drives the full §8 matrix for both required MoE targets on one
RTX PRO 6000 with the documented env (HF_HOME, MOE_ENABLE_SM120, device-memory-
ratio<0.9 to force offload) and aggregates into result_matrix.json. All inputs
are documented env vars in the script header.
…(DRAFT/VERIFY scheduler)

Stacks the two independent additive PD-DFlash features from the same plan:
- origin/feat/pd-dflash-phaseA-runner (#157): expert_nbytes / ExpertPrefetcher.expert_nbytes_map
- origin/feat/pd-dflash-serving-scheduler (#156): Scheduler DRAFT/VERIFY + set/clear/admit_verify_demands

Conflicts in benchmarks/dflash/report.py and tests/python/dflash/test_pd_dflash_report.py
resolved KEEP-BOTH: #157's versions are strict supersets (Task-1 contract identical,
plus BM1/aggregation/CLI), preserving 100% of both sides' behavior.
…lator seam

Honest gate: Steps 1-4 of Task 6 are complete via the #156+#157 stack this
branch is based on. Step 5 (engine DRAFT->VERIFY->DRAFT with exact per-round
expert-byte demand) genuinely requires a public single-round control seam on
DFlashSpeculator (begin_session/draft_round/verify_round + a read-only route
projection) so the engine can register the pending verify's EXACT summed
expert_nbytes BEFORE the verify runs.

That seam does not exist (no draft_round/verify_round anywhere), and Task 6's
authorized file list scopes only serving/{batch,scheduler,engine}.py -- not
spec_decode/dflash.py or distributed/expert_executor.py. Post-hoc RouteAheadStats
can't gate admission, fabricating bytes from expert count is forbidden, and
re-implementing the draft/verify loop in the engine would be a forbidden second
router. Reporting the exact seam instead of hacking one in.
@drunkcoding
drunkcoding marked this pull request as ready for review August 15, 2026 18:21
@drunkcoding
drunkcoding merged commit fde70eb into dev Aug 15, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant