feat(preflight): measurement-fidelity gate for the benchmark harness - #204
Open
sicario001 wants to merge 8 commits into
Open
Conversation
Make the benchmark harness measure its own scheduling fidelity so we can tell harness-induced timing drift apart from real server behavior. - traffic/workers: record scheduler_ready_at as the item's intended ready_at (when it was *due*), not when the dispatcher happened to pick it up, so ready->dispatch lag becomes observable rather than hidden. - core/response: carry the paired lifecycle timestamps (ready/dispatched/ picked-up/client-sent) plus always-recorded client_sent_at. - evaluator/performance: accumulate ready->dispatch, dispatch->pickup, pickup->send and end-to-end ready->send drift into CDF sketches, surface them in the aggregated summary, and soft-WARN past a configurable threshold (lifecycle_drift_warn_threshold_ms, default 50ms). - core/tokenizer: make the transformers import lazy so importing the text client no longer forces the GIL back on under free-threading. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add opt-in record-book instrumentation (record_preflight_timing) to every client modality so preflight can join client- and server-side timelines by request id without putting any timing values on the wire. - All six clients (chat, completions, tts, realtime_tts, vajra_tts_stream, stt) stamp chunk_recv_times and attach a correlation request-id header. - The three streaming-input WS clients (realtime_tts, vajra_tts_stream, stt) additionally record per-segment input_send_times and their intended input_send_deadlines, enabling input-delivery and input-pacing metrics. - config/client: add the record_preflight_timing flag (off by default, so normal benchmarks are unaffected). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Give the AUDIO channel modality a real generator so STT workloads can be driven without a real audio dataset. - config/generator/channel: make AudioChannelGeneratorConfig concrete (duration_seconds, sample_rate, waveform=sine|silence, frequency_hz) with validation, replacing the NotImplementedError stub. - generator/channel/audio: AudioChannelGenerator writes a deterministic PCM-16 WAV (tone or silence) once per parameter set to a cache dir and reuses it across all requests; numpy/soundfile imported lazily. - generator/channel/registry: register AUDIO -> AudioChannelGenerator. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
sicario001
force-pushed
the
users/rayyan/preflight-validation
branch
3 times, most recently
from
July 24, 2026 08:18
ecec3a6 to
e65aac4
Compare
Add `veeksha preflight`, which certifies the harness keeps time honestly before its benchmark numbers are trusted. It drives the real scheduler -> dispatch -> client path against deterministic mock servers and gates p99 timing drift against thresholds. - servers: per-modality mock servers (raw-asyncio HTTP/SSE for chat/ completions/tts; websockets-based for realtime_tts/vajra_tts_stream/stt), each a pinned subprocess that records its own ground-truth timeline and serves it back over /preflight/records for a request-id join. - scorer: pure drift math over the paired record books -- request/response delivery, server ttfc/tpoc pacing fidelity, lifecycle dispatch drift, streaming-input delivery + pacing, and informational client-observed ttfc/tpoc. - validator: PASS / FAIL / SERVER_AT_CAPACITY verdicts (server-pacing breach is blamed on the mock, not the harness). - config/runner/report: benchmark-style config -- polymorphic traffic_scheduler, per-category workload/mock timing (text/tts/stt), configurable input length, and sessions = K * concurrency sizing. - cli: register the preflight subcommand. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
sicario001
force-pushed
the
users/rayyan/preflight-validation
branch
from
July 24, 2026 10:16
e65aac4 to
e0316eb
Compare
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Veeksha reports server-side timing (ttfc/tpoc, delivery latencies) as ground truth. But those numbers are only trustworthy if the harness itself keeps time honestly — if it dispatches requests on schedule, streams paced input on schedule, and doesn't add its own queueing/transport drift on top of what the server does.
This PR adds
veeksha preflight: a command that certifies exactly that. It drives the real scheduler → dispatch → client path against deterministic mock servers and gates the p99 timing drift against thresholds, so you can tell harness-induced drift apart from real server behavior before you trust a benchmark run.It also back-ports the core instrumentation (lifecycle dispatch-drift metrics) into the normal performance evaluator as a soft WARN, so production runs surface the same signal without needing a mock.
Why
On a real benchmark you only see end-to-end numbers; you can't tell whether an inflated ttfc came from the server, from transport, or from the harness dispatching the request late. Preflight removes the server as a variable (deterministic mock with a known ttfc/tpoc schedule) and instruments both sides, so every millisecond of drift is attributable to a specific stage.
How it works — the record-book model
No timing values ever go on the wire. Each request carries only a correlation request-id header. Both sides independently stamp their own monotonic clock (comparable because mock and client run on the same host), and the two timelines are joined by request-id after the run.
Symbol legend —
t_is a timestamp; the subscript_imeans "for the i-th chunk / segment" (0-indexed, so_0is the first).c= client side,s= server side:t_csclient_sent_att_srserver_recv_timet_ss_iserver_send_times[i]t_cr_ichunk_recv_times[i]t_cs_iinput_send_times[i]t_sr_iinput_recv_times[i]Concretely, the two record books hold:
client_sent_at(t_cs), per-chunkchunk_recv_times(t_cr_i), and — for streaming-input WS clients —input_send_times(t_cs_i) + the intendedinput_send_deadlineseach segment was supposed to be sent at.server_recv_time(t_sr),server_send_times(t_ss_i),input_recv_times(t_sr_i), and aresponse_start_timeanchor so ttfc isn't polluted by the streaming-input phase.The mock servers run as pinned subprocesses and serve their ground-truth record book back over
/preflight/records.Verdicts
The metrics
Grouped by what they certify (all in ms):
A. Lifecycle / dispatch drift (harness-only; no server needed)
lifecycle_ready_to_dispatch_msdispatched_at − ready_at— scheduler queue laglifecycle_dispatch_to_pickup_mspicked_up_at − dispatched_at— dispatcher → client-worker handofflifecycle_pickup_to_send_mst_cs − picked_up_at— client worker's own pre-send overheadlifecycle_ready_to_send_mst_cs − ready_at— end-to-end dispatch drift (sum of the three)B. Delivery lag (localhost transport/queueing; should be ~0)
request_delivery_mst_sr − t_cs— request bytes client → serverresponse_delivery_mst_cr_i − t_ss_iper chunk — response bytes server → clientC. Server pacing fidelity (breach → SERVER_AT_CAPACITY)
server_ttfc_abs_error_msabs((t_ss_0 − response_start) − configured_ttfc)server_tpoc_abs_error_msabs((t_ss_i − t_ss_{i-1}) − configured_tpoc)D. Streaming-input (WS clients only: realtime_tts / vajra_tts_stream / stt)
input_delivery_mst_sr_i − t_cs_i— per-segment client → server deliveryinput_pacing_abs_error_msabs(t_cs_i − deadline_i)— how far each paced segment slippedE. Client-observed (informational, not gated) — what a client-only view would report
client_observed_ttfc_mst_cr_0 − t_cs— end-to-end first-chunk latencyclient_observed_tpoc_mst_cr_i − t_cr_{i-1}— end-to-end inter-chunk latencyConfig & usage
Config is the same vidhi system benchmarks use, so every field is settable as a
--flag, a--config config.yamlkey, or a CLI sweep. There are four groups: which checks run, traffic, per-category workload/mock timing, and gate thresholds.1. Which checks run
One boolean per client pathway (all
Trueby default):--check-text(chat),--check-completions,--check-tts,--check-realtime-tts,--check-vajra-tts,--check-stt. The six clients fall into three workload categories — because their request/response shapes differ — and each category has its own config block:textttsstt2. Traffic & sizing
Traffic is closed-loop concurrency, configured with two scalar flags (preflight builds the scheduler itself with
rampup_seconds=0):--concurrency(default 50) — how many sessions are in flight at once (the load level you're certifying at).--num-sessions(default 500) — total sessions to drive per check (the sample size). Raise it for more samples / tighter p99s.# certify at concurrency 200 with 4000 sessions/check veeksha preflight --concurrency 200 --num-sessions 40003. Per-category workload & mock timing
Each block controls two things: the input the harness generates, and the schedule the deterministic mock promises (its ttfc/tpoc — the ground truth that pacing fidelity is measured against).
--text.*— chat & completions--text.input_tokens--text.num_response_chunks--text.server_ttfc_ms--text.server_tpoc_ms--tts.*— tts (HTTP), realtime_tts & vajra_tts_stream (WS)--tts.input_tokens--tts.input_chunk_tokens--tts.input_pacing_tps--tts.num_response_chunks--tts.server_ttfc_ms--tts.server_tpoc_msThe two WS clients stream the prompt in
input_chunk_tokens-sized messages paced atinput_pacing_tps— that pacing is exactly what theinput_pacing_abs_error/input_deliverymetrics grade. Plain HTTPttssends the prompt in one shot and ignores those two fields.--stt.*— stt (WS, audio-in)--stt.input_seconds--stt.input_chunk_bytes--stt.sample_rateinput_seconds, fixes the clip's byte size and thus how many input messages it streams--stt.num_response_chunks--stt.server_ttfc_ms--stt.server_tpoc_msThe audio is synthetic (from the new
AudioChannelGenerator— a cached tone/silence clip), so no dataset is needed.4. Gate thresholds & output
p99 ceilings, in ms unless noted (a breach flips the verdict):
--dispatch-drift-threshold-ms(10),--delivery-lag-threshold-ms(5),--server-pacing-threshold-ms(5, breach → SERVER_AT_CAPACITY),--input-pacing-threshold-ms(10, WS-input only),--max-unpaired-fraction(0.02).--output-dir(preflight_report) is where the rendered report is written.Examples
Results
Environment: single unpinned 10-core macOS box, free-threaded CPython 3.14t (
PYTHON_GIL=0), all six mock servers + clients contending for the same cores. All config values are the stockveeksha preflightdefaults — concurrency 50, 500 sessions/check; text/tts mock timing 200 ms ttfc / 20 ms tpoc over 100 response chunks and STT 200 ms / 50 ms over 40 deltas; 100-token prompts (tts/vajra input paced at 50 tokens/s over ~25 deltas), 3 s STT audio; gates dispatch-drift-threshold 10 ms, delivery-lag-threshold 5 ms, server-pacing-threshold 5 ms, input-pacing-threshold 10 ms, max-unpaired-fraction 2%. A warmup pass precedes the measured run so first-touch costs (librosa import, synthetic-WAV generation, connection setup) don't land as cold-start outliers.Concurrency 50, 500 sessions per client — this run
lifecycle_ready_to_sendlifecycle_dispatch_to_pickuprequest_deliveryresponse_deliveryserver_ttfc_abs_errorserver_tpoc_abs_errorinput_delivery(WS)input_pacing_abs_error(WS)client_observed_ttfc(info)client_observed_tpoc(info)–= metric doesn't apply (completions is single-response → no tpoc; input metrics are WS-only).PR Checklist (Click to Expand)
Thank you for your contribution to Veeksha! Before submitting the pull request, please ensure the PR meets the following criteria. This helps Veeksha maintain the code quality and improve the efficiency of the review process.
PR Title and Classification
Only specific types of PRs will be reviewed. The PR title is prefixed appropriately to indicate the type of change. Please use one of the following:
[Bugfix]for bug fixes.[Feat]for new features.[Core]for changes in the core benchmarking logic[CI/Build]for build or continuous integration improvements.[Docs]for documentation fixes and improvements.[Tests]for changes in the test suite.[Misc]for PRs that do not fit the above categories. Please use this sparingly.Note: If the PR spans more than one category, please include all relevant prefixes.
Code Quality
The PR needs to meet the following code quality standards:
make formatto format your code.docs/if the PR changes user-facing behavior. This helps users understand and adopt the new behavior.Notes for Large Changes
Please keep the changes as concise as possible. For major architectural changes (>500 LOC), we would expect a GitHub issue (RFC) discussing the technical design and justification. Otherwise, we will tag it with
rfc-requiredand might not go through the PR.Thank You
Finally, thank you for taking the time to read these guidelines and for your interest in contributing to Veeksha. Your contributions make Veeksha a great tool for everyone!