$ rolloutkit explain SP005
SP005 — inflight-completion
Measures: Measures a steady-state request baseline, launches contracts.inflight.concurrent requests,
waits until their sockets are confirmed connected, sends SIGTERM while they are still unfinished, 
then classifies every accepted request as completed, reset before response, reset mid-response, or 
timed out. The denominator is what was still open at T0, which is normally smaller than the 
configured concurrency. Completion must be 100 percent.
Preconditions:
  - contracts.inflight must not be explicitly null; null is an intentional opt-out and therefore 
SKIP rather than a measurement failure.
  - When readiness is the zero-config fallback target it has to clear two independent clauses, and 
both must hold. Its p50 must be at least 10x the probe-path jitter, so the before/after-SIGTERM 
boundary is distinguishable from noise, and it must be at least 3ms in absolute terms whatever the 
ratio says. An explicit --inflight-path bypasses both.
  - Neither clause is the junior one, and which of the two actually refuses a given service depends 
on the machine the run happened on. Measured over eight runs of one fixture on each of two hosts. On
an idle macOS laptop the probe path is quiet, so the ratio comes close to clearing — it reached 4.09
against the cutoff of 10 — and what refuses is the absolute floor: readiness p50 never rose above 
0.79ms, 3.8x under the 3ms it needs. On a two-core Linux CI runner the jitter is three times larger,
so the ratio refuses with room to spare at 2.41 and below, 4.2x under its cutoff, while the same 
fixture's readiness p50 climbs to 1.19ms, within 2.5x of the floor. Remove either clause and one of 
those two hosts loses the clause that was holding it. The ratio is evaluated first, so when both 
refuse the reported cause names the ratio; that is an ordering, not a ranking.
  - Resolution on the fallback path is a property of the host, not only of the service. The jitter 
floor it divides by was measured 3.4x apart across three conditions — 0.154ms median on an idle 
macOS laptop against 0.516ms on a native Linux CI daemon — and the same image at 1ms and 2ms of 
readiness delay therefore resolved on the laptop and was refused on the runner, with nothing about 
the service differing. A result that resolves on one machine can be INCONCLUSIVE on another. Pass 
--inflight-path with a slower representative endpoint for a result that does not depend on where it 
ran. If SP005 reports readiness_fallback_below_resolution, that is the tool declining to guess, not 
a defect in the service; the precondition evidence carries a cause saying which clause refused.
  - Shutdown must visibly start, otherwise the request outcomes cannot be attributed to a shutdown 
transition at all — this is the precondition that stops a process which ignores SIGTERM from 
reporting a clean sweep.
  - The pre-signal baseline must be all 2xx, otherwise shutdown would be blamed for failures that 
were already present in steady state.
Verdicts (branch):
  PASS         all_completed
    Every request that was in flight when SIGTERM arrived received a complete response.             
  FAIL         requests_destroyed
    At least one in-flight request was reset, truncated, or timed out. broken_requests names each   
    one with its offset from T0.                                                                    
  ERROR        nothing_in_flight
    SIGTERM was sent while no request was actually open. The window was empty, so a clean result    
    would have meant nothing; the run reports the empty window instead of a sweep.                  
  SKIP         disabled
    contracts.inflight was explicitly set to null. Under --fail-on this still blocks, because SP005 
    is a required contract.                                                                         
  INCONCLUSIVE readiness_fallback_below_resolution
    No in-flight path was configured and readiness is too fast to hold a request open across the    
    signal — either relative to the probe-path jitter or in absolute terms. Pass --inflight-path    
    with a slower representative endpoint. The precondition evidence names which of the two refused.
  INCONCLUSIVE shutdown_never_started
    The process showed no reaction to SIGTERM, so the measured window contained no shutdown. Request
    counts stay in the evidence; the verdict does not.                                              
  INCONCLUSIVE baseline_not_2xx
    The steady-state baseline was not all 2xx, so the request path was already broken before the    
    signal was sent.                                                                                
Why it matters: These are the requests a caller is currently waiting on. Losing them is a 
user-visible error on every single rollout, and it is invisible to any check that reads the exit 
code: a process can call os._exit(0), report a clean exit, and destroy every open response on its 
way out.
Drain strategies:
  - prestop: the hook only prevents new routing before T0. Requests already accepted must still 
complete, so the contract is unchanged.
  - in_app: the application owns both halves — stopping new work and finishing what it accepted 
before T0.
  - none: completion is measured exactly the same way; there is simply no separate protection for 
new connections.
First step after FAIL: Read broken_requests and the window evidence before changing anything: the 
offsets say whether requests died at the listener close or at the process exit. A worker pool that 
finishes only the request in hand and abandons its queue is the common cause, and worker count — not
graceful-timeout — is what governs it.
