Skip to content

docs: add set up runner - #829

Merged
zhyncs merged 1 commit into
sgl-project:mainfrom
zhyncs:new
Jul 30, 2024
Merged

zhyncs merged 1 commit into
sgl-project:mainfrom
zhyncs:new

Conversation

@zhyncs

@zhyncs zhyncs commented Jul 30, 2024

Copy link
Copy Markdown
Contributor

Thank you for your contribution, we really appreciate it. The following instructions will help improve your pull request and make it easier to receive feedback. If there are any items you don't understand, don't worry. Just submit the pull request and ask the maintainers for help.

Motivation

Please explain the motivation behind this PR and the goal you aim to achieve with it.

Modification

Briefly describe the changes made in this PR.

Checklist

  1. Ensure pre-commit pre-commit run --all-files or other linting tools are used to fix potential lint issues.
  2. Confirm that modifications are covered by complete unit tests. If not, please add more unit tests for correctness.
  3. Modify documentation as needed, such as docstrings or example tutorials.

@zhyncs
zhyncs merged commit 62c673c into sgl-project:main Jul 30, 2024
@zhyncs
zhyncs deleted the new branch July 30, 2024 09:43
timethink pushed a commit to timethink/sglang that referenced this pull request Mar 9, 2025
JinyanYi pushed a commit to JinyanYi/sglang that referenced this pull request Jun 23, 2026
efschu pushed a commit to efschu/htsglang that referenced this pull request Aug 23, 2026
Wave 3, stage 5 -- the LAST stage of the batched-window tree. WINDOW-QUEUE
ticket W7 (strand 21a, preflight_pass=Y: 7 passed with 4 red-first, 3/3
mutants killed, and the 17 pre-existing sgl-project#630 tests unchanged).

One commit, base 2efb933:

  3f16e8e  [sgl-project#829] The HiCache deadline must not close a pair healthy peers
              are using

THE DEFECT. `bounded_wait` enforced its deadline by passing a timeout INTO the
gloo work itself -- `work.wait(timeout=)`, introduced by sgl-project#630 -- and on a
shared gloo pair that does not merely abandon one wait, it POISONS the pair
for every peer still using it. The production string
"Application timeout caused pair closure" was reproduced red-first in a real
two-process gloo run and reads PAIR_SURVIVED on the fix. The deadline now
lives in `ParkedWait.join`, off the work: the wait is abandoned by the CALLER
while the underlying `Work` stays parked, so nothing is torn out from under a
healthy peer.

NO CROSS-SURFACE, computed rather than hoped. The only file this shares with
the rest of wave 3 is mem_cache/hicache_collective.py, and the +119 that stage
3 put there comes from commit 2efb933 -- which is precisely W7's own base.
So W7 already contains that change and there is nothing to reconcile; its
other two files are new and under mem_cache, disjoint from W5/W4b's files.

sgl-project#734's DISCRIMINATOR IS PRESERVED, and this was checked rather than assumed
because it is the exact thing strand 17c's 622 falsification turned on: the
`waited < timeout_s * 0.95` branch that distinguishes a dead peer from a slow
one is still in `bounded_wait` after this change. W7 moves WHERE the deadline
is enforced; it does not move the threshold.

That also makes this gate non-vacuous in the way that matters here.
`test_pp_sync_rendezvous_630.py` -- the suite that went red under the 622 merge
for precisely this threshold, and the reason 622 is still off the line -- sits
INSIDE the battery and is green on this stage.

KNOWN FOLLOW-UP, NOT CARRIED HERE. Strand 21c has since measured that the
0.95 comparison is REDUNDANT under this very ParkedWait design -- a real
expiry takes the not-completed path 4 out of 4 times, and any RuntimeError
reaching that `except` already means transport death -- while the comparison
leaves a BLIND BAND over the last 5% of the bound, where a peer death is
labelled a timeout (30 s at the 600 s default). An amendment is being built
(delete the comparison, make the except an unconditional transport error, and
guard at construction that the process-group timeout exceeds the bound).

That amendment is NOT in this tree. It did not exist when this stage's battery
started, and per standing instruction the window tree does not wait for it --
it lands in the next round as its own stage. This paragraph exists so the next
reader does not re-derive the finding or mistake the preserved comparison
above for a settled decision: it is preserved here because THIS commit does not
touch it, not because it is known to be right.

A related thread for whoever owns the 622 posten, explicitly UNMEASURED and
not a claim of this merge: 17c established that 622 reddens sgl-project#630 by SHIFTING
gloo timing until the 0.95 branch flips, and left open why the timing shifts.
This change removes `work.wait(timeout=)`, one mechanism by which a wait on a
shared pair can perturb its peers. Whether that is upstream of what 622
perturbs is unmeasured here and is not asserted.

GATE. Battery test/registered/unit/{managers,planner,server_args,mem_cache},
hermetic under CUDA_VISIBLE_DEVICES="", one battery at a time, against a ZERO
baseline since stage 3b.

    baseline (tip 4f2072a)   7 failed, 8585 passed, 1852 skipped, 887 s
    stage 1 (W1+W2)             7 failed, 8638 passed, 1852 skipped, 868 s
    stage 2 (W3)                7 failed, 8653 passed, 1852 skipped, 922 s
    stage 3 (W4a/W5/W4b)        7 failed, 8673 passed, 1852 skipped, 915 s
    stage 3b (sgl-project#791 stub)        0 failed, 8684 passed, 1852 skipped, 900 s
    stage 4 (W6)                0 failed, 8703 passed, 1852 skipped, 931 s
    this stage                  0 failed, 8710 passed, 1852 skipped, 912 s
    NEW failure ids             NONE

The +7 is this stage's own suite, matching its ticket exactly. The skipped
count is 1852 in all seven runs of this train, so nothing went green by being
skipped.

The sgl-project#630 check above was verified rather than inferred from the overall zero:
test_pp_sync_rendezvous_630.py sits under test/registered/unit/mem_cache, i.e.
inside the battery, and run standalone on this stage it is 3 passed --
including test_a_dead_peer_still_raises_a_named_bounded_error, the exact case
that reddened under the 622 merge.

Its new suite, test_bounded_wait_pair_survives_829.py, lands under
test/registered/unit/mem_cache and is therefore inside the battery and
actually collected.

WINDOW SCOPE, so the window reader does not expect what cannot appear: W7's
effect is only OBSERVABLE with PP>1 and a storage-backed HiCache. On a boot
without both, a green W7 criterion would be vacuous rather than passing.

No boot. This completes the tree; W9 is a separate stage after the push.
efschu pushed a commit to efschu/htsglang that referenced this pull request Aug 24, 2026
…s on

sgl-project#829's root -- an arm slot outliving the ring it names -- is already closed on
integ/round5 by d507e19, and test_pp_arm_slot_outlives_ring_829.py pins the
behaviour with 9 green tests. This adds no runtime code and changes no source
line. It pins the PREMISES that make the closure a proof rather than an
observation.

THE ROOT, restated with file:line so the pins have a referent:

  :2606  rising edge records self._pp_flip_arm_mb_id = mb_id
  :2616  and self._pp_flip_arm_epoch alongside it
         cutover commits with _pp_flip_armed_passes == 0
  :3905  init_pp_loop_state REBUILDS mbs/last_mbs/running_mbs from zero, and
         pp_loop_size may CHANGE (TP phase runs pp_size=1), so a carried index
         can be out of range
  :2776  the falling edge jumps the pass loop to the recorded slot

Pre-sgl-project#829 that put PP0 on slot 2 of a fresh ring while its downstream sat on 0
(boot_window2_0823_1554, epoch 6, "RESUME SLOTS [2, 1, 1] -- DIVERGED"), and
PP1 raised sgl-project#631 PROXY LEFTOVER REFUSED one second later.

TWO GUARDS CLOSE IT, and they are COMPLEMENTARY rather than redundant:

  A  :3903  init_pp_loop_state calls pp_flip_forget_ring_scoped_slots(self)
            unconditionally, retiring all three ring-scoped carriers.
  B  :2755  the falling edge refuses a restore across a generation
            (ring_rebuilt = arm_epoch != now_epoch); the only jump is the
            elif arm at :2776.

init_pp_loop_state has THREE callers and only the cutover advances the epoch,
so guard B is blind to the other two rebuilds and guard A covers them. Neither
may be dropped.

WHAT WAS MISSING. The proof rests on three uniqueness facts that no test
pinned: the ring is rebuilt in exactly one place, the arm slot is recorded in
exactly one place, and the pass loop can be jumped from exactly one place. A
second rebuild site or a second jump writer would bypass both guards WITHOUT
failing any existing test, silently restoring the state that killed the boot.

Verified by exhaustive enumeration over python/sglang/: one rebuild site
(:3905-3910), one arm writer (:2606), one jump site (:2776).

test_pp_ring_rebuild_choke_point_829.py -- 5 AST-level uniqueness pins, ~2 s,
CPU only, no torch and no process group. A failure there is not automatically a
bug; it is a demand that a newly added site be checked against the epoch gate,
and the failure messages say so and name the offending function and line.

Deliberately NOT pinned: the order of the clear against the array assignments.
Both orders are correct and pinning one would make a harmless refactor red.

DANGER DIRECTION. Nothing here enforces uniformity and no runtime code was
added, so a healthy ring cannot be stalled by it. The existing danger tests
still pass: an abandon in the same epoch still restores the arm slot, and
sgl-project#757's leftover drain still runs on a committed falling edge.

Tests: 14 passed (9 existing + 5 new).
Mutants: mutants_829_chokepoint.sh, 4 written, 4 KILLED, tree restored green --
second rebuild site, rebuild stops clearing, second resume-slot writer, arm slot
recorded without its epoch.
test/registered/unit/managers/ collects 3670 tests cleanly.
ruff check clean, ruff format clean, codespell clean.

Merge compatibility: two new test files, zero source lines, so this cannot
conflict with the round-6 source merge. If round-6 adds a ring-rebuild or jump
site the pins go red by design, naming the site.

sgl-project#829 remains open only on METAL VERIFICATION, which is a window question.
efschu pushed a commit to efschu/htsglang that referenced this pull request Aug 26, 2026
…, so 411 declines have no verdict

Routing from the write-side agent (sgl-project#872) narrowed Posten 0 correctly: the store
is healthy, 24277 canonical pages live during the R7 window, and the historic
"store is empty" readings probed a path this boot does not use. So the 671
refused walks are a MATCH problem, not a content problem. The question that
follows immediately is the one nobody could answer: a walk that matches nothing
should fall through to an L3 prefetch, and prefetch was attempted on only 264
of 675 sampled walks.

THE OBVIOUS ANSWER IS WRONG, and the code says why. It is tempting to read the
411 as the same MambaComponent refusal declining twice -- one root, two numbers.
It is not:

  * The prefetch anchor IS mamba-gated, but by an aliasing the base contract
    does not describe. base_prefix_cache.py:201-210 separates `last_host_node`
    (the L3 prefetch anchor) from `best_match_node` (the validator-consensus L2
    anchor) -- two fields, two purposes. UnifiedRadixCache sets them equal under
    HiCache (unified_radix_cache.py:1443-1449). Deliberate and commented, but it
    contradicts the field's own documentation, and two fields that are
    documented different and implemented identical are a drift source (sgl-project#747's
    shape). Named, not changed here.
  * Even so, the refusal does NOT decline the prefetch. Total refusal leaves
    best_match_node at the root, and the caller admits the root on purpose:
    `locally_eligible = last_host_node.backuped or last_host_node is
    self.tree_cache.root_node` (scheduler.py:4933-4935). A cold request with no
    match is supposed to prefetch. The first term holds.
  * The second term (>= 256 new tokens) holds for agent prompts of thousands.

That leaves the rate limiter -- AND THERE THE EVIDENCE STOPS, which is the
actual finding. None of the three terms is counted or logged. The 411 declines
are silent. Nobody can attribute them from this boot, and no amount of
re-reading the log will change that.

    eligible = (locally_eligible
                and prefetch_length >= self.prefetch_threshold
                and not self.cache_controller.prefetch_rate_limited())

Three unrelated verdicts wearing one boolean, remedies in three different
files. The sgl-project#914 shape one module over: blame without a defect.

So this is an instrument and NOT a policy change. The three terms are the same
three, evaluated in the same order, with the same outcome; `eligible` is now
`reason is None`, one expression, so the predicate and its explanation cannot
drift apart the way sgl-project#747 records these very lineages drifting. The first
failing term is named rather than all of them -- a request can trip several,
and summing them would double-count exactly as
`refused_tokens_by_component` is documented to.

Not env-gated, unlike the sgl-project#904 match census. That one builds an object and
walks validators a second time, so it pays for itself only when armed. This is
one integer increment on a path that already builds a RadixKey and takes a host
lock -- and a counter you must remember to arm cannot answer "was it ever
tried", which is the whole question. `attempted` is counted alongside the
refusals so the denominator is local (sgl-project#873: a denominator reconstructed from
another log is how a narrowed candidate set reads as a decomposition), and an
unrecorded gate says "no observation" rather than a silent zero (sgl-project#829).

HYPOTHESIS, RECORDED AS ONE. prefetch_capacity_limit is `0.5 *
mem_pool_host.size` (cache_controller.py:729), and that size is not constant
across a phase flip: sgl-project#905 measured the two host tiers at 703472 rows (PP) and
30518 (TP), 23x apart, putting the TP-phase budget near 15259 tokens -- under
four prefetches of the 4096 this window actually completed, against 5
concurrent requests per flip. The order of magnitude fits 411/675, and I am
deliberately not fitting it exactly: the PP phase has ample budget, so the
number cannot come from there alone. If it holds, the same host-tier asymmetry
behind sgl-project#905's double-free is also starving the TP-phase prefetch budget -- one
defect, two effects, to be checked rather than assumed. The counter decides it
on the next boot instead of re-arguing it.

RED-FIRST, four mutants, each red, restored green (14 tests):
  revert to the shipped conjunction (no counter) ......... 4 failed
  eligible computed twice instead of derived from reason . 2 failed
  attempts not counted (denominator lost) ................ 2 failed
  no-observation reported as attempted=0 ................. 1 failed

ONE SELF-INFLICTED DEFECT, found and fixed in the same pass, recorded because
the form is evidently easy to commit. My first version of
test_the_rate_limit_check_is_still_called_at_most_once counted occurrences in
the function's RAW source and went red because a PRE-EXISTING comment at :2674
mentions `prefetch_rate_limited()`. That is the sgl-project#908 substring defect -- prose
used to reach a verdict about code -- in a test of mine, an hour after I
rejected the same form in someone else's patch. Comment lines are now stripped
before counting.

GATE test/registered/unit/mem_cache serial, CVD="": 3 failed, 1950 passed,
1658 skipped. Both axes agree (summary 3, ANSI-stripped extraction 3). Two are
test_acceptance_emitters_758::RefillTiming, baseline-proven pre-existing
earlier in this branch; the third is test_pool_invariant_double_owned_912, a
concurrently-developed test belonging to sgl-project#912 and untouched by this commit.
The sgl-project#904 census suite is green against this change (62 passed together with
the sgl-project#913/sgl-project#914/sgl-project#915 suites), which is the regression that matters: note_refused
gained an optional third argument and its existing callers must not care.
efschu pushed a commit to efschu/htsglang that referenced this pull request Aug 27, 2026
… every arm

One of four boots in the 0827 window died in a CPU spin whose hot frame was
the at-arm census. `arm()` called `_pool_census("at-arm", ...)`
unconditionally (sgl-project#631 J), which walks the pool and, through
`_census_ownership_audit`, the KV row-ownership map. That was affordable when
an arm was rare. It is not: the same window measured 69 cutovers in five
minutes, so a full-pool walk per arm is an O(pool) tax per flip on the
scheduler thread.

A CADENCE GATE, NOT A DELETION. The census is the only instrument that can see
the sgl-project#631 J page loss, so what changes is how OFTEN it runs, never whether it
CAN. Two independent admissions, either of which opens the gate:

  * the first arm after SGLANG_PP_ARM_CENSUS_MIN_INTERVAL_S of wall clock
    (default 30s) -- so a slow-arming instance censuses every arm exactly as
    before and is not throttled at all;
  * every Nth arm (SGLANG_PP_ARM_CENSUS_EVERY_N, default 16) -- so a
    fast-arming instance still gets a bounded sample rather than nothing.

Setting BOTH to 0 restores the unconditional pre-sgl-project#926 behaviour, which is the
escape hatch an operator needs when chasing exactly the page loss this
watches for.

NEVER SILENTLY FALSE (sgl-project#829/INDIKATOR-GESETZ): a skipped arm is counted, and
the count rides the next census that does run -- "N arm(s) since the last one
were NOT censused ... a SAMPLE, not a continuous record". Without that line a
sampled window reads exactly like a clean one, which is the failure this gate
would otherwise introduce while fixing the spin.

Tests, hermetic, CUDA_VISIBLE_DEVICES="": test_arm_census_cadence_926.py,
6 passed. Pins both halves -- 69 arms produce 4 censuses, the Nth arm is the
one that fires, the time budget alone admits every arm of a slow cadence, both
admissions off restores the unconditional census, and a skipped arm is counted
and reset onto the census that reports it.

sgl-project#801 IS NOT IN THIS COMMIT, and the reason is a measured negative rather than
a missing step. The task's fix shape -- a void-send backstop on the
intermediate hop, gated like the last rank's #791b contract -- was built and
driven through the three-process gloo ring
(test_pp_output_ring_retraction_wedge_791b's harness, hazard moved to the last
rank so the missing send lands on an intermediate hop). THE RED ARM DID NOT
WEDGE: with the new relay neutered in the child, all three ranks still ran all
12 passes (voids=1, requeued=1 on PP0 and PP1). The existing sgl-project#801 republish
already carries that case, so the backstop was dead code.

It also cannot close the hole `_pp_send_output_to_next_stage` names, and the
reason is structural: that hole is "this rank received NOTHING because its OWN
slot was empty while the successor's was not", and PP0 derives the published
expectation FROM ITS OWN SLOT (`expects_output = _pp_output_exchange_due(
h.mbs[mb_id])`). An empty slot therefore publishes False, so ANY backstop
gated on `_pp_output_expected_for_slot` is inert in precisely the state that
wedges. Closing it needs the successor-to-predecessor expectation wire the
comment already calls "a wire against the ring direction and a separate
posting". Reverted rather than shipped unproven, so this branch stays a clean
boot candidate.
efschu pushed a commit to efschu/htsglang that referenced this pull request Aug 28, 2026
…he silent hop

Boot 2 of window-flip-0828 wedged silently for 10+ minutes: PP0 and PP1
blocked in gloo waitSend under _pp_commit_comm_work's naked
p2p_work.work.wait() (PP1 via _pp_commit_pending_req_work), PP2 in
_do_recv -- a closed three-arc cycle on a group whose own timeout is two
hours. The sgl-project#753 comment in this file already described the exact shape
(boot v7pp9); the ordering was fixed then, the wait stayed naked.

The bound routes through the sgl-project#630/sgl-project#829 canon
(hicache_collective.bounded_wait -> ParkedWait): the unbounded wait()
parks on a thread and the deadline is on the JOIN. Deliberate deviation
from the order's 'pass the deadline into work.wait(timeout)': sgl-project#829
retracted that design in this tree -- an expired timed Work.wait closes
the gloo pair, and hicache_collective.py names _pp_commit_comm_work as a
measured victim (34 of 262 boot logs). Budget 120 s
(SGLANG_PP_RING_COMMIT_BUDGET_S; <= 0 = documented escape hatch,
byte-for-byte pre-sgl-project#973), reasoned against the canon's constants: 12.6x
the longest healthy cutover, 4x the sgl-project#789 budget, 5x under the HiCache
bound, 60x under the group timeout. On expiry: RingCommitTimeout with a
sgl-project#650-style peer statement naming the silent hop; transport failure is
NOT converted (sgl-project#734 stays distinguishable). Helpers are module-level,
not methods -- the method form broke ~12 one-method-at-a-time stand-in
holders (measured: 796 5->2, 801 14->3), recorded in a code comment.

Wait-site audit: :5253 bounded-now; :3270 bounded by delegation (proven
by test); _do_recv/:7592 and :5545 bounded-already via the sgl-project#789 gate;
parallel_state.py recv_object stays unbounded and is NAMED as its own
posten (needs the resumable PpChainReceiver treatment, not a terminal
bound mid-protocol).

Tests: test_ring_commit_bounded_973.py, 5 arms on real 3-process gloo --
pre-sgl-project#973 naked commit HANGS (distinguished from raised via fsynced
progress marker), bounded commit raises within budget with the peer
statement, healthy paired traffic unchanged, escape-hatch mutant hangs
again (can-fail), :3270 reachability arm. Gates: BEFORE == AFTER
byte-identical on 796(5)/801(14)/797(31)/630(5+14)/829(7) plus an
18-module sibling sweep; extraction count probe OK on every run.
ruff/codespell: 0 new findings.
efschu pushed a commit to efschu/htsglang that referenced this pull request Aug 28, 2026
…e mutants because the module is new

sgl-project#980 shipped 1202 lines across seven files with no tests, including a new
482-line module (distributed/pp_object_recv.py). A red-first against the
previous commit is the weak proof already reported twice in this window --
every arm would die on ImportError, equally red against a module whose
functions are all 'pass'. So each invariant is paired with a mutant that
breaks that invariant and nothing else, and the arm must go red for it.

What is asserted is NOT 'does it time out'. The module's own law is that once
the size header is received the payload is on the wire and must be taken off
it, because a receiver that gives up mid-frame and later re-posts reads a
payload AS a size and every later message on that stream is garbage. An
abandoning bound is therefore worse than no bound: the unbounded wait hangs
one rank, the abandoning one silently corrupts the stream. Every arm counts
irecv posts -- exactly one size and one payload per object, however many
steps expire and however many times the caller is handed a stall and returns.

Covered: resumption across expired steps in both halves; a stall that raises
AND leaves the frame resumable, with the same receive then completing; a
transport error propagating as itself rather than as ObjectRecvStalled (sgl-project#734,
so a dead peer stays distinguishable from a slow one); abort_after_s <= 0
restoring the exact pre-sgl-project#980 unbounded wait so the default path gains only a
log line.

MY OWN FIRST STRUCTURAL ARM WAS A FALSE POSITIVE, recorded in place rather
than quietly rewritten. It asserted 'wait(timeout' not in the module source
and went red on the module's DOCSTRING, which explains at length why it does
not do that -- so the better the hazard was documented, the more surely the
arm failed. Replaced by an AST walk for a real .wait(...) call carrying a
timeout keyword, plus a can-fail proving that detector sees a genuine one.
The prohibition matters because no runtime arm can observe it: a timed
Work.wait closes the gloo pair (sgl-project#829) and would pass hermetically while
killing a real boot on both sides.

Test: 11 defs / 11 passed at 4ea93b8 (count probe), 1.84s, hermetic --
dist.irecv and ParkedWait stubbed in the module namespace, no gloo, no CUDA.
efschu pushed a commit to efschu/htsglang that referenced this pull request Sep 3, 2026
…the stashed-frame budget is keyed to the frame and counts arrivals at its own slot

Both reviewer BLOCKERS fixed at their root, not at the symptom.

BLOCKER A -- the launched-pass set survived the ring rebuild.
`_pp_launched_pending` is ring-scoped bookkeeping (slot numbers of the
ring that launched them), but `pp_flip_forget_ring_scoped_slots` -- the
function whose own sgl-project#829 docstring claims to own exactly that class --
did not clear it. A retraction rebuilds the ring, `arm()`'s quiescence
precondition then reads a slot from the DEAD ring and defers for ever:
the TP-sticky shape the reviewer named. Fix is one statement in the
designated authority, and it CLEARS rather than intersects with
`range(pp_loop_size)` -- the ring is rebuilt EMPTY two statements after
the call, so an in-range survivor would be exactly as wrong as an
out-of-range one.

BLOCKER B -- the stashed-frame budget could stop the group falsely.
The counter was neither keyed to a frame nor to an armed window, and
counted loop VISITS. Three corrections, each with its own test:

  (a) keyed to (arm epoch, frame stamp) -- back-to-back frames each get
      their own budget instead of summing into a false STOP, and a
      disarm cannot leave a count for the next window. Every early
      return of `_pp_flip_hold_slot` now forgets the window through
      `_1173_forget_stashed_frame`; in the TP phase the bound is 4, so a
      single inherited visit changes the verdict.

  (b) a visit counts only when the loop ARRIVES AT THE SLOT THE FRAME
      NAMES. That is what the STOP claims -- "the receive kept getting
      the chance and still did not take it" -- and it is the only form
      that is reachable on the TP ring: `pp_loop_size` is 1 there,
      `mb_id` is 0 on every iteration and never CHANGES, so an
      mb_id-change detector would have been structurally unfireable
      exactly where the bound is smallest. Own mutant M6 proves it.

  (c) unreadable live slot or unreadable frame slot => the budget does
      not advance at all. An instrument that cannot measure the chance
      it counts must never fire a group stop.

Arm side: the deferral was unbounded and its warning unrated. It is now
bounded on FORWARD PROGRESS -- a frozen (outstanding slots, fwd_ct) for
longer than `launched_pass_stall_s` (default 120 s) escalates to the
same named STOP, ring progress restarts the clock. Bounding on deferral
COUNT was rejected: `arm()` is driven from the receive poll, so a count
bound fires at a rate set by client traffic. The ARM DEFERRED warning is
rate-limited like the sibling sgl-project#1020 guard (<=3 or every 512) and carries
`deferrals=` and `streak=` so a suppressed gap stays readable.

Non-blocking items taken: N4 (the reported `queue=` term is the same
reading the verdict used, not a re-derivation), N5 (the sgl-project#731 argument
restated for all three in-flight pairs at the loop), N8
(`pending_prefill_terms` declared rank-DIVERGENT by construction --
weg1b4 measured 5739 on PP0 vs 3827 on PP1 -- reporting only, no
cross-rank ballot), N9 (the in-flight billing test now uses a request
whose `extend_range.end` is below its total, so removing the resident
dedup guard actually changes the number).

EVIDENCE
  red-first, reviewed HEAD c32eac6 (test file copied into a scratch
    worktree): 16 failed / 8 passed of 24. 13 are blocker-targeted; 3
    are collateral (the file now passes `launched_pass_stall_s` to the
    runtime constructor, which does not exist there) -- named, not
    hidden.
  fixed tree: 24 passed.
  mutants, all against the fixed tree, all DEAD:
    M1 launched-set clear removed              -> 2 failed
    M2 count every visit, not arrivals         -> 1 failed
    M3 frame identity dropped from the key     -> 1 failed
    M4 arm-side escalation neutralised         -> 1 failed
    M5 early returns no longer forget          -> 1 failed
    M6 mb_id-change detector instead of arrival-> 2 failed
    M7 stall clock never restarts on progress  -> 1 failed
    M3 and M5 SURVIVED a first round and drove two of the corrections
    above -- recorded, not quietly re-run.
  sibling test_pp_flip_slot_hold_631.py: 8 failed / 11 passed on both
    the reviewed HEAD and the fixed tree (its stand-in now binds
    `_1173_forget_stashed_frame`; without that it was 15 failed).
  ruff check parity over python/sglang/srt/managers/ +
    test/registered/unit/managers/: 466 == 466 errors on both trees
    (all pre-existing); ruff format: the three production files were
    already dirty on the parent, both new test additions are formatted.
  matched check (D1) re-run on the fixed tree: the three tests of
    TestTheDrainedPremiseCountsLaunchedWork pass -- an empty
    waiting_queue with chunked remainder 1912 and a launched slot reads
    pending == 1912, not 0. Its mutant M-D1 (drop the in-flight
    remainder term at scheduler.py `pending += inflight_tokens`) turns
    exactly those assertions red: 2 failed / 22 passed. Tree restored
    and re-verified byte-identical afterwards.
  bounded suite, test/registered/unit/managers, -n 8, one run each:
    parent scratch c32eac6: 263 failed / 4678 passed / 18 skipped /
      12 errors / 565 subtests passed (568.75 s)
    fixed tree:                248 failed / 4693 passed / 18 skipped /
      12 errors / 565 subtests passed (573.82 s)
    comm of the sorted FAILED/ERROR node-id sets: 16 names cured (all
    of them the red-first test_arm_quiescence_1173.py cases -- the
    count matches the red-first tally exactly), and ONE name appears
    only on the fixed side:
      test_pp_proxy_readiness_contract_789.py::PPProxyReadinessContract789
        ::test_shipped_gate_raises_named_diagnostic_instead_of_wedging
    That is NOT a regression and was verified, not assumed: run solo,
    that test PASSES on the fixed tree while a DIFFERENT member of the
    same file fails -- and the parent scratch produces the identical
    solo result (1 failed / 3 passed, same member). The failing member
    of that module wanders between runs; this diff touches neither the
    module nor its production file. Known sgl-project#899/sgl-project#895 PP-proxy family
    (NOT_CROWDING_PROVABLE).

DEVIATIONS
  N2 is implemented here, not deferred as the earlier report said.
  N3 (drain-and-flip queue axis) stays open by design; N6 (D2b is a
  rank-local refinement of a rank-local predicate) and N7 (two
  authorities for one notion: `_inflight_ids` slot occupancy vs
  `_pp_launched_pending` launch bookkeeping) stand as named residue.
  N11: the earlier report's red-first arithmetic was wrong and is
  re-measured above. N12: the follower-side raise is rank-local by
  construction and its message now says what it counted.
  No boot. Desk only.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant