docs: update README - #688
Merged
Merged
Conversation
timethink
pushed a commit
to timethink/sglang
that referenced
this pull request
Mar 9, 2025
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 16, 2026
…ed inert under load TWO FINDINGS FROM THE LOADED CORRIDOR RUN, one a fix and one a negative result that stops a default from moving. 1. A RUNG THAT RETURNS NOTHING NOW SAYS SO. The pre-gate KV relief was logged only under `if kv_freed > 0`. On 2026-08-16 the seam was refused 76 times from 06:47:48 with no relief line anywhere in the log, so "the rung returned 0" and "the rung never ran" were indistinguishable -- and the guard's own "reclaimed 0 MiB from [nothing]" was then read (by me, in the sgl-project#687 diagnosis) as the rung being exhausted. IT NEVER SAID THAT. That string is the GUARD LADDER's provider list, and the ladder has exactly two providers, allocator-cache and draft-weights. No KV provider is registered with the guard anywhere in the tree, deliberately: the cap is a group decision and the ladder is rank-local, so the rung's bytes arrive as `kv_freed` BEFORE the guard probes and can never appear in that list however much it paid. The zero line now says that outright, and names the three non-interchangeable causes to check: the admission floor (healthy), an empty evictable set (the pool is genuinely live), a disqualified rung (a defect). 2. SGLANG_FLIP_SEAM_CHUNK_MIB=16 BUYS NOTHING UNDER LOAD. DEFAULT STAYS 0. Row-blocking's own comment required a loaded corridor run before its default could move, because its measured 488.7 -> 305.6 -> 276.5 MiB shrink at B = 1, 4, 16 "was taken at 90 live slots and prices the seam's constant, not its behaviour under a full pool". That caution was right. Two boots of 8974994, same argv, same 4x25625-token load, one variable: chunk OFF 185650 live slots staging 1456.14 / 1354.00 / 2016.64 MiB chunk 16 288904 live slots staging 1657.42 / 1555.57 / 2250.81 MiB Fitting staging = a + b*slots per rank across each boot's own points: slope 0.001953 (off) vs 0.002064 (armed) MiB/slot intercept 1093.6 / 991.4 / 1686.6 vs 1061.3 / 959.4 / 1654.6 MiB Identical within 3%. The knob was verified live in the worker environment, not merely exported. The shrink does not appear because the backing term is `max(ceil(max(com_w, B*com_w - (B-1)*rel_w)/B), min(com_w, chunk_floor))`: with a release leg small against the commit leg the numerator stays near B*com_w and the division cancels, and the arena chunk floor binds what is left. At 90 live slots those terms sit differently, which is precisely why the comment demanded this run. Recorded rather than deleted: the knob and its 16-block default remain, so a successor with a different pool geometry can re-price it without rebuilding the machinery. What must not happen is shipping it as a default on the strength of a 90-slot measurement. BOTH BOOTS SERVED CLEANLY on the sgl-project#687 law-advisory code: 12 and 15 flips, 0 refusals, 0 delays, 0 withholds, 0 drain-mode yields, 4/4 requests each. The law warning fired 2 and 3 times and the seam proceeded every time. TESTS: 2 new source-assertion cases pinning the zero-report branch and the clause that ends the guard-ladder confusion (the same convention this file already uses for the rung's wiring), 29 in that file, 974 across every corridor / phase / purity / seam / margin / kv_backing suite.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 16, 2026
…ed inert under load TWO FINDINGS FROM THE LOADED CORRIDOR RUN, one a fix and one a negative result that stops a default from moving. 1. A RUNG THAT RETURNS NOTHING NOW SAYS SO. The pre-gate KV relief was logged only under `if kv_freed > 0`. On 2026-08-16 the seam was refused 76 times from 06:47:48 with no relief line anywhere in the log, so "the rung returned 0" and "the rung never ran" were indistinguishable -- and the guard's own "reclaimed 0 MiB from [nothing]" was then read (by me, in the sgl-project#687 diagnosis) as the rung being exhausted. IT NEVER SAID THAT. That string is the GUARD LADDER's provider list, and the ladder has exactly two providers, allocator-cache and draft-weights. No KV provider is registered with the guard anywhere in the tree, deliberately: the cap is a group decision and the ladder is rank-local, so the rung's bytes arrive as `kv_freed` BEFORE the guard probes and can never appear in that list however much it paid. The zero line now says that outright, and names the three non-interchangeable causes to check: the admission floor (healthy), an empty evictable set (the pool is genuinely live), a disqualified rung (a defect). 2. SGLANG_FLIP_SEAM_CHUNK_MIB=16 BUYS NOTHING UNDER LOAD. DEFAULT STAYS 0. Row-blocking's own comment required a loaded corridor run before its default could move, because its measured 488.7 -> 305.6 -> 276.5 MiB shrink at B = 1, 4, 16 "was taken at 90 live slots and prices the seam's constant, not its behaviour under a full pool". That caution was right. Two boots of 8974994, same argv, same 4x25625-token load, one variable: chunk OFF 185650 live slots staging 1456.14 / 1354.00 / 2016.64 MiB chunk 16 288904 live slots staging 1657.42 / 1555.57 / 2250.81 MiB Fitting staging = a + b*slots per rank across each boot's own points: slope 0.001953 (off) vs 0.002064 (armed) MiB/slot intercept 1093.6 / 991.4 / 1686.6 vs 1061.3 / 959.4 / 1654.6 MiB Identical within 3%. The knob was verified live in the worker environment, not merely exported. The shrink does not appear because the backing term is `max(ceil(max(com_w, B*com_w - (B-1)*rel_w)/B), min(com_w, chunk_floor))`: with a release leg small against the commit leg the numerator stays near B*com_w and the division cancels, and the arena chunk floor binds what is left. At 90 live slots those terms sit differently, which is precisely why the comment demanded this run. Recorded rather than deleted: the knob and its 16-block default remain, so a successor with a different pool geometry can re-price it without rebuilding the machinery. What must not happen is shipping it as a default on the strength of a 90-slot measurement. BOTH BOOTS SERVED CLEANLY on the sgl-project#687 law-advisory code: 12 and 15 flips, 0 refusals, 0 delays, 0 withholds, 0 drain-mode yields, 4/4 requests each. The law warning fired 2 and 3 times and the seam proceeded every time. TESTS: 2 new source-assertion cases pinning the zero-report branch and the clause that ends the guard-ladder confusion (the same convention this file already uses for the rung's wiring), 29 in that file, 974 across every corridor / phase / purity / seam / margin / kv_backing suite.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 16, 2026
…s standing in front of
54 MINUTES OF SILENT OUTAGE, health 200 throughout. From 16:23:10, 325
consecutive lines of:
BOTH BLOCKED: nothing can run in the pp layout and the target cannot admit
either (0 req resident, 10495392 tok pending)
Last real batch 16:23:11: full token usage 1.00, #running-req 0, mamba 0.17.
The whole KV pool was radix cache with ZERO resident requests -- every row
unlocked and evictable -- while 10.5M tokens queued and three GPUs sat at 0%.
ONE SWALLOWED EXCEPTION. _post_evict_rows asked tree_cache.evictable_size().
MambaRadixCache does not return a number from that method; it raises
NotImplementedError and says "use full_evictable_size() and
mamba_evictable_size() instead". The probe caught it and used 0, so on the
class this rig runs it returned `available` ALONE -- the exact error its own
docstring warns about, committed three lines below the warning.
At usage 1.00 that reads ~0, so every admissibility question answered no:
pp could not admit, tp had nothing resident to decode, and sgl-project#688's BOTH BLOCKED
branch declined. That branch returns BEFORE alloc_token_slots -- so the
allocator was never reached, eviction never ran, and the unlocked cache was
never freed. The receipt called it "an evict trigger" while no evict could
occur, which is the same counter-vs-actuator shape as sgl-project#681/sgl-project#694 in a third
place: a message naming an action nothing performs.
CONFIRMED BY ABSENCE in the specimen (WEDGE-2026-08-16T1623Z.txt): zero RADIX
SHAPE, zero "Out of memory", zero EVICTION UNDER-DELIVERED. The allocation path
was never entered. py-spy shows the ranks spinning the event loop building
nothing.
THE TRAP IS ALREADY DOCUMENTED IN THIS TREE, at common.py:411-425, for these
same two classes -- and I read that comment the same day while diagnosing sgl-project#694
and did not apply it here. The resolution order is now COPIED from there rather
than re-derived, because two spellings of one rule is how this comes back.
WHY NOW. The bug shipped with sgl-project#688's admissibility simulation and needed
usage == 1.00 to bite. sgl-project#696's floor repair shrank the pool by 39,504 tokens, so
full occupancy arrived sooner and the wedge began 12 minutes after that boot.
sgl-project#696 EXPOSED this; it did not cause it.
THE SHAPE TO LEARN: a swallowed exception that yields a PLAUSIBLE value. Zero
is a legal row count, so nothing downstream could tell "the cache holds
nothing" from "the cache was never asked". Every accessor is now tried in turn
and only a genuine absence of all of them yields zero.
Health being 200 for the entire outage is the second lesson: the endpoint
answers while the scheduler builds no batch. It is not a liveness signal.
TESTS: test_post_evict_rows_698.py 5 passed (red-first: pre-fix it fails
"0 not greater than or equal to 150000", reproducing the wedge arithmetic).
managers + mem_cache 64 failed / 1922 passed -- the same 64 baseline.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 16, 2026
…es, and pin it THE INVARIANT WAS PROSE. phase_policy's branch says "Declining here is what routes the caller to the evict rung instead of to a cutover." The caller did not: scheduler.py handled every decline identically -- one throttled log line, return. So on 2026-08-16 the instance printed "this is an evict trigger and NOT a flip" 350 times across 54 minutes while no eviction was ever attempted, health answered 200 the whole time, three GPUs sat at 0%, and 10.5M tokens queued behind a pool nothing would free. I wrote that comment in sgl-project#688. It is the fourth counter-vs-actuator member found today, and the first where the actuator existed only as a sentence. WHAT THIS COMMIT DOES: the decline now calls evict_from_tree_cache, bounded to one attempt per 5 s (the decline is evaluated every round, so an unbounded call walks the whole tree in a tight loop on an already-wedged box), and REPORTS WHAT EVICTION RETURNED. THE REPORT IS THE POINT AS MUCH AS THE CALL. "The remedy ran and freed 0" and "the remedy never ran" are the two states this outage could not distinguish, and telling them apart is what turns a silent wedge into a diagnosis. AND ON THIS SPECIMEN IT WOULD HAVE DELIVERED ZERO -- said plainly, because the routing is necessary and NOT sufficient. At 16:22:58-16:23:11 a single request was mid CHUNK-PREFILL (#new-seq 1, #new-token 512, #cached-token 0) while usage climbed 0.95 -> 1.00, with no retract, abort or finish anywhere in the window. A chunked request is resident but sits in NO BATCH (sgl-project#631 defect O), which is why the scheduler read #running-req: 0 while its own protected prefix held the pool. Eviction cannot free a locked chain. The deeper root is that a chunked request's prefix can fill the pool its next chunk must allocate from -- a self-deadlock -- and that is a separate fix on the chunked/admission path, not this one. Also exports BOTH_BLOCKED as a shared constant instead of matching a respelled literal across two modules. TESTS: test_both_blocked_routing_698.py 6 passed -- the sgl-project#505 discipline: the pin fails if the caller stops routing, if the relief stops calling eviction, if it stops reporting a zero delivery, or if the rate limit is removed. managers + mem_cache 64 failed / 1928 passed, the same 64 baseline.
efschu
added a commit
to efschu/htsglang
that referenced
this pull request
Aug 17, 2026
…nothing closed it Desk analysis of the 3x FLIP ABANDONED on 0b61699, plus the guard that makes the real state legible. 1. THE 1748-vs-1693 ARITHMETIC, reconstructed. phase_flip_runtime.py:4993-5019: usable = from_driver = max(0, driver_free - reserve) spendable = usable # allocator cache is NOT counted So "spendable" is driver-free minus the kept-free reserve, measured AFTER _reclaim_cached_blocks() has returned what it can; whatever the caching allocator still holds is deliberately excluded. The 1748 requirement comes from _staging_bytes, which is incoming + max(outgoing, local) over the WIDEST WAVE, using the same row_nbytes the move itself uses -- derived from the plan, not estimated, and waved so it scales with pool geometry rather than prompt length. I find no overcount on that side. 2. THE RUNG LINE IS ARITHMETICALLY IMPOSSIBLE, and that is the root. _floor_rows is max_live + 1 + margin_rows + admission_reserve_rows. margin_rows DEFAULTS TO 0 and is never passed at the construction site (kv_backing_relief.py:2158-2167), and admission_reserve_rows is chunked_prefill_size = 512. So floor = max_live + 513, and floor=398471 means max_live = 397,958 -- against a current cap of 137,216. A live row id 2.9x ABOVE the cap. Compare the healthy shape this module documents itself (line 875): "max_live=644 + admission reserve 512, slack=405894". There the high-water id is tiny. Here it outlived the pool it was measured in: ids from a larger id space surviving a reshard/shrink. Because slack is max(0, current - floor_rows), it pins to 0 for as long as that holds, so the rung can NEVER propose a shrink. The evict-rung funding path (sgl-project#688) is therefore permanently unavailable at this operating point, and every flip falls back on the raw seam fund alone. That is why the instance abandoned three times over 55 MiB instead of funding it from KV once -- the backstop was gone, not merely small. So: the floor FORMULA is right and its INPUT is impossible. The defect is upstream of this file, in whatever leaves live ids above the cap. 3. WHAT LANDS HERE. Only the guard: a floor above the cap now says FLOOR UNREACHABLE, names the gap in rows, and states the implication (this rung can never fund; max_live is above the cap). "slack=0" alone is indistinguishable from a rung that merely had no room this round, which is exactly the confusion this ticket started in. The healthy path is untouched and a floor exactly AT the cap is reported as tight, not impossible. I did NOT change the floor, the eviction handoff, or the live-set derivation. Re-basing live ids after a shrink/reshard is the actual fix and it sits in the area F4-r4 holds for sgl-project#715, so per the coordination rule it goes back through the operator rather than being edited here. Tests: 5, red first -- two new assertions failed, three controls (healthy shape, boundary at floor == cap, never-ran) passed before the change and still do. managers + mem_cache: 2892 passed, 0 failed. ruff clean.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 17, 2026
…ead them the same
_resident_ceiling returns -1 for two OPPOSITE states, and its own docstring
says so: "Highest row a RESIDENT REQUEST pins, or -1 when none/unknown."
build_flip_live_slots_fn sets req_max to -1 when it has no request parts, so an
IDLE box is encoded exactly like an UNREADABLE split.
The two demand opposite behaviour:
* unreadable -> evict NOTHING. Unmapping a row a live request is reading
is the one unrecoverable error, so the conservative branch is right here.
* none resident -> the entire live set is tree-only and MAXIMALLY evictable.
_evict_floor_rows took the conservative branch for both, which means it refused
to price an eviction precisely when it had the most to win. On the specimen:
BOTH BLOCKED ... 0 req resident
KV rung: current=137216 rows, floor=398471, slack=0
397,958 max_live against a 137,216 cap -- 2.9x over -- so slack pins to 0, the
sgl-project#688 evict-rung funding path is structurally dead, and every flip falls back on
the raw seam budget. That is why three FLIP ABANDONED events turned on a mere
55 MiB shortfall.
ROOT DIFFERS FROM THE FILED HYPOTHESIS, and the distinction matters for the
neighbouring tasks: the ids are NOT stale pre-shrink survivors needing a
rebase. 397,958 is a perfectly valid id in the ~437k id space; the pool simply
has only 137,216 rows BACKED. The floor is max(live id) + reserve, a SPARSE
high-water mark, so ~137k live rows scattered across the id space demand
398,471 rows of backing. Nothing is un-rebased; the mark is just the wrong
statistic when the live set is sparse. A rebase would not have fixed this.
The two states are separable from data already recorded -- the live-set split
carries req_rows beside req_max -- so no new enumeration is needed.
Tests, hermetic (CUDA_VISIBLE_DEVICES=""):
test_the_specimen_shape_reproduces ......... the plain floor IS 398471, and
it exceeds the 137216 cap, so slack pins to 0
test_nothing_resident_prices_the_eviction .. the fix: floor collapses under
the cap and an eviction is priced
test_unreadable_split_still_refuses ........ CAN-FAIL: the conservative
branch must survive for its real case. A fix that treated -1 as "evict
everything" passes the fix test and fails this one -- and that mistake
unmaps live rows.
test_resident_rows_present_is_unchanged, test_nothing_resident_predicate_is_exact
-> 5 passed + 3 subtests; 76 passed + 5 subtests across 717 + flip-runtime +
715 suites. ruff clean in the changed region.
CAN-FAIL PROVEN BY MUTATION: restoring the conflation fails 1 of 5 (the fix
test), reverted and re-verified 5 passed.
Desk only -- not yet observed on metal. The live proof is a flip funded by the
evict rung on an idle box, which the next boot can show.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 17, 2026
…e rules outrank it Wiring for 59592d6, plus both review findings, plus three precedences the EXISTING TESTS taught me -- which is the substance of this commit. FINDING 1, THE TP MIRROR. The tp branch pulled unconditionally on pend>0, so after an EXHAUSTED release the next TP evaluation would pull straight back and decode would lose the layout before serving anything: the C2 defect with the phases swapped, degenerating under both-sides load to max_hold PP rounds, ~0 TP rounds and TWO seams per cycle -- strictly worse than the timer it replaced. The pull now yields to a RUNNING decode batch for MIN_DECODE_ROUNDS (2: the minimum that means "did not preempt mid-batch"), bounded so it cannot become a new starvation of the prefill side. The degenerate cycle is pinned by test, not by hope: release at the bound, then assert the pull does NOT come straight back. FINDING 2, THE COUNTER LIFECYCLE. hold_rounds_so_far was caller-maintained. next_hold_rounds() is now a pure function resetting on EITHER boundary -- phase change or pending reaching 0 -- and the defect it prevents is pinned directly: a stale counter of 8 carried across a phase change releases the very first hold of the next episode, i.e. the C2 fix evaporates for the arrival that needed it. FINDING 3, THE REASONS REACH THE LOG. The gate returns its verdict as the decision's reason, so it travels the same path BOTH BLOCKED already does -- that is how the boot's acceptance gets read. THE THREE PRECEDENCES, each taught by a test I broke: * sgl-project#688 idle-locked outranks it, exactly as it outranks sgl-project#689 formation: holding a layout that can build NOTHING is waiting inside a layout that cannot serve. * The DRAINED exit outranks it on sgl-project#669's economics: a residual ABOVE one chunk stays (which this hold wants anyway), but a SUB-CHUNK residual is finishing regardless and holding for it spends a ~2.6 s seam to save a fraction of a chunk. sgl-project#669 moved anti-pinning to the starvation cap precisely so the drain could exit. * The DECODE STARVATION CAP outranks it absolutely. That SLO is the system's guarantee that PP can never pin the server; this lever's round bound is only a secondary backstop. Vetoing the cap would put a local timer above a global guarantee and reintroduce the pinning it prevents. AND THE GATE IS PP_TO_TP ONLY, as sgl-project#689's is. My first wiring vetoed EVERY arm, including the idle return leg -- 11 tests red -- because the rules arm for reasons this lever cannot see. It may only convert the one arm that contradicts it. Recorded because three exemptions is a shape: if a fourth appears, invert to an allowlist rather than adding it. Tests: 22 passed + 17 subtests in the lever file; 221 passed + 24 subtests across phase-policy, idle-locked-arm, window-formation, admission-intake, 708 and flip-runtime. ruff clean.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 17, 2026
…-pong A layout may be declared unable to run only after it has HAD THE CHANCE to run. An emptiness observed within idle_locked_settle_s of entering a layout is a transient, not a verdict. THE CLAIM THAT FAILED The IDLE_LOCKED branch sits above the min-dwell check and bypasses the only anti-thrash bound, justified by a comment stating "IT CANNOT OSCILLATE ... after the flip the target runs by premise, so the same condition is false there". It oscillated. Across the 16 boot rotations of 2026-08-17 the policy produced alternating runs of 72 arms / 299 s, 12 / 31 s and 10 / 27 s twice. The premise fails on WHEN it is evaluated, not on what it says. This branch is reached on the first round after a cutover, while the just-entered layout is still empty and its carried work not yet re-admitted -- Scheduler._idle_locked_inputs is gated on _round_built_nothing, which a just-entered layout satisfies trivially. The new layout is observed in its empty transient, certified unable to run, and armed straight back. That is also where sgl-project#713's TTFT quantisation came from. The unit of delay is one whole cutover (median 2864 ms tp_to_pp, 2772 ms pp_to_tp over 486 flips), so the 0.1 / 3.1 / 5.9 s levels in the sgl-project#713 tables are how many cutovers a request sat through. The 06:19 table was taken during a 27 s run. THE VALUE IS DERIVED, NOT CHOSEN Delay from "cutover complete" to the first batch the new layout builds, over 162 cutovers: 0 s for 66 of 150, 1 s for 34, 2 s for 27, 3 s for 12, thin tail to 6 s, one outlier at 30 s. 2.0 s covers 84.7 %. The p95 (4 s) is deliberately NOT used: it exceeds the 3 s min_dwell_s this rig boots with, and a settle above the dwell would make the fast escape slower than the path it exists to bypass. Log stamps are second-resolution, so this is a bound, not an optimum, and the docstring says so. FAILURE DIRECTION, AND WHAT BOUNDS IT A genuine idle lock forming within the settle of a cutover is now delayed, by at most the settle. Bounded three ways: the value is capped at min_dwell_s at the use site, so an operator cannot configure the fast escape into being the slow one; the 180 s decode-stall cap remains the backstop that released the 09:42:39 specimen; and the settle is consulted only right after a cutover, which is the only place the transient exists. sgl-project#688's escape is preserved and pinned. phase_since, not last_flip_at: the first is when THIS layout was entered and is maintained from the OBSERVED phase, so a manual POST /phase_flip restarts it too; the second is an arm stamp that is 0 until the policy has armed once. None degrades to pre-guard behaviour rather than to an infinite settle. RED-FIRST, AGAINST THE RECORDING test_idle_locked_settle_713.py replays the recorded arms through the real policy off scripts/fixtures/d2_injector_pingpong_excerpt.txt, reusing the injector's parser so harness and suite cannot disagree about what the log says. settle disabled -> 12 of 12 arms armed, the ping-pong reproduced settle enabled -> 1 of 12 armed Not zero, and that is the point: the arm that legitimately leaves a 35 s-settled idle-locked layout survives, and only the eleven arm-backs on 0-1 s-old layouts are refused. The first version of this replay asserted all twelve were transients; the data refused, one arm being 35 s past its cutover. That arm was not noise, it was the control case, and it is now the selectivity pin. Mutation-proven: disabling the guard at source turns 3 tests red. REGRESSIONS Baselined before and after by capturing the failure set with the guard reverted. 8 failures pre-exist on this branch in this area and are untouched; the guard adds none and 705 pass. The five sgl-project#677-era pins stay green because they construct PhasePolicyState() with no phase_since -- which is also why they never caught this, and their docstring now says so instead of restating the falsified invariant. sgl-project#712 TEXT REMOVED The BOTH-BLOCKED decline used to redirect to "the state-slot bound (mamba/GDN slots)". That was never measured: it was a hypothesis authored into a log string, read back out of the log and filed as a finding, and sgl-project#712 was closed as unfounded on that evidence. The line now reports only what it knows. test_both_blocked_binding_resource_708 REQUIRED that wording, so the pin is inverted rather than relaxed -- an unmeasured cause must not be named.
efschu
pushed a commit
to efschu/htsglang
that referenced
this pull request
Aug 17, 2026
Fix for the root filed in ANALYSE_741. On 2026-08-17 19:30:40 the KV backing rung evicted 127,731 rows that the phase flip was about to pack, and the next access above the new cap was an illegal memory access 24 log lines later. It killed that day's serving. WHY BOTH HALVES WERE BLIND AT ONCE, which is what shapes the fix. _nothing_resident() asks the live split for req_rows, and _shrink_to's safety net re-measures through _max_live_row() -- which calls the SAME _live_slots_fn. A flip quiesces its requests before packing them, and a quiesced request sits in none of the batch structures _live_reqs enumerates, so that one enumeration reported zero to both. Fixing only the predicate would have left the net equally blind to any other caller that shrinks during a park, so both are fed from ONE side channel. LINE 1 -- the parked extent is visible to predicate AND net. _nothing_resident() consults _flip_pending() first; _max_live_row() folds the parked max row id in, which is the half a predicate-only fix would have missed. (-1, -1) means UNKNOWN and blocks in both -- never reads as empty. LINE 2 -- the rung refuses outright while a flip is armed, on the pricing and the collecting site both, because the failure is a SILENT eviction followed by a DELAYED fault and one mechanism is not enough. Gated on ARMED ONLY: outside a flip the rung stays fully live, which sgl-project#688's evict-rung funding path depends on. WIRED, not merely defined. Both channels are passed at the production factory against scheduler.phase_flip_runtime, and an AST pin asserts the factory actually passes them -- parsed rather than grepped, because the module's own prose names both kwargs while explaining them. A fix wired into nothing is the defect class this repo keeps finding; it is not shipping as one here. TEST RESULTS (repo rule: documented before commit) New suite test_evict_rung_flip_park_744.py: 15 tests + 2 subtests, all green. Can-fail proofs cut BOTH ways on purpose -- removing the extent visibility must let the eviction happen again, and the gate must NOT make the rung dead outside flips. Mutation matrix, 6 mutants, ALL KILLED (run against the new suite plus both sgl-project#717 suites): M1 predicate ignores parked extent -> 3 failed M2 net ignores parked extent -> 1 failed M3 gate removed from pricing site -> 1 failed M4 gate removed from collecting site -> 2 failed M5 gate ALWAYS on (rung dead outside flips) -> 3 failed <- the sgl-project#688 guard M6 unknown extent treated as empty -> 1 failed M5 is the one that matters most: it proves the gate is not permitted to disable the rung outside a flip. Pinned suites green: test_evict_rung_nothing_resident_717, test_evict_rung_floor_invariant_717, test_kv_backing_cap_agreement_656, test_kv_backing_recovery_clamp_684, test_kv_backing_exhaustion_662_f4 -- 88 passed with the new suite. Full managers regression, compared PER SUITE against HEAD in a scratch worktree (per the truncated-baseline lesson -- a total can hide a swap): baseline HEAD : 29 failed, 4 errors, 2522 passed with sgl-project#744 : 28 failed, 4 errors, 2540 passed NEW failures : ZERO The single baseline failure absent from my run (test_phase_flip_mover_streaming_631 :: test_the_waved_price_is_short_of_the_ measured_live_set) is NOT claimed as a fix: it passes 3/3 in isolation on BOTH trees, so it is order-dependent in the full run and unrelated to this change. Ruff and codespell clean. Two things stated plainly rather than dressed up. The fix was built BEFORE the falsifier, contrary to red-first; the mutation matrix is the equivalent evidence and the ordering was mine. And the sgl-project#717 suites caught a real error at once -- they invoke the rung's methods UNBOUND against stubs, my first version used direct attribute access, and all four went red; fixed by matching the file's existing getattr(self, ..., None) idiom. KNOWN LIMITATION, filed as its own follow-up: _flip_pending() returns the last enumeration that saw requests, consulted only while armed. That makes line 1 CONSERVATIVE rather than exact -- a flip that arms before any enumeration has seen requests answers UNKNOWN and blocks. Safe, but the exact arm-time snapshot is not shipped here. No boot. Boot proof goes on F4-r4's window list.
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.
Motivation
cc @merrymercy @Ying1123 @hnyls2002
fix
on Lambda GPU
Modification
as titled
Checklist
pre-commit run --all-filesor other linting tools are used to fix potential lint issues.