Fix the default argument of OpenAI Chat completion - #605
Merged
Merged
Conversation
merrymercy
added a commit
that referenced
this pull request
Jul 9, 2024
timethink
pushed a commit
to timethink/sglang
that referenced
this pull request
Mar 9, 2025
5 tasks
MengYu10151
pushed a commit
to MengYu10151/sglang
that referenced
this pull request
Jun 26, 2026
Bump the pinned DeepEP commit (ci_install_deepep.sh and docker/Dockerfile) from 9af0e0d0 to d4f41e4 (v1.2.1-32), the first pin that ships EPv2 ElasticBuffer (EPv2 was introduced in DeepEP sgl-project#605 / b306af0). d4f41e4 is a descendant of the old pin and still exports the legacy v1 Buffer, so the existing deepep backend keeps working while the epv2 backend can import ElasticBuffer. EPv2 links NCCL symmetric memory (nccl::NCCLSymmetricMemoryContext), so the build needs an NCCL shipping the symmetric-memory headers (verified with nvidia-nccl-cu13>=2.30.7).
MengYu10151
pushed a commit
to MengYu10151/sglang
that referenced
this pull request
Jun 26, 2026
Bump the pinned DeepEP commit (ci_install_deepep.sh and docker/Dockerfile) from 9af0e0d0 to d4f41e4 (v1.2.1-32), the first pin that ships EPv2 ElasticBuffer (EPv2 was introduced in DeepEP sgl-project#605 / b306af0). d4f41e4 is a descendant of the old pin and still exports the legacy v1 Buffer, so the existing deepep backend keeps working while the epv2 backend can import ElasticBuffer. EPv2 links NCCL symmetric memory (nccl::NCCLSymmetricMemoryContext), so the build needs an NCCL shipping the symmetric-memory headers (verified with nvidia-nccl-cu13>=2.30.7).
MengYu10151
pushed a commit
to MengYu10151/sglang
that referenced
this pull request
Jun 27, 2026
Bump the pinned DeepEP commit (ci_install_deepep.sh and docker/Dockerfile) from 9af0e0d0 to d4f41e4 (v1.2.1-32), the first pin that ships EPv2 ElasticBuffer (EPv2 was introduced in DeepEP sgl-project#605 / b306af0). d4f41e4 is a descendant of the old pin and still exports the legacy v1 Buffer, so the existing deepep backend keeps working while the epv2 backend can import ElasticBuffer. EPv2 links NCCL symmetric memory (nccl::NCCLSymmetricMemoryContext), so the build needs an NCCL shipping the symmetric-memory headers (verified with nvidia-nccl-cu13>=2.30.7).
MengYu10151
pushed a commit
to MengYu10151/sglang
that referenced
this pull request
Jun 29, 2026
Bump the pinned DeepEP commit (ci_install_deepep.sh and docker/Dockerfile) from 9af0e0d0 to d4f41e4 (v1.2.1-32), the first pin that ships EPv2 ElasticBuffer (EPv2 was introduced in DeepEP sgl-project#605 / b306af0). d4f41e4 is a descendant of the old pin and still exports the legacy v1 Buffer, so the existing deepep backend keeps working while the epv2 backend can import ElasticBuffer. EPv2 links NCCL symmetric memory (nccl::NCCLSymmetricMemoryContext), so the build needs an NCCL shipping the symmetric-memory headers (verified with nvidia-nccl-cu13>=2.30.7).
kenzhangwangshu
added a commit
to kenzhangwangshu/sglang
that referenced
this pull request
Jul 17, 2026
Bump the mainline DeepEP pin from 9af0e0d (v1.2.1, 2025-09-15) to 567632d, the last commit before the EPv2 repo reorg (sgl-project#605). This picks up deepseek-ai/DeepEP#458 (hidden-dim 3072 low-latency kernels), the use_fabric buffer kwarg (sgl-project#217), and NVSHMEM 3.5 runtime fixes (sgl-project#564), while keeping the pre-reorg layout the Dockerfile build steps expect. Also updates the matching checkout in ci_install_deepep.sh. Context: sgl-project#24502.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 5, 2026
…asurement boot is cheap SGLANG_VRAM_FLIGHT_TRACE now takes "1"/"all" or a comma-separated rank list. A SCOPE, not a cap: an armed rank still records its whole boot with nothing dropped. The reason to have it is that the ring is uncapped by design and its host-RAM cost scales with a boot's allocation count on a swapless box, so the pressure to reach for max_entries -- the knob that produced the sgl-project#602 wrap -- has to be answered by a different lever. A rank scope costs the unscoped ranks their trace visibly; max_entries costs every rank its oldest events silently. This makes the measurement boot stageable. Marks alone (SGLANG_VRAM_FLIGHT_DIR, ~4 ms per rank per boot, no trace) already yield the complete per-post resident dataset; the trace is only needed to break a post down by call site, and can then be armed on one rank. TESTS - 236 green across the mem_ledger suite (was 232; four scope tests added, including that "0" is read as a rank name and not as a boolean off, which would otherwise produce a boot with no trace at all). - GPU chain test re-run on the 5090: ALL PASS, 16 checks. - The wiring pin from the previous commit caught this commit's own change of arm_process_trace's signature and had to be updated. That is the pin working.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 5, 2026
…tead of modelling it The demand model overpredicts by 4664 / 993 / 2701 MiB on this rig (sgl-project#602 window), i.e. up to 4.7 GiB of KV pool per card is given away, because no MODELED term has ever been checked against a MEASURED one. This adds the instrument that produces the measurement. It records and attributes; it sizes nothing and writes no number into the ledger. Three sources, because no single one covers the posts. 1. Phase marks. mark() reads torch.cuda.memory_stats and NVML at eight named boot boundaries (BOOT_PHASES) and appends one JSON line per mark. The difference between two consecutive marks IS the post allocated between them. Measured cost: 0.6 ms per mark, ~4 ms per rank per boot. 2. Process-start allocation recording, armed in run_scheduler_process before the first CUDA allocation. max_entries is NOT capped: the sgl-project#602 capture set it to 100000, came back exactly full, and therefore silently held only its final 10.7 s. The window is instead bounded by an EVENT -- the snapshot is dumped and recording stopped once every runner in the process is up -- so nothing inside the window is dropped and serving does not pay +1.7 us per allocation (3.7 vs 2.0 us, measured) for the life of the process. Dumped once per process, not per runner: under speculative decoding the target and the NEXTN draft both capture graphs, and a snapshot taken at either one's capture_end is missing the other's. 3. The non-torch remainder, per PID. Each mark records what NVML says THIS pid holds on the card, so non_torch = nvml_self - torch_reserved is measured rather than left over from two card-level totals. This also settles TERM_PARENT_CONTEXT by direct observation instead of by gap inference. CORRECTION TO THE sgl-project#602 HANDOFF. It advises reading device_traces and NOT segments[].blocks[].frames. That is right for those captures and the reason is worth keeping straight: torch fills block frames only for blocks allocated after recording began, so a post-boot arming starves that structure (80 of 2046 blocks, 3 of 25142 MiB). Armed at process start it becomes the EXACT resident attribution, because it is keyed on the blocks the allocator still holds rather than on a ring of events. Both structures are parsed, and both parsers return a Coverage verdict beside their numbers -- the sgl-project#602 aggregation produced a tidy, sorted, entirely truthful 3 MiB answer to a 25142 MiB question with nothing in the output saying so. MEASURED, and correcting an assumption of my own: torch.cuda.is_initialized() is NOT "a primary context exists". On this rig, pinned to the 5090: after import torch -> False / NVML 0 MiB; after importing any sglang.srt module -> True / NVML 0 MiB; after the first 1-byte allocation -> True / NVML 500 MiB. Verified in the same run that current_device(), memory_stats() and _record_memory_history() bind nothing either, which is what makes it safe for a mark to read them at process start. The direct question is answered by NVML's per-process list and recorded as holds_device_context. FINDING, not fixed here: DemandInputs.parent_binds_cuda_context is hardcoded False at engine.py:467, so TERM_PARENT_CONTEXT is never charged on the production path -- only test_full_demand_reserve_593 ever sets it True. On the reference rig the parent/tokenizer binds a context on the TP0 card, so this is an UNDER-charge of about one context. It is left alone until the measurement boot observes the parent directly in NVML's per-process list; correcting a term against an inference is what this task exists to stop. TESTS - test_flight_recorder_605.py: 26 tests green (hermetic, CUDA_VISIBLE_DEVICES=99). - Whole mem_ledger suite: 232 green, no regression. - CAN-FAIL PROVEN by mutating production code and observing red, four times: coverage ignoring unframed blocks -> 3 red; python_site returning frames[0] -> 3 red; churn ignoring orphan frees -> 2 red; deleting the kv_pool_sized call site -> 1 red. Restored to green after each. - Parsers run against the real sgl-project#602 captures, not fixtures: 2046 blocks / 80 framed / 25142 MiB reserved / 100000 entries / 40 orphan frees / 31 MiB peak outstanding, all asserted. The 31 MiB independently reproduces the handoff's corrected figure. - CHAIN TEST ON A REAL CARD (scripts/vram_ledger/flight_selftest.py, 5090 by UUID, ~570 MiB, corridor untouched): ALL PASS, 16 checks. It proves what no fixture can -- arming binds no context, marking binds no context, and a snapshot from a process-start arming reaches COMPLETE coverage with the probe allocation attributed to its own source line. Its first cut asserted on torch's is_initialized flag and reported four failures against a correct instrument; that is where the measurement above came from. - Wiring pinned against the serving tree's own source, because sgl-project#602 closed with twelve green fixture tests beside a production carrier that lacked the field. Proves presence, not execution; execution on the serving path needs a boot. NOT YET DONE: no measurement boot has run, so there is no per-post dataset for this rig yet and demand model v2 is not started.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 5, 2026
…asurement boot is cheap SGLANG_VRAM_FLIGHT_TRACE now takes "1"/"all" or a comma-separated rank list. A SCOPE, not a cap: an armed rank still records its whole boot with nothing dropped. The reason to have it is that the ring is uncapped by design and its host-RAM cost scales with a boot's allocation count on a swapless box, so the pressure to reach for max_entries -- the knob that produced the sgl-project#602 wrap -- has to be answered by a different lever. A rank scope costs the unscoped ranks their trace visibly; max_entries costs every rank its oldest events silently. This makes the measurement boot stageable. Marks alone (SGLANG_VRAM_FLIGHT_DIR, ~4 ms per rank per boot, no trace) already yield the complete per-post resident dataset; the trace is only needed to break a post down by call site, and can then be armed on one rank. TESTS - 236 green across the mem_ledger suite (was 232; four scope tests added, including that "0" is read as a rank name and not as a boolean off, which would otherwise produce a boot with no trace at all). - GPU chain test re-run on the 5090: ALL PASS, 16 checks. - The wiring pin from the previous commit caught this commit's own change of arm_process_trace's signature and had to be updated. That is the pin working.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 5, 2026
…ys honest Precondition for arming SGLANG_VRAM_FLIGHT_DIR on every production boot. The mark file is APPENDED -- that is what lets a crashed boot keep the boundaries it did reach -- so a permanently armed recorder makes one file hold many boots, and a reader that returns the whole file returns marks from several process lifetimes. phase_deltas over that computes a difference from one boot's last mark to the next boot's first: a number that describes nothing, printed in the same table and the same units as the real posts. Left alone, permanent arming would have made the instrument's output less trustworthy the longer it ran. - Every mark carries boot_id, derived from the LAUNCHER (this process's parent pid + start time) rather than from this process, so all ranks of one boot agree on it without a collective. A per-process uuid would tag each rank's file differently and make cross-rank reading impossible. - read_marks returns the latest boot by default, a named boot on request, and the whole file only when explicitly asked with boot="all". - phase_deltas SKIPS the seam and logs it, rather than reporting it. - list_boots + `attribute_flight.py boots` say which boots a directory holds; `phases --boot` selects one. MEASURED, for the retention question: one rank's boot is 8 marks / 5800 bytes (725 B per mark), so a 3-rank boot costs 17 KiB and 1000 boots cost 16.6 MiB. No rotation policy is proposed for the marks, because at that size the condition does not bind and an unused knob is one more thing to get wrong. Snapshots are the opposite case (~18 MB each) and are only written when the trace is armed, which stays window-only. TESTS - 241 green across the mem_ledger suite (was 236; six boot-scoping tests). - CAN-FAIL PROVEN twice: making phase_deltas span the seam -> 1 red (4 deltas where 3 are real); making read_marks return the whole file -> 2 red. - attribute_flight.py smoked end to end against a two-boot directory: `boots` lists both, `phases` shows only the latest. - Rebased onto 7044be2 (production tree: sgl-project#602 ledger + sgl-project#603 hoist) before all of the above; the rebase was clean and every call site survived it.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 5, 2026
…t posts The payout step. "Internal demand overpredicts by 4664 / 993 / 2701 MiB" is a fact that funds no fix: it says the model is wrong without saying WHICH term is wrong. This puts each modeled term beside the measurement that brackets it and prints the error per term. - contract.py writes the MODELED ledger into the flight directory at boot (no-op unless the recorder is armed, before the fit/refuse verdict so a refusing boot is inspectable). Without it the two halves of the comparison never exist at once: the ledger is logged and gone, the marks arrive later. - reconcile.py maps terms to phase gaps through TERM_TO_POST, a TABLE with a stated basis per entry, so a reader can reject a mapping he disagrees with instead of reverse-engineering it from arithmetic. - `attribute_flight.py reconcile <dir>` prints it. TWO WAYS SUCH A TABLE COULD LIE, both pinned: ABSORBING. A measured byte no term claims, folded into the nearest term, makes the table balance and the unmodeled post disappear. The residuum is therefore computed independently and printed as its own row whether it is 4000 MiB or 0. PRETENDING TO MEASURE. A term with no bracketing boundary is UNMEASURED, not 0-measured. Reporting 0 would manufacture a full-size overprediction on a term that may be perfectly correct -- TERM_NCCL_BUFFERS is exactly that case today. Two more honest refusals fell out of the mapping: the pool-sizing gap holds the KV pool AND the state pool, so the KV pool (the ledger's residual) is subtracted -- and when the gap is SMALLER than the pool the ledger placed in it, the gap is not split at all, because the pool did not get what was budgeted and a negative state pool is nonsense reported as fact. TERM_ACTIVATION is labelled a LOWER BOUND: the first forward is not necessarily the deepest the rank will see. TERM_PARENT_CONTEXT gets a DIRECT settlement rather than an inference: bytes held on the card by any process that is not a rank of this boot, from NVML's per-process list. A rank-only card yields a MEASURED zero, which is a different statement from "we did not look". TESTS - 254 green across the mem_ledger suite (was 241; 13 reconciliation tests). - Two of those tests failed on first run and the CODE was right both times: the residuum reported 1325 and 300 MiB where I had predicted 900 and 0, and in each case it had named exactly the posts I had left out of my own fixture ledger. Expectations corrected, not the code. - CLI smoked end to end against a synthetic boot: a deliberately inflated capture term reads +2701 MiB against a 900 MiB measurement, the unmodeled attention workspaces land in a 300 MiB residuum, and the NCCL term reads UNMEASURED. NOT YET RUN against a real boot; no rig numbers exist here. The mapping bases are claims about where allocations happen and the first real boot is what tests them.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 5, 2026
…, not where one flagset looks FIRST REAL EXECUTION FALSIFIED THE PAYOUT. Production booted the recorder tree at 21:11, wrote all three ranks' marks correctly, and produced NO modeled ledger, so reconcile had nothing to compare against. Two independent defects, either of which alone would have wasted the boot. 1. THE DUMP SAT ON A FLAG-GATED PATH. It was placed in enforce_boot_contract, which is reached only from _vram_ledger_non_kv_per_gpu, which sits inside `if vram_ledger_enabled()`. Production runs --rank-auto-reserve-mib auto with enable_vram_ledger False, so it takes ledger_full_demand_per_gpu and never calls the contract at all. server_args.py states this outright in its own comment: "the gated ledger path has always added it (_vram_ledger_non_kv_per_gpu), this one did not, and production runs THIS one". I had that comment in front of me while writing the dump. The fix is not a better caller. It is that a caller was the wrong KIND of place: the dump now sits in engine.build_card_ledgers, the single function that constructs a ledger, whose own docstring says both paths share it. No reserve path, flagset or future caller can route around it. 2. THE LAUNCHER AND THE RANKS WOULD HAVE DISAGREED ON THE BOOT ID. The ledger is built during argument resolution in the LAUNCHER; the marks are written by the RANKS. boot_id derived from the parent process gives a rank its launcher (right) and the launcher its shell (wrong), so the two halves would have been filed under different ids and reconciliation would have matched nothing even with defect 1 fixed. The launcher now publishes the id through SGLANG_VRAM_FLIGHT_BOOT_ID and the ranks inherit it. The published value equals what the parent-based derivation produces, so nothing that already works changes. TESTS - 263 green across the mem_ledger suite (was 254; 9 new). - The new tests EXECUTE the constructor rather than inspecting the source. A source-level assertion would have passed for the shipped defect too: the call was present, just somewhere production never went. That is the whole lesson of this commit and it is why the test calls build_card_ledgers and looks for the file. - CAN-FAIL PROVEN twice against the exact shipped defects: putting the dump back behind the contract -> 3 red, including "no ledger written by the constructor" and the ledger/marks id-agreement test; making the launcher derive its id from its parent -> 1 red. - Also pinned: contract.py may not mention the recorder at all, so nothing Stage 1 needs can drift back behind that gate. - A dump failure never costs the caller its ledger (asserted against an unwritable directory); unarmed boots write nothing. Found while making the fix: my scripted removal of the old dump truncated contract.py, taking kv_pool_mib_per_rank with it. The suite caught it on the next run. Restored from git and redone. NOT YET RUN against a real boot. The next armed boot is what proves this, and it proves it by producing a ledger_<boot_id>.json beside the three mark files.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 5, 2026
…rank runs two runners The 21:11 boot's marks show 14 phases per rank, not 8: under speculative decoding the target AND the NEXTN draft each run initialize(), so pre_weight_load / weights_loaded / kv_pool_sized / capture_begin all fire twice. Only capture_end carried the runner tag, which was enough to read the capture posts and not enough for the rest. MEASURED on rank 0 (5090), why this matters: target weights 13124 MiB, then reserved DROPS 154 MiB, then draft weights 2052 MiB. reconcile's gap rule takes the first occurrence of the opening phase and the last of the closing one, so the state-pool gap (weights_loaded -> kv_pool_sized) currently spans the draft's weight load and would charge 2052 MiB of draft weights to the mamba/GDN state pool. The number would have looked like a large underprediction in a term that is fine. This commit only makes the data separable; the per-runner gap arithmetic in reconcile.py is the next step and is not in here. TESTS: 263 green, unchanged. This is a tagging change; the boot that proves it is the next armed one, and it proves it by showing draft_worker on all 14 marks instead of 2.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 5, 2026
…t skipped Crashes 9, 10 and 11 (2026-08-05) all ended in the same unhelpful shape: ranks 0 and 1 standing in one collective, rank 2 standing in a different one, and nothing anywhere saying which collective rank 2 had SKIPPED. The tracebacks report where each rank was STANDING, which is downstream of the defect. The per-rank counts already existed -- the prefill line prints "tp.all_reduce 243.4/129x" -- they were simply never compared ACROSS ranks. This adds that comparison as a standing instrument. It is measurement, not mitigation: it changes nothing about what the ranks do and cannot repair a divergence. It reports, so the next crash arrives with its cause attached. Counting: one dict increment per collective, at the four GroupCoordinator dispatch sites, keyed by the family names the collective clock already derives (tp.all_reduce, dcp.all_gather, ...). Placed AFTER the clock's re-entry guard so each collective is counted exactly once. Guarded by a module-level bool resolved at import, so the hot path costs one bool read plus one dict increment. Two reporting paths, for two different failure states: 1. Scheduler._census_tick -- the detector. Runs on tp_cpu_group (gloo), NEVER the device/BAR1 path, so a wedged device group cannot silence the instrument meant to explain it. Rides the same unconditional once-per-iteration point as the sgl-project#603 reduce, so its round counter is replicated and the cadence gate opens on the same round for every rank. Default every 50 iterations (~2 s in production), an order of magnitude inside the ~30 s spin deadline: the divergence is named while the ranks are still healthy, long before the abort. 2. format_local_census, called from barlink_bar1.check_aborted before it raises -- the wedge-proof half. Takes NO collective on purpose: by abort time a peer is very likely dead (in all three crashes the third rank aborted ~30 s after the first two), so a cross-rank exchange would hang exactly when the evidence is wanted. Each rank logs its own counts; the three lines are diffed afterwards. Warn-never-raise throughout: a failed comparison is logged and dropped, and the abort-path dump can never mask the real error. ARMED BY DEFAULT, like the sgl-project#605 flight-recorder marks -- an instrument that must be switched on before a crash explains no crashes. SGLANG_COLLECTIVE_CENSUS=0 disables counting; SGLANG_COLLECTIVE_CENSUS_INTERVAL tunes or (<=0) disables only the periodic comparison, leaving the abort dump armed. Tests: test/registered/unit/distributed/test_collective_census_583.py Hermetic (no CUDA, no process group, no model). The injected divergence is crashes 9/11 in numbers: [129, 129, 128] on tp.all_reduce. * 14 passed * can-fail proof: breaking only the count comparison in _diff turns 4 of them red * pins the missing-key case (a rank that skipped a family's ONLY collective has no key at all -> must read as zero, not drop the family) * pins armed-by-default, the kill switch, the replicated cadence gate, and warn-never-raise on a wedged/absent group * regression: census + retract-583 + 603 + retract-fcfs = 35 passed * ruff: 0 new findings (parallel_state 0/0, barlink_bar1 2/2, scheduler 89/89, schedule_batch 40/40); new files ruff-clean and formatted; codespell clean Crash 11 (21:26, boot 11, tree WITHOUT the retraction fix) is byte-for-byte crash 9's shape and NOT crash 10's: all three ranks are inside run_batch (scheduler.py:2032), ranks 0/1 at communicator.py:1179 and rank 2 at linear.py:2340, with check windows 1 and 4. So the `if batch:` fork is not involved there, and crashes 9/11 are a site INSIDE the forward, distinct from the retraction site closed for crash 10. The census is what will name it.
efschu
added a commit
to efschu/htsglang
that referenced
this pull request
Aug 13, 2026
…false zero residue The fill side of sgl-project#602 stayed open because the instrument that was supposed to name the posts was wrong in two ways on the ship config. Both were found by reading the marks of a real ship boot (1353495-1786609875, 2026-08-13, --tp-size 1 --pp-size 3 --rank-gpu-memory-mib 31800,14000,15600). RANK COLLISION. Marks are filed under the TP rank. The ship config runs TP=1 with PP=3, so the TP rank is 0 in all three processes and all three append to flight_marks_rank0.jsonl. read_marks keyed its result on the rank field, so three processes on three different cards came back as one timeline, and differencing it produced posts no card ever paid -- a 20480 MiB card's 482 MiB CUDA context billed to the 32607 MiB card. Grouping is now by pid, which the writing process stamps and which cannot collide while it lives. The boot is also resolved across all rank files instead of per file, since ranks do not stop writing at the same instant. FALSE ZERO RESIDUE. non_torch_bytes was written as max(0, nvml_self - reserved). On this config torch reports up to 7162 MiB MORE reserved than NVML says the process holds, so the subtraction went far negative and the field read 0 -- publishing "no CUDA context, no NCCL buffer, no JIT workspace on this card" for a rank whose context measured 886 MiB. A floor built to absorb sub-MiB quantisation was swallowing gigabytes. The two cases are separated: non_torch_measurable says whether the subtraction is a measurement at all, and unbacked_reservation_bytes measures how far reserved exceeds resident. The new report closes the per-card identity exactly on all three cards of the ship boot: nvml_total = carve_out + resident + foreign + free, drift 0 MiB. NOT claimed here: that the unbacked reservation causes the underfill. The CUDA path of get_available_gpu_memory reads torch.cuda.mem_get_info (the driver's free) after an empty_cache, not torch's reserved counter, so that chain is falsified rather than asserted. Tests, PYTHONPATH=/spinning/wt-605-fr/python, python3 -m pytest: - test/registered/unit/mem_ledger/test_fill_side_605.py: 4 passed. Red first: 3 of 4 failed against the pre-fix recorder (rank grouping "1 != 3"; KeyError non_torch_measurable; unbacked_reservation_bytes absent from a mark whose non_torch_bytes read 0 on 27308 MiB resident). - Can-fail proof for the unbooked-allocation falsifier: a mutant that sets the residual line to 0 fails with "!! IDENTITY BROKEN by 300 MiB"; reverting the mutant restores 4 passed. - test/registered/unit/mem_ledger/: 357 passed, 1 failed, 1 collection error. Both pre-existing and untouched by this change: the 612 communicator-group declaration test and a missing 'datasets' module, neither of which references flight_recorder, read_marks or the report. - ruff: all checks passed. black: clean. codespell: clean.
efschu
added a commit
to efschu/htsglang
that referenced
this pull request
Aug 13, 2026
…ed spread Records what the recorder produced once it stopped misfiling ranks and stopped publishing a floored zero (eb5ace7). The fill-side table closes the per-card identity exactly on all three cards of ship boot 1353495-1786609875 -- nvml_total = carve_out + resident + foreign + free, drift 0 MiB -- with a corridor overshoot of +3569 / +1134 / +1830 MiB. The answer to "why is this not computed exactly beforehand" is a spread over 14 boots of one config: cuda_context_and_comm has spread EXACTLY 0 (888 / 482 / 482 MiB, every boot), while kv_pool_target moves 1364-2408 MiB and tracks the free-at-last-mark spread almost one for one. The corridor overshoot is not made of hidden consumers; it is made of the pool being sized differently each boot. Also names what the unbacked reservation is, which was this shift's open risk: the KV pool is a CUDA VMM arena (mem_cache/kv_vmm_backing.py, "256 GiB virtual; free until committed") exposed as a torch.cuda.MemPool through CUDAPluggableAllocator and committed incrementally against a watermark, so torch's reserved counts the pool's LOGICAL size while NVML counts committed pages. Their difference is the uncommitted span. That reframes the fill side: the free VRAM is space the arena has not committed, so the lever is the commit watermark, which C22 already localised. Register: C23 (the reserved-counter causal chain, falsified), C24 (the false zero residue), C25 (rank vs pid under PP), C26 (what reserved means here). Not claimed: that raising the watermark fills the corridor. The recorder does not yet mark committed bytes; that is named as the next stage. Tests: test_fill_side_605.py 4 passed. Docs-only otherwise.
efschu
added a commit
to efschu/htsglang
that referenced
this pull request
Aug 13, 2026
…posts it cannot support Stage 4 of the flight recorder: mem_ledger/measured.py reads the recorder's boot history and offers per-card residuals to the ledger, off unless SGLANG_VRAM_LEDGER_MEASURED is set. The rule that makes this worth having is the refusal. Measured over the ship boots of 2026-08-13, the posts of one unchanged config fall into two populations: cuda_context_and_comm at spread EXACTLY 0 (888 / 482 / 482 MiB over 20 boots) and kv_pool_target at spread 1364-2408 MiB. A median exists for both and looks equally like an answer. Installing the second would convert variance into false precision, so precedence is not "prefer any measurement" but "prefer a measurement stable across at least MIN_BOOTS boots"; anything wider is logged as DECLINED with its spread and the modelled term stands. Real-data result, no GPU touched: cuda_context_bytes = 888 / 482 / 482 MiB, derived from the boot history instead of from the GPU probe that calibration.py otherwise spends device seconds on. python -m sglang.srt.mem_ledger.probe --from-flight-recorder DIR reports what the history supports and what it refuses. The import sits inside that branch, so the boot path never reaches this module and is byte-identical with the flag absent. Tests, PYTHONPATH=/spinning/wt-605-fr/python: - test_measured_source_605.py: 8 passed, including off-by-default (inert without the env var, active with it) and too-few-boots. - Can-fail proof: a mutant whose stability verdict ignores the spread fails both TestWidePostIsRefused cases; reverting restores 8 passed. - test/registered/unit/mem_ledger/: 365 passed, 1 failed. The failure is the pre-existing 612 communicator-group declaration test, untouched here. - Validated against the real history at /spinning/flight_605: 20 boots, three cards, spread 0 on every card. - ruff, black, codespell clean.
efschu
added a commit
to efschu/htsglang
that referenced
this pull request
Aug 13, 2026
…ots, and the corridor under load R2. Four things that were argued in R1 are now measured, on a boot of the ship configuration (1464299-1786612548, argv from the s485 capture). COMMIT WATERMARK AS A POST. KvVmmArena keeps a read-only census (arena_census, a WeakValueDictionary and not a WeakSet so observing an arena cannot keep it alive) and mark() records kv_arena_reserved / backed / retained per phase. The chain "commit watermark -> resident -> free -> corridor" is now a measured quantity rather than a plausible story. Measured at first_forward: the 5090 holds 31182 MiB of arena reservation against 22690 MiB committed, i.e. 8492 MiB reserved and unbacked, beside 3463 MiB free on the card. retained is 0 on this boot and is reported separately from backed on purpose -- parked handles are memory NVML charges the process for while backed does not. LEDGER DUMP ON SHIP BOOTS. The modelled ledger was never built on the shipped config: it pins --rank-gpu-memory-mib, which is the pin path, and the pin path skips the planner, so fourteen boots of recorded marks sat beside zero modelled counterparts and reconcile.py had nothing to compare. __post_init__ now builds one for the RECORD after the configuration resolves, gated on the recorder already being armed and wrapped whole. The ledger is discarded: never returned, never consulted for a size. First ledger_<boot>.json on a ship-config boot in this chain was written by this commit. CORRIDOR UNDER LOAD, 100 ms. The boot marks are snapshots and cannot answer a law about a continuous floor. corridor_trace.py samples in-process (bounded ring, off unless SGLANG_CORRIDOR_TRACE_MS is set) and corridor_sampler.py samples the same quantity from OUTSIDE the ranks, which needs no call site in the scheduler. Both reduce on the MINIMUM, because a floor is broken by the worst instant and not the typical one. Measured over 75 s, 750 samples per card, under five real generations: 3080 5c64 free min 1542 MiB margin +518 no breach 5090 31d7 free min 2801 MiB margin +1777 no breach 3080 62db free min 2062 MiB margin +1038 no breach ERRORS FIRST, THE INSTRUMENT'S OWN: the first version of the sampler cost 25250.9 us per card per sample and ran at a 75.7% duty cycle, because the registry's memory_info_for_uuid opens an nvmlInit/nvmlShutdown pair and scans every device by UUID on each call -- thirty init/shutdown cycles per second at this cadence. Handles are now resolved once per run: 28.9 us per card, 0.0867% duty, 0 overruns. The cost is published in every summary rather than assumed, and the two runs agree within ~150 MiB despite the 874x difference, which is what makes the cheap reading trustworthy. Tests, PYTHONPATH=/spinning/wt-605-fr/python: - test_corridor_trace_605.py: 8 passed. Can-fail proof: a mutant reducing on the mean instead of the min fails the single-trough breach case. - test/registered/unit/mem_ledger/: 373 passed, 1 failed -- the pre-existing 612 communicator-group test, which references none of this. - ruff clean on every file touched here. server_args.py carries 357 pre-existing ruff errors, identical count in the untouched ship worktree. - Real generations against the measured boot: 5/5 http 200, 320 tokens each.
efschu
added a commit
to efschu/htsglang
that referenced
this pull request
Aug 13, 2026
…demand is exact R1's headline is withdrawn by measurement. It reported a per-post spread over "14 boots of one unchanged config" and concluded the corridor overshoot was boot-to-boot nondeterminism in KV pool sizing. The 14 boots were >=11 different configs -- the sgl-project#656 shift was editing --phase-flip-tp-vector between them -- so R1 pooled distinct configurations into one distribution and read the variance as randomness. The conclusion was drawn as wide as the question instead of as wide as the sample. Grouped by full post signature the same 14 boots give 11 signatures, one with four members, and those four are byte-identical on every post and every card. A fifth boot taken on the same captured argv but a DIFFERENT code tree reproduced it exactly: resident 28436 / 18002 / 16674 MiB. Given its configuration the boot's demand is exact and repeatable to the byte, and the only quantity that moves at all is the NVML-unattributed driver line. Also settled here: the 702 MiB weights_target spread is between-config, not a layout lottery (three cards rise together by identical +28/+674 increments, which no re-partition can do, since a re-partition conserves the total); the residual's three suspected tenants are excluded by NVML's own per-process list showing exactly one pid per card; and the corridor holds under load with the binding card's worst instant at 1542 MiB, +518 over the law. The number the KV-universe shift asked for: the arena carries 6.8-8.5 GiB of reserved-but-uncommitted address space per card, so the commit watermark is not capacity-limited, and the safely claimable amounts at the under-load worst instant are +1777 / +518 / +1038 MiB. Register: C27 (the retraction), C28 (weights layout falsified), C29 (the pin path is why the ledger never dumped), C30 (residual candidates excluded). Docs and register only. Ship restored via res-r5 and verified with a REAL generation (120 tokens, http 200), not a health 200.
efschu
added a commit
to efschu/htsglang
that referenced
this pull request
Aug 13, 2026
… then externally killed An earlier note would have left a successor believing this shift ended with serving up. It did -- health 200 at 09:31:00Z and a REAL generation of 120 tokens, not a health 200 alone -- and then the instance took an external SIGKILL at 09:32:32Z as the sgl-project#656 shift opened a new window. The instance's own log rules out the kernel OOM killer (oom_kill still 9, MemAvailable 57872 MiB). No attempt was made to boot into their live window: two instances on one set of cards is an OOM, which the capture-replay script refuses by design.
efschu
added a commit
to efschu/htsglang
that referenced
this pull request
Aug 13, 2026
…project#605 VRAM flight recorder) Merge source origin/feat/vram-flightrecorder-605 @ 848ccb6 onto the step-1 tip 70302cf. Conflicts: 0. 18 files, 2566 insertions, 217 deletions. Carries: per-boot attribution with drift 0 (marks grouped by PID, not by TP rank -- under PP the TP rank is 0 in all three processes and rank-grouping billed a 3080's context to the 5090); the commit watermark posted as a recorded quantity via KvVmmArena.arena_census(); continuous under-load mode; and the ship-boot ledger dump -- ServerArgs.__post_init__ now builds a modelled ledger FOR THE RECORD, gated on the recorder already being armed and discarded immediately, because the ship config pins --rank-gpu-memory-mib, which takes the pin path, which skips the planner, so 14 boots of measured marks had sat beside zero modelled counterparts. Flag-gated throughout: with SGLANG_VRAM_FLIGHT_DIR unset the dump returns on its first line. Both source branches of MERGE-R7 touch python/sglang/srt/server_args.py and docs/dev/631/CONTRADICTIONS_REGISTER.md. Both merged without conflict and both sides were verified present in the merged files afterwards rather than assumed: the kv-universe seam/vacate comment blocks and the sgl-project#605 _dump_observation_ledger are all present, and the register is +526 lines / -0 against 481411a, which is exactly 518 (kv-universe) + 8 (flight recorder). TEST RESULTS -- same CPU-only desk protocol as step 1 (CUDA_VISIBLE_DEVICES=99, PYTHONPATH=<worktree>/python, pytest --color=no, one directory per invocation). | suite | BASE 481411a | after step 1 | after step 2 | |----------------------|-----------------|--------------|--------------| | sgl-project#631 flip family | 1116 passed | 1116 passed | 1116 passed | | unit/managers | 9F 1357P 18S | 9F 1357P 18S | 9F 1357P 18S | | unit/mem_ledger | 1F 359P | 1F 359P | 1F 379P | | unit/model_executor | 15F 594P | 15F 594P | 15F 594P | | unit/server_args | 615P | 615P | 615P | | unit/turnkey | 116P | 116P | 116P | | unit/utils | 46F 348P 4S | 46F 348P 4S | 46F 348P 4S | | unit/docker | 4P | 4P | 4P | | new-656 arm | (files absent) | 4F 56P | 4F 56P | Every failure count identical to baseline at every step; the one mem_ledger failure is the same inherited test_communicator_group_contract_612.py case before and after. +20 mem_ledger passes are this step's three new sgl-project#605 test files. Total new tests across both merges: +80 collected, 0 new failures. Lint, base vs merged over the 37 touched .py files: ruff 473 -> 472 (one error removed in phase_policy.py, none added; all 15 new modules ruff-clean). black 26.1.0, the version pinned in .pre-commit-config.yaml: 9 files dirty before, 9 after, but the SETS DIFFER -- this branch's reformat of server_args.py is not churn, it FIXES pre-existing drift (server_args.py, model_runner.py and kv_vmm_backing.py were black-dirty at 481411a and are clean now), while three newly added test files land dirty. Six files are dirty on both sides. Recorded, not fixed: a merge shift does not reformat, and the standing defect is that the pre-commit hook is not being run on this line. codespell 9 -> 11; the two new hits are both the word "unparseable" (a valid variant) and the pre-existing "schedul" hit at CONTRADICTIONS_REGISTER.md is the deliberate 15-character TASK_COMM_LEN truncation from MERGE-R5 and must not be "fixed".
efschu
added a commit
to efschu/htsglang
that referenced
this pull request
Aug 13, 2026
…el collision Both R7 source branches extend docs/dev/631/CONTRADICTIONS_REGISTER.md and the union merged cleanly (+526 lines, 0 deletions), but the merged file carried EIGHT ambiguous identifiers, which is a silent defect in the one document whose purpose is that a claim can be looked up. feat/vram-flightrecorder-605 appended eight table rows labelled C23-C30. Every one of those labels was already in use at 481411a for an unrelated contradiction: C23-C26 the four '### C<n>' sections further down the file (the SGLANG_UNEVEN_TOKEN_VECTOR reading, the sgl-project#695 recipe's rank discovery, the sgl-project#695 exact-size pin, sgl-project#644's allocator residual) C27-C30 narrative entries the body itself cites 4, 9, 3 and 6 times The briefing for this shift anticipated a four-label collision (C23-C26). It is eight: C27-C30 are load-bearing too, which is only visible by grepping the body rather than the headings, since the incumbents are prose entries and the arrivals are table rows -- the two forms do not textually conflict, so git merged them without a murmur. Resolved by renaming the ARRIVING side, which has no inbound references in this file, to a namespace that cannot collide: C23->C605-1 ... C30->C605-8, in arrival order. Verified programmatically that all eight row bodies are byte-identical apart from the label; nothing was dropped, merged or reworded, and no incumbent entry was touched. A note above the table records the mapping, and both sgl-project#605 handoffs, which name their own labels in prose, carry a pointer to the shipped ones. Docs only: no code path, no test, no count changes.
efschu
added a commit
to efschu/htsglang
that referenced
this pull request
Aug 13, 2026
…n eight-label register collision Records what merged (feat/kv-universe-656 @ 4157aad, then feat/vram-flightrecorder-605 @ 848ccb6, both --no-ff, both conflict-free), the suite counts at every step against the frozen baseline /spinning/wt-merge-r7-base @ 481411a, the register union verification (+542 lines, 0 deletions), and the follow-ups carried from both branch handoffs. Errors first, and the three worth reading before quoting anything else: 1. The C-label collision the briefing sized at four labels is EIGHT. The sgl-project#605 rows arrive as TABLE ROWS while the incumbent C23-C30 are '###' sections and prose entries, so git merged all eight silently and the heading grep -- the check that was legitimate in R6, when only one branch touched the file -- reports the file clean. C28 alone is cited nine times in the body. Resolved by renaming the arriving side to C605-1..C605-8; bodies verified byte-identical apart from the label. 2. Four cases in test/srt/test_phase_flip_serving_proof_gate.py -- the file pinning the quarantine-constant removal, i.e. step 1's central claim -- cannot pass under the CPU-only merge protocol at all: they need a visible accelerator. Proven inherited by running the identical arm against the untouched source worktree. So that gate did NOT run in this merge, and the branch's own "239 passed" was measured with a device visible. 3. The sgl-project#605 branch's server_args.py reformat is NOT churn. It is a black 26.1.0 pass that fixes pre-existing drift: server_args.py, model_runner.py and kv_vmm_backing.py were formatter-dirty at 481411a and are clean now. Reverting those hunks to keep the diff tight would have re-broken the file. Six files remain dirty on both sides -- the pinned pre-commit hook is not running on this line. Also records that the stale local feat/route-a-631 ref is now THREE rounds behind and still checked out in another strand's worktree, so R8 must keep using origin/* as merge sources and HEAD:refs/heads/* for pushes. Docs only.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 13, 2026
…ng the ledger TASK 1 (weights on the pin path) and TASK 4 (residual recalibration). COMPLETENESS CHECK, red-first. reconcile.completeness_failures() names any card whose model-weights term is priced at zero or absent. Run against the real shipped dump ledger_1464299-1786612548.json it fails on all three cards, which is the red the brief asked for: model weights (shards) on GPU 0/1/2: priced at 0 MiB. This is the PIN PATH signature -- pinning --rank-gpu-memory-mib skips the planner that computes the shard vector, so the term is built and dumped as a zero rather than refused. A REFUSAL PASSES THE CHECK. Only a silent zero fails. That distinction is the whole point: a zero is indistinguishable from a price. WEIGHTS ON THE PIN PATH. _build_card_ledgers now accepts weight_mib_per_rank and history; both default to None and None reproduces the old behaviour exactly, so the sgl-project#593 sizing paths are byte-identical. Only the observation ledger passes them -- a sizing path must not change what a boot reserves as a side effect of an instrument being armed. PIPELINE PARALLELISM RETURNS None, NOT A NUMBER. The ship configuration is pp_size=3 / tp_size=1 with --pp-layer-ratio 28,20,16, so the split is a LAYER split, and per-layer bytes are not uniform on a hybrid Qwen3.5/3.6 checkpoint (interleaved GDN and full attention). Solving the measured episode-1 posts 13674/8325/9293 MiB for a uniform per-layer cost gives 488/416/581 MiB per layer -- the model does not close, so it is not shipped. None reaches the ledger as no term at all, which the completeness check then names. HISTORY INTO THE LEDGER. build_card_ledgers(history=...) gives measured-over- inherited precedence for the two terms the boot history can speak to, and refuses rather than averages a wide one: hardware residual band charged at its HIGH, superseding the window- 2026-08-06 probe (664 -> 902 MiB on the 5090) load transient REFUSED and UNBOUNDED; the inherited 70 MiB is explicitly NOT used as a fallback A refused residual band keeps the probe calibration: a wide history is a reason to distrust a summary of the history, not to discard a direct measurement. Tests: 15 new across test_history_into_ledger_605.py (8) and test_pin_path_weights_605.py (7), all red first. The byte-identical-default test is the one protecting every existing caller. Suite: 531 passed, 1 failed (inherited test_communicator_group_contract_612, also failing at base cd71ec3). black 26.1.0 clean; ruff 0 on every touched file, same as base.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 13, 2026
…a caller TASK 3 (missing boundaries) and TASK 6 (corridor_trace production call site). NCCL BOUNDARY. TERM_NCCL_BUFFERS has been in the ledger taxonomy since sgl-project#595 with nowhere to be measured, so it read UNMEASURED on every boot ever recorded. BOOT_PHASES gains nccl_init_begin/nccl_init_end and model_runner marks them around the whole group-building block. The end mark sits AFTER the phase-flip secondary groups, not after initialize_model_parallel: those groups are communicators too, and a boundary drawn before them would price a launch's NCCL buffers at whatever fraction the primary topology happens to build. GDN SCRATCH GETS A NAMED BOUNDARY BUT NO CALL SITE, deliberately. The GDN prefill scratch is allocated inside a forward pass, not at boot, so there is no honest boot-phase home for it; inventing one would put a mark on the hot path to satisfy a table. TERM_TO_POST names gdn_scratch_begin/end so the reconciliation reports the term as UNMEASURED-with-a-named-missing-boundary -- a to-do with an address rather than a permanent blank. CORRIDOR CALL SITE. R2 open item 1: the sampler was tested, ready and callerless -- a module the tree carried and never ran. Scheduler gains _corridor_trace_tick(), called beside _census_tick(). It arms ONCE (a sampler per iteration would be one NVML thread per scheduler round), never raises, and never retries a failed arming. Off by default in two independent ways: the state lives in class-level attributes so an un-armed scheduler carries no per-instance attribute at all, and corridor_trace.start() returns None unless SGLANG_CORRIDOR_TRACE_MS is set. Tests: 9 new (test_corridor_trace_call_site_605.py), red before the change with AttributeError on Scheduler._corridor_trace_tick. The tick is exercised by binding the REAL Scheduler method to a stub, not by mocking the method under test, so a rename on the production side fails this file. Three tests pin the off-by-default property and two pin never-raise/never-retry. The existing phase-contract tests (every declared phase has a call site; no call site invents a phase) both accept the new pair. Suite: 424 passed, 1 failed (inherited test_communicator_group_contract_612). black 26.1.0 clean.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 13, 2026
…re the model was
TASK 5. Re-ran reconcile.py against the same boot 1464299 data with the
corrected mapping, and the headline is a retraction of the first run's own
table rather than a verdict on the model.
Two of the first run's five findings were instrument defects, not model
defects:
weights 27800 MiB measured on a card holding 26364 MiB in total -- the
row summed two loads across a free. Correct: 13850 (largest of
three episodes 13674/13850/2074).
transient 0 MiB measured at the one mark where the quantity is
structurally zero. Real peak 13392 MiB.
And the totals row subtracted a BUDGETED KV pool (29927 MiB) from a MEASURED
footprint whose arena actually backed 21130, driving measured demand to
-3045 MiB. Now read from the arena census; demand reads 5752/4113/3961 MiB.
ACCEPTANCE. Every row is now matched, matched-within-a-recorded-band,
UNMEASURED-with-the-boundary-named, or REFUSED-with-the-refusal-quoted. The
refused activation and graph-capture terms were absent from the first table
entirely and are now rows.
THE WEIGHTS ROW DOES NOT CLOSE, AND IS NOT FAKED. pp_size=3 with
--pp-layer-ratio 28,20,16 makes the split a LAYER split; per-layer bytes are
not uniform on a hybrid checkpoint (solving the measured posts for a uniform
cost gives 488/416/581 MiB per layer, a 39% spread). The estimator is named as
open; what ships is the completeness check that fails loudly on the pin path's
silent zero.
Docs: docs/dev/631/HANDOFF_LEDGER_RECONCILE.md,
docs/dev/631/RECONCILE_SECOND_RUN.md
Register: C605-9..C605-12 appended (summed-weights measurement, the 70 MiB
transient in both value and mapping, the residual recalibration, the
budgeted-KV-pool subtraction).
Evidence: /spinning/evidence-631/ledger-r1/ (rerun_reconcile.py,
reconcile_second_run.txt, boot_history_bands.txt, RECONCILE_SECOND_RUN.md).
Suite: 424 passed, 1 failed vs base 379 passed, 1 failed (same inherited
test_communicator_group_contract_612). black clean, codespell clean.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 13, 2026
…econciled nothing Follow-up on five live boots in /spinning/evidence-631/acceptance-656/flight/. All four verified fixed against boot 1917721-1786622304. Two this branch already covered; two it did not. 1. THE TOOL HAD RECONCILED NOTHING FOR AN ENTIRE RELEASE. read_marks was correctly changed to PID keying (the ship config runs --tp-size 1 --pp-size 3, so all three processes file under TP rank 0) and attribute_flight._reconcile() was never updated: it handed the pid dict into marks_by_rank.get(int(rank)). Pids 1918126..8 cannot equal ranks 0..2, so EVERY card matched nothing and the tool printed "The ledger names no card whose rank left marks" and exited 1 -- read by two shifts as a fact about the boot. THE SILENT SKIP WAS A PINNED CONTRACT and is the accomplice: a test asserted an unmatched rank is skipped rather than invented, which made a total keying mismatch look like a quiet edge case. reconcile() now re-keys via marks_by_rank_from_pids() -- card uuid, else the caller's key, else the MAXIMUM rank the marks carry (process-level phases all report 0, written before the runner knows its pipeline rank; verified on two boots) -- cross- checks nvml_total_bytes against the card, and REFUSES on any card left unmatched. CardVramLedger.to_json now emits the uuid so the join is identity rather than inference. 2. MEASURED DEMAND WENT NEGATIVE: -2023 MiB on the 5090, -180 on a 3080. My fix already subtracted the measured pool but FELL BACK to the modelled budget when the arena census was absent -- the same defect wearing a condition. Fallback removed; absent an arena census the demand refuses loudly. The obvious second source is rejected by measurement: the target runner's weights_loaded -> kv_pool_sized growth contains the KV pool AND the state pool (7720 vs 6916 MiB on boot 1464299). 3. _field_bytes TOOK THE FIRST MARK = always the target runner. The peak fix covered only the transient. Live boot 1917721 reads the hardware residual at 886 MiB on the target and 896 on the draft. A field term is a LEVEL, so it is now the MAXIMUM across runner partitions; summing would be wrong and process-level phases are unchanged. Falsifier (target 0 / draft nonzero) pinned. 4. not_applicable IS NOT UNMEASURED. NCCL buffers are correctly 0 under barlink; reporting that as UNMEASURED invites a successor to hunt for the boundary this branch just added, measure 0, and conclude the recorder is broken. Renders "N/A -- not applicable to this launch (barlink ...)". LIVE ACCEPTANCE, boot 1917721-1786622304: demand -2023 / 158 / -180 -> 5740 / 4075 / 3919 MiB residual 886 / 480 / 480 -> 896 / 496 / 496 MiB (draft runner) NCCL UNMEASURED -> N/A (barlink) CLI exit 1, zero cards -> all three cards rendered Output: /spinning/evidence-631/ledger-r1/reconcile_live_boot_1917721.txt Tests: 13 new (test_reconcile_caller_keying_605.py), fixtures transcribed from the live boot, all red first. Two legacy tests pinned falsified premises and are updated in place with the falsification in their docstrings. Suite: 437 passed / 1 inherited failed (base 379/1); with turnkey 553/1. Register: C605-13..C605-17. black 26.1.0 clean, ruff 0 on every touched file.
efschu
added a commit
to efschu/htsglang
that referenced
this pull request
Aug 13, 2026
…ject#605 reconcile-loop closure) Reconcile-loop closure for the sgl-project#605 VRAM flight recorder, merged at 20e2e37 onto cd71ec3 (the MERGE-R7 tip both lines carried). Carried: pin-path weight completeness check (the pin path skips the planner, so the ledger's largest post shipped as 0 MiB on every pinned boot; None now reaches the ledger as no term at all and reconcile names it loudly, where a zero would have passed every check by looking like a price); the load transient boundary and its refused constant; the NCCL phase boundary (nccl_init_begin/end around the whole group-building block, end mark placed after the phase-flip secondary groups because those are communicators too) with N/A(barlink) rendering; hardware-residual recalibration from 472 boots of recorded history (refuse-wide rule, charge the band HIGH never the mean); the corridor_trace.py production call site in Scheduler._corridor_trace_tick, flag-gated default OFF in two independent ways; the caller-keying fix in attribute_flight.py (a PID-keyed dict was passed into a rank-keyed lookup, so every card matched nothing and the tool reconciled ZERO cards for an entire release while printing that as a fact about the boot); measured-pool subtraction with loud refusal instead of a silent fallback to the modelled budget; _field_bytes max-across-runners; card uuid in the ledger dump. Register: appends C605-9..C605-17, no collision with the incumbent C605-1..C605-8 that MERGE-R7 created (9 lines added, 0 deleted). Tests documented in docs/dev/631/HANDOFF_MERGE_R8.md.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 14, 2026
…mmunicators the ledger was missing MERGE-R9 12.6, the one inherited mem_ledger red, and load-bearing rather than cosmetic: initialize_phase_flip_secondary_groups builds flip_tp, flip_dcp and flip_pp over the same world (parallel_state.py:3502-3512), and sgl-project#605 put the nccl_init_end mark AFTER that call on purpose (model_runner.py:1985) -- so the first boot to measure TERM_NCCL_BUFFERS measures those three communicators while the term's signature does not know they exist. Undeclared, they hit the OOM direction twice: their buffers were charged to no ledger row, and they left nccl_signature unmoved, so a figure measured on a non-flip launch was silently reusable on a flip one. Both directions of the contract now hold. The over-declaration arm was already green and stays green: flip_pp is emitted with world_size=1 (the call site passes pp_size=1) and classify_communicator_groups -- not this inventory -- is what decides a single-rank group allocates nothing. Deciding it at the inventory would hide the group the moment the call site passes a different pp_size. flip_dcp is emitted on the CONSTRUCTION SITE's condition (dcp_size > 1 of the SECONDARY set), not on "dcp is enabled": the secondary set's DCP width is len(--phase-flip-tp-vector), and the primary --dcp-size has nothing to do with it. The width is read from the vector the call site itself reads, and server_args pins len(vector) == pp_size (server_args.py:7708), so the inventory cannot drift from the launch. A malformed vector falls back to pp_size instead of raising -- server_args is the judge of argv and the ledger runs before it; a bad flag must not arrive as a memory-ledger stack trace. TEST RESULTS (venv /spinning/htsglang-gpu/.venv, CUDA_VISIBLE_DEVICES=99, PYTHONPATH=<worktree>/python, pytest --color=no): base 99a4b0a test/registered/unit/mem_ledger/ 1 failed, 437 passed FAILED test_communicator_group_contract_612.py:: TestTheDeclarationNamesEveryGroupTheRuntimeBuilds:: test_no_runtime_group_is_missing_from_the_declaration -> ['flip_dcp', 'flip_pp', 'flip_tp'] != [] here test/registered/unit/mem_ledger/ 444 passed, 0 failed Name-diffed: the base red is gone and the delta is exactly the six new pins in TestThePhaseFlipSecondaryGroupsAreDeclared. No test changed verdict in the other direction.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 14, 2026
…mmunicators the ledger was missing MERGE-R9 12.6, the one inherited mem_ledger red, and load-bearing rather than cosmetic: initialize_phase_flip_secondary_groups builds flip_tp, flip_dcp and flip_pp over the same world (parallel_state.py:3502-3512), and sgl-project#605 put the nccl_init_end mark AFTER that call on purpose (model_runner.py:1985) -- so the first boot to measure TERM_NCCL_BUFFERS measures those three communicators while the term's signature does not know they exist. Undeclared, they hit the OOM direction twice: their buffers were charged to no ledger row, and they left nccl_signature unmoved, so a figure measured on a non-flip launch was silently reusable on a flip one. Both directions of the contract now hold. The over-declaration arm was already green and stays green: flip_pp is emitted with world_size=1 (the call site passes pp_size=1) and classify_communicator_groups -- not this inventory -- is what decides a single-rank group allocates nothing. Deciding it at the inventory would hide the group the moment the call site passes a different pp_size. flip_dcp is emitted on the CONSTRUCTION SITE's condition (dcp_size > 1 of the SECONDARY set), not on "dcp is enabled": the secondary set's DCP width is len(--phase-flip-tp-vector), and the primary --dcp-size has nothing to do with it. The width is read from the vector the call site itself reads, and server_args pins len(vector) == pp_size (server_args.py:7708), so the inventory cannot drift from the launch. A malformed vector falls back to pp_size instead of raising -- server_args is the judge of argv and the ledger runs before it; a bad flag must not arrive as a memory-ledger stack trace. TEST RESULTS (venv /spinning/htsglang-gpu/.venv, CUDA_VISIBLE_DEVICES=99, PYTHONPATH=<worktree>/python, pytest --color=no): base 99a4b0a test/registered/unit/mem_ledger/ 1 failed, 437 passed FAILED test_communicator_group_contract_612.py:: TestTheDeclarationNamesEveryGroupTheRuntimeBuilds:: test_no_runtime_group_is_missing_from_the_declaration -> ['flip_dcp', 'flip_pp', 'flip_tp'] != [] here test/registered/unit/mem_ledger/ 444 passed, 0 failed Name-diffed: the base red is gone and the delta is exactly the six new pins in TestThePhaseFlipSecondaryGroupsAreDeclared. No test changed verdict in the other direction.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 16, 2026
… unattributed
WHAT THE GAP COST, MEASURED. On 2026-08-16 at 02:36:30 an instance died with
GPU 0 ... 76.38 MiB is free ... Process 1920108 has 4.29 GiB memory in use
Naming that process took hours: log archaeology, then a pid-clock interpolation
across two boots' `boot_id` fields (pid 1851351 -> 02:10:44, pid 1924983 ->
02:38:10, 44.7 pids/s, so pid 1920108 lands at 02:36:22). It turned out to be a
test harness on the serving card.
Every fact needed to answer that in ONE LINE was already computed. `_nvml_view`
returns `nvml_processes`, the full pid->bytes map of everyone on the card, on
every mark. The recorder simply stops marking: its last boot post is
`first_forward`, and the failure was 36 minutes later.
NOT A DUPLICATE OF THE sgl-project#605 CORRIDOR SAMPLER, and the difference is durability.
That sampler does run during serving, at 100 ms, and does call `_nvml_view`:
* it keeps a fixed-size RAM ring, so it dies with the process that crashes --
which is the one process whose state the post-mortem needs;
* its `Sample` retains free/self/reserved/allocated and DISCARDS the per-pid
map it just read, so it cannot name a foreign holder even while running;
* it was not armed on the boot that died.
Marks are appended to a FILE and survive the crash. That is not a theoretical
advantage: the surviving boot marks are exactly what made the pid clock
calibratable after the process was gone.
A SEPARATE FILE, DELIBERATELY. The boot ledger's readers pair marks BY POST
NAME (`reconcile` asks for the `weights_loaded -> kv_pool_sized` delta, and for
`kv_arena_backed_bytes` at `boot_complete`). A boot post is a unique boundary;
a serving sample is a time series, and thousands of the latter in that file
would turn a table of posts into a log with posts in it. So the series goes to
`flight_serving_rank{n}.jsonl` and every existing consumer of
`flight_marks_rank{n}.jsonl` is untouched -- 467 mem_ledger tests confirm it.
ONE RECORD BUILDER, TWO DESTINATIONS. `mark` grew an internal `_filename`
rather than gaining a second copy of the record layout. A duplicated schema is
precisely how the field a post-mortem needs ends up present in one file and
missing in the other -- which is the shape of the defect this commit exists to
close.
PACED, ON THE MONOTONIC CLOCK. The call site runs once per scheduler iteration,
thousands of times a second; the pacer (default 30 s, `0` disables) is what
makes that affordable, and the cost when the recorder is unarmed is one dict
lookup. Wall time is unusable here: an NTP step backwards would stall the
series and a step forwards would flood it, and the boot that most needs the
record is the long-lived one whose clock is being corrected.
WHERE IT IS CALLED, AND WHY THERE. Beside `_corridor_trace_tick` in
`get_next_batch_to_run`, on that line's existing argument -- every rank reaches
it exactly once per round -- so the cadence is replicated and the per-rank files
line up round for round, which is what makes them comparable across ranks.
Unlike its neighbours it needs no collective and takes no branch: it is
write-only and cannot make two ranks disagree about anything. It is NOT on a
batch-conditional path, because an idle rank losing its card to a foreign
process is exactly the 2026-08-16 case.
THE CALL-SITE TEST EARNED ITS PLACE IMMEDIATELY. The first version of the tick
referenced `flight_recorder` as if it were a module-level import; it is
imported inside `run_scheduler_process`. That is a `NameError` on every
iteration, and the bare `except Exception` around it turned the whole
instrument into one that silently never runs -- the exact failure mode this
task exists to prevent, in the code meant to prevent it.
`test_the_tick_marks_with_this_rank` failed and named it. The import now sits
OUTSIDE the guard so it fails loudly, only the call is guarded, and the guard
logs once at WARNING rather than staying silent.
The recorder's own `BOOT_PHASES` comment states the lesson this file follows:
"twelve green fixture tests passed while the production carrier lacked the
field they all built by hand."
TESTS. `test_flight_serving_marks_684`, 17 cases, hermetic (CPU only, no CUDA):
- RED FIRST: all 13 API cases failed with `no attribute` before the change.
- The acceptance property reproduces 02:36:30 exactly -- this process at
26.65 GiB and a foreign pid at 4.29 GiB on one card with 80 MiB free -- and
asserts the foreign holder is named IN THE RECORD ON DISK.
- Pacing, monotonic-clock behaviour, `0` disables, a malformed interval falls
back rather than silencing the series, an unarmed process writes nothing.
- The boot ledger keeps one mark per post while the series accumulates.
- An NVML failure still leaves a timestamped record; a write failure and a
raising probe never reach the serving loop.
- Call site: taken off the REAL Scheduler class, so a rename fails this file;
pins `self.ps.tp_rank` (the Scheduler has no `tp_rank` -- a predecessor's
assumption that it did raised on every rank), and pins the position beside
the corridor tick.
Suites: 467 mem_ledger, plus 557 across mem_ledger + the 681/682 guard files.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 16, 2026
…he fix was on disk THE LEDGER COULD NOT ARBITRATE, TWICE IN ONE NIGHT. It reported `model weights (shards) = 0 MiB` on all three cards while they held 16196 / 10194 / 10832 MiB, marked three posts UNBOUNDED and said `fits=False` everywhere. Neither the sgl-project#683 attribution ("who took the card") nor the sgl-project#678 sizing question could be settled from it; both were answered by hand. (a) WHY THE ZERO, AND WHERE THE NUMBER WAS. Not an unwired term, not a fingerprint that never matches: `reconcile.completeness_failures` already names it -- the shipped config pins `--rank-gpu-memory-mib`, the PIN PATH, and the pin path skips the planner that computes the shard vector. The term is built from an all-zero vector and dumped as a price, indistinguishable in the JSON from a model that needs no weights. The flight recorder was already measuring it. The reserved-bytes delta between `pre_weight_load` and `weights_loaded` IS the shard footprint, per card, every boot. This reads that. Provenance gets a fifth kind, `MEASURED` -- not MODELED (no formula of ours produces it) and not CALIBRATED (not a cached probe under a fingerprint; re-measured every boot). That is the kind the standing directive asks for: demand from measurement, not estimate. DETECTION STAYS WHERE IT ALREADY WORKS. The engine does NOT add a second refusal for the zero case. `completeness_failures` calls it "the PIN PATH signature" and `require_complete` raises on it; a refusal inside the engine would change the verdict of every card whose shard vector is legitimately absent at that point in the boot, including the pre-planner ledger whose residual is the RANK BUDGET rather than the KV pool. I built that refusal first, watched it break five unrelated suites, and took it back out -- the detector is the acceptance, pinned in both directions: it stops firing once the post is measured and keeps firing on a fingerprint with no marks to stand in. (b) THE FITS SPLIT, A PRECISION AND NOT A WEAKENING. `fits` was `not unbounded and committed <= total`, so ONE inherently-unbounded transient made every card unfittable forever. The arithmetic side already passed (2848 against 32607); `fits=False` was caused purely by a non-empty `unbounded`. The load transient refuses on EVIDENCE -- 563 boots, a 0-18486 MiB spread, above the 50% refusal rule -- and that refusal is correct and permanent, so the flag was conflating "a post could not be priced" with "the card is overcommitted". A transient is a peak ABOVE the resident set, not a claim on the card. It now travels in `unbounded_transient`, rendered beside the verdict WITH its evidence, and does not block the fit. Resident refusals still do: pinned in both directions, including a synthetic unbounded resident post forcing fits=False. Nothing is estimated in either bucket. (d) THE ACTIVATION POST IS AN UPPER BOUND, LABELLED AS ONE. The serving marks sample `allocated_peak_bytes` under real load -- the counter `probe_activation.py` reads -- but never reset it, and a reset at mark time would change what every other reader of those fields sees. So what this publishes is a monotone envelope since process start, above the resting set, over-stated by an unknown amount and said so in the term's own derivation. Over-reserving is the safe direction; the failure this ledger exists to end is the under-charge. A per-phase point estimate needs the reset and is future work. THE INSTRUMENT BUILT TWO TASKS AGO IS WHAT MADE (a) AND (d) POSSIBLE, and it is live: 519 serving samples spanning 03:56:48 to 05:27:02 on the running boot, plus the boot-scoped marks. No new measurement path was added -- these are differences between marks the recorder was already taking. (c) STAYS GATED, AND THE INVESTIGATION RESOLVED -- see the report. Measured across the same two capture marks: reserved delta 184/182/182 MiB against an NVML free drop of 282/324/324, so the reserved-bytes delta is structurally blind to 98-142 MiB per card (the private-pool component an OOM here named directly). Feeding `capture_mib` would under-charge. The probe does not need replacing, the FIELD does -- the honest quantity is the NVML free delta these same marks already record -- but the refusal also carries an inherited "3.3-3.8x low" that does not reproduce on this config (~192 estimate against 282-324 measured, i.e. 1.5-1.7x), so that has to be re-derived rather than carried. The finding is recorded in the code; nothing is fed. TESTS. 13 new hermetic cases on the reader, red-first (all 13 failed on the missing API), including: the first load is the shard post and not the drafter or the second layout, cards kept apart by uuid, an unpaired load yielding nothing rather than a guess, no marks giving an empty answer rather than a zero, and the serving envelope labelled upper-bound-only. Plus the completeness detector pinned in both directions and the transient split pinned in both directions. Suites: 482 mem_ledger, 2415 across mem_ledger + unit/managers. The 4 failures in that sweep are pre-existing and unrelated, parity-proven earlier against the untouched tree.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 16, 2026
… allocator's
THE ALLOCATOR'S BOOKS ARE STRUCTURALLY BLIND TO PART OF A GRAPH CAPTURE.
Measured on this rig 2026-08-16, across the same capture_begin -> capture_end
marks:
card reserved delta NVML free drop blind to
5090 184 MiB 282 MiB 98 MiB
3080 182 MiB 324 MiB 142 MiB
3080 182 MiB 324 MiB 142 MiB
The gap is the private-pool component CUDA graphs take, which an OOM on this
rig named outright ("71.21 MiB allocated in private pools"). So the post is fed
from the NVML free delta, MEASURED provenance, re-measured every boot and never
cached across regimes -- the same rule the weights term follows.
BOTH NUMBERS ARE KEPT. `capture_reserved_mib` sits beside `capture_mib` in the
record and in the term's own derivation, so the blindness stays visible to the
next reader instead of decaying into folk knowledge about "why we use NVML
here".
THE STALE FACTOR IS WITHDRAWN, NOT SILENTLY REPLACED. The refusal carried
"3.3-3.8x low" from the 2026-08-05 window. It does not reproduce on this
configuration: the captured-tokens estimate reads ~192 MiB here against a
measured 282-324, i.e. 1.5-1.7x. The ESTIMATE stays rejected -- an under-charge
is the direction that OOMs -- but the factor is re-derived from this boot's own
marks rather than carried, and the refusal text now says so. That is the same
disposal the 550k pin got in sgl-project#678, for the same reason: a number that outlives
the regime it was measured in is not evidence.
CONTAMINATION IS A PRECISION CAVEAT, NOT A SAFETY ONE, and it is recorded as
such. NVML free is card-wide, so a foreign process allocating during the capture
window inflates the reading. That is an OVER-charge: it costs KV pool, never a
boot -- the same direction that justifies the activation upper bound.
A STRUCTURAL FLOOR, NOT A THRESHOLD. The driver cannot release less than the
allocator took, so an NVML delta BELOW the reserved delta on the same window is
physically impossible. That is an instrument fault, not a small capture:
`capture_fault_mib` appears instead of `capture_mib` and the term posts
UNBOUNDED loudly, quoting both readings, rather than feeding a number already
known to be wrong. A boot whose marks lack the pair at all posts UNBOUNDED too.
WHAT THE LEDGER NOW SAYS, from the running boot's records on disk (hermetic, no
card touched):
card demand before -> after KV pool before -> after fits
5090 1824 -> 19188 29759 -> 12395 False -> True
3080 1325 -> 12561 18131 -> 6895 False -> True
3080 1325 -> 13158 18131 -> 6298 False -> True
weights 16196 / 10194 / 10832 MiB (was 0 on all three)
capture 262 / 324 / 324 MiB (allocator-only: 164 / 182 / 182)
activation <=906 / <=718 / <=677 MiB (upper bound, labelled)
Every card prices its resident side fully and fits with honest numbers. The load
transient still refuses -- correctly, on 563 boots of evidence -- and travels as
a risk band that does not block the verdict.
TESTS. Four new hermetic cases on the capture reader: the fed number is the
driver's while the allocator's is kept beside it, an impossible reading becomes
a fault rather than a price, a boot without the pair prices nothing, and the
no-op second capture round of a flip boot is skipped rather than read as a
zero-cost capture. 485 mem_ledger, 2418 across mem_ledger + unit/managers; the 4
failures there are pre-existing and unrelated, parity-proven against the
untouched tree.
efschu
added a commit
to efschu/htsglang
that referenced
this pull request
Aug 17, 2026
…ribution, rank-2 root 1. RESTORE, NEVER REBUILD -- the pin (test_restore_never_rebuild_677.py). A fence patches the BUILD entry points (weights_arena.allocate_arena, weights_arena.pack_into_arena, torch.cuda.CUDAGraph) to raise, and the REAL production mover PhaseFlipStacks.refill runs under it on both legs, including the checksum-mismatch restore arm -- the one branch that touches the arena twice and is likeliest to reach for a rebuild. arena_refill is deliberately NOT fenced: it is the copy the flip exists to perform, and a pin that fenced it would pass by forbidding the work. Can-fail arms: every entry point is shown to actually raise, and a planted mover calling allocate_arena is caught. Pinning production rather than a re-implemented loop is the point -- a re-implementation keeps passing while production drifts (sgl-project#624). 2. PEAK-INSTANT ATTRIBUTION -- PhaseFlipRuntime._record_seam_peak, emitted on the sgl-project#605 flight-recorder channel (not a new one: it already carries the torch view, the NVML view and the boot id, and is append-only). Placed at _staging_affordable, the instant the flip's demand is weighed against free VRAM -- earlier the buffers do not exist, later the decision is already taken. Carries staging_bytes, refill_destination_bytes, graph_workspace_bytes, the reserve, driver free, allocator cached free, and a SIGNED unattributed_bytes. Two choices, both pinned and both mutation-proven: unmeasured components are None and never 0 (a zero reads as "costs nothing" -- the sgl-project#606 defaulted- measurement defect), and the residual is signed, because a negative one means the named terms OVER-count, a different defect that max(0, ...) would hide. Guarded end to end: an instrument on the seam path may cost a line, never a cutover. 3. THE RANK-2 ANOMALY -- the sgl-project#685 candidate is REFUTED. sgl-project#685 (0e50e48, f1774d7) is an UnboundLocalError use-before-bind on a variable named 'cell' in the cold seam-pricing branch; it has no arena-tail content and no 1456 MiB figure exists anywhere in source or records. The live candidate is arena GROWTH, from the sgl-project#690 image sizes: rank 0 PP 12619.6 TP 9614.9 growth 0.0 seam draw 909 rank 1 PP 9014.0 TP 9614.9 growth 600.9 seam draw 1006 rank 2 PP 7211.2 TP 9614.9 growth 2403.7 seam draw 1648 Rank 0's PP layout is the larger, so it never grows; rank 2 grows four times what rank 1 does. The ordering matches the draws exactly and no other per-rank term does. Stated as a CANDIDATE, not a finding: the excess over rank 0 is 16% of the growth on rank 1 and 31% on rank 2, so growth explains the order and not the size. Instrument 2 settles it without a dedicated experiment -- it emits exactly this quantity at the peak instant. FILED, NOT BUILT: TICKET_718_contiguous_destination_extent.md -- making a peer's destination extent contiguous so a BAR1 write lands in place and the receive buffer stops existing. The largest structural reduction available, and the only one that removes a buffer rather than relocating it; it touches the reshard wire format and the pool allocator together, so it belongs to a deliberate design pass. The ticket names what must be decided, what must not be assumed (it trades allocator freedom for staging bytes, and that freedom is what keeps admission working under fragmentation), and makes a live reading from instrument 2 its prerequisite. Tests, hermetic (CUDA_VISIBLE_DEVICES="", no GPU, no serving contact): test_restore_never_rebuild_677.py 7 passed + 3 subtests test_seam_peak_attribution_677.py 8 passed MUTATION PROOF: null->0 and signed->floored fails 3 of 8 FULL SUITE compared by failing NODE ID against base b786858, ANSI stripped (counts alone hid a real regression earlier in this branch): base 13 failed / 2181 passed; now 13 failed / 2208 passed regressions: NONE. The 13 are pre-existing. ruff + codespell clean on all changed files. Desk only. Live readings ride the later review boot.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 24, 2026
…ure what warm-up costs TWO PIECES THE DESIGN OWES, both consequences of carrying no KV. 1. VALIDATE-EARLY REFUSAL (sgl-project#806 pattern, ServerArgs.__post_init__). The flip retracts every resident request and DROPS the prefix tree, so the next phase starts with an empty device tier and restores prefixes by read-through. With --enable-hierarchical-cache off there is nothing to read through: the sgl-project#703 flip-time writeback has nowhere to persist, the retracted prefixes are gone, and every conversation re-prefills from scratch on every flip. That is a correctness-shaped cost, not a tuning one, and it is INVISIBLE at runtime -- the flip completes, the requests complete, and only the token bill says anything happened. A silent, expensive, correct-looking failure is what a launch gate is for. Placed beside sgl-project#806's own check and after `materialize_declarations`, for the reason sgl-project#806 documents: the hierarchical cache is switched by handlers above, so an earlier check would pass a launch this one refuses. sgl-project#806 refuses the flip that cannot ENUMERATE what it must move; this refuses the flip that cannot RESTORE what it deliberately drops. NO FALLBACK IS OFFERED AND THE MESSAGE SAYS SO -- a test asserts the phrase. Reviving the mover here would reintroduce the seam this ticket retired, the staging reserve behind W25's 33 refused arms, and the resident carry that crashed three ranks in sgl-project#825. Both exits are named instead, because which one is right depends on what the operator wanted. 2. THE WARM-UP LEDGER (managers/warmup_latency.py), the metric the user named: not "rows carried" but served-request latency by rounds since cutover. PRIOR ART CHECKED AND IT IS A NEAR MISS, not a hit: `regime_classifier.PhaseDwellGate.rounds_since_flip` has the rounds-since-flip concept but is a GATE deciding whether a flip may happen, and carries no latency. Also searched: phase_flip_runtime for warm/latency/post-cutover, the seam census (times the seam, not what follows it), the sgl-project#605 flight recorder (the seam's own peaks). Nothing measures this. Geometric bands (<=1, <=4, <=16, <=64, steady) because the CLAIM is that the cost concentrates in the first rounds and decays; a mean cannot be right or wrong in a way that shows that. Every band reports as a ratio against THIS instance's own steady state, so the figure needs no remembered number from another boot to be readable. The can-fail directions are the file's point. `None` survives wherever nothing was compared -- a ratio against an absent control reads as "no warm-up cost" while meaning "nothing was compared", the sgl-project#606 shape in the one number this ticket is judged on. "Has not flipped" never folds into "has flipped and settled". An empty ledger still says it has nothing to say. HALF-WIRED, AND SAID PLAINLY. `note_cutover` is wired at the cutover. The request feed is NOT: request latency is assembled in `tokenizer_manager`, a DIFFERENT PROCESS, so feeding it is a cross-process change rather than a line. Recorded as an open integration point instead of guessed at -- a wrongly-wired instrument reports a number, which is worse than reporting none, and this is the number the proof window judges the design on. TESTS (hermetic, CUDA_VISIBLE_DEVICES=""): test_phase_flip_needs_hicache_856.py in server_args/ -- 776 passed overall test_warmup_latency_856.py 13 passed, 5 subtests managers -k "phase_flip or seam or warmup or uncached" 564 passed, 28 subtests, 0 failed ruff format clean; ruff check adds ZERO errors -- verified per file from the repo root against HEAD: server_args 358 -> 358, phase_flip_runtime 0, warmup_latency 0, corridor_admission 0. RUFF MEASUREMENT CORRECTION, since a previous commit reasoned from it: ruff must be run FROM THE REPO ROOT or it does not find pyproject.toml and reports a different rule set entirely (phase_flip_runtime.py read as "110 errors" from a stray cwd and "All checks passed" from the root). The earlier 144-vs-144 comparison was taken with the same cwd on both sides, so its conclusion -- zero added -- stands; the absolute number was just scheduler.py's 102 plus schedule_batch.py's 42.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 30, 2026
…eport-only-Vorstufe) == BEFUND, DER DIESEN SCHNITT AUSLOESTE == `initialize_decoupled_kv_group` (parallel_state.py:3676) hatte NULL Aufrufer im ganzen Baum -- praesent-aber-unverdrahtet. Zwei Quellen: devindex symbol_profile meldet 0 aufgeloeste Caller UND 0 textuelle Reads; die Volltext-Gegenprobe ueber python/ findet ausserhalb von parallel_state.py nur einen Doku-String in mem_ledger/engine.py:678. Gleichzeitig gated `SGLANG_DECOUPLED_KV` bereits die POOL-Haelfte (model_runner_kv_cache_mixin.py:3352). Genau diese Asymmetrie IST die sgl-project#1007-Booby-Trap: die Pool-Haelfte zu armen dimensionierte einen Plan fuer eine Gruppe, die nie gebaut wurde. `refuse_pp_dcp_combination` (:3653) benennt diese Gruppe im eigenen Refusal-Text als den designierten Weg ("For token-sharded KV under PP use the #704b decoupled-KV group"). Die Sperre bleibt unberuehrt: sie verweigert das stille Vehikel (dcp_size ueberladen), nicht die Faehigkeit. == WAS DIESER SCHNITT TUT == (a) Aufrufer in ModelRunner.init_torch_distributed, an derselben Stelle und aus demselben Grund wie der sgl-project#631-Flip-Block darueber: der Create ist ein KOLLEKTIV, also muss das Erreichen rang-uniform sein -- ein Server-Arg ist das per Konstruktion. Vor der sgl-project#605-Flight-Recorder-Marke, damit die NCCL-Bilanz diese Kommunikatoren mitzaehlt. (c) `--enable-decoupled-kv`, DEFAULT AUS. Er baut die Gruppe und SONST NICHTS. `set_decoupled_kv_active` wird bewusst NICHT gerufen, `_DECOUPLED_KV_ACTIVE` bleibt False, die B1-Verzweigung in `get_dcp_group` (:2854) bleibt tot, die Pool-Haelfte ist nicht angefasst. Report-only-Vorstufe: die Gruppe existiert, liest sie aber niemand. == EIN PASSENDER DESK-CHECK (Fehlerklasse: Flag-Registrierung + Rangplan) == py_compile waere hier blind gewesen. Geprueft wurde stattdessen: 1. Flagge als dataclass-Feld registriert, Default False -> True/False 2. plan_decoupled_kv_ranks(w=3,tp=1,pp=3) = [[0,1,2]] (Flip-Form) 3. plan_decoupled_kv_ranks(w=3,tp=3,pp=1) = [[0],[1],[2]] (pure TP, degeneriert korrekt: B1 ist ein PP-Mechanismus) 4. CLI akzeptiert --enable-decoupled-kv -> ACCEPTED == BOOT-BEWEIS (boot_855_704bgroup2_0840f82601_0830_165321) == * "#704b decoupled-KV group built over pipeline ranks [[0, 1, 2]]" auf ALLEN DREI Raengen (PP0/PP1/PP2) -- Manifest-Gleichheit hielt * "manifest DIVERGES"-Refusal: 0 * "initialize_decoupled_kv_group was never called"-Assert: 0 * `set_decoupled_kv_active` trapsafe bare 0 / genuine 0 -> Routing nie gearmt * Serving liefert: "capital of France is" -> " Paris. Paris is the largest" ERSTER BOOT-VERSUCH SCHEITERTE EHRLICH und ist Teil des Befunds: Bar1WindowRefused -- die neue Gruppe 'decoupled_kv:0' erbte das 24-MiB-Default-Fenster, waehrend nur 12 MiB BAR1 frei waren (world 23 + pp 95 + flip_tp 47 + flip_dcp 31 bereits gehalten). Das Refusal ist KORREKT ("an explicit window is an instruction ... silently serving a smaller one would make every later size decision rest on a number nobody chose"). Behoben durch ein eigenes Fenster DECOUPLED_KV_0=8, nicht durch Abschalten von barlink. Merkposten fuer jeden weiteren Gruppenbau auf dieser Form: BAR1 ist mit ~196 MiB in vier Gruppen nahezu erschoepft. BELEG-STUFE: BOOT-BEWIESEN, dass die Gruppe auf allen Raengen entsteht und das Serving unveraendert laeuft. NICHT behauptet: dass token-gesharde KV unter PP damit funktioniert -- die Pool-Haelfte liest weiterhin dcp_size/attn_dcp_rank (unter PP 1 und 0) und ist der naechste, separate Schnitt (b), der ohne GO nicht gebaut wird.
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.
Fixes #582