31 files had Windows line endings (\r\n) from merge commit. This causes
patch_ops.sh replace_once() to fail: anchor strings use \n but file
content has \r\n, so no match → patch fails → docker build fails.
Also added .gitattributes to force LF for all text files going forward.
flash_attn_varlen OOMs at 4096 tokens, Q-tiling also OOMs (K tensor too large).
During profiling (BI100_IN_STARTUP_PROFILE=1), return zeros immediately.
Profiling only measures memory footprint, not output correctness.
Restore: chunked_prefill=on, max_num_batched_tokens=4096.
flash_attn_varlen_func allocates O(n²) temp memory for 4096 dummy tokens
during profile_run, causing OOM at gpu_memory_utilization=0.80.
BI100_IN_STARTUP_PROFILE=1 env var is already set by
patch_worker_startup_profile_guard.py during the synthetic forward pass.
Real inference requests still use flash_attn_varlen (much faster).
Verified on real BI-V100:
flash_attn_func works with head_dim=256 (diff < 0.004, no NaN)
flash_attn_varlen_func works for variable-length batching
seq=1024: 1.7x faster than PyTorch matmul
The profiling-stage _run_sdpa_fallback now tries flash_attn_varlen_func
first, falls back to Python Q-tiling only on exception.
This addresses the 10-50x attention slowdown identified in the analysis:
Python Q-tiling: O(L^2) per-tile matmul in Python loop
flash_attn: fused kernel, O(L) memory, hardware-optimized
CCCL segmented_sort.cu AST chain → traced back to base engine zip →
discovered base patch_ops.sh deploys 10+ files we were missing.
Missing patches that caused real failures:
1. paged_attn.py — Triton context_attention_fwd HANGS BI-V100 GPUs permanently.
Base engine replaces it with _forward_prefix_pytorch pure-PyTorch fallback.
WITHOUT THIS: GPU hang on any prefix-cached request → timeout → 0 score.
2. patch_xformers_sdpa_seq.py — head_dim=256 > cudnnFlashAttn 128 limit.
Qwen3.5 uses head_dim=256. Without this bypass, attention crashes.
3. sequence.py — completion_tokens inflation under chunked prefill.
Bug: get_output_token_ids_to_return(delta=True) with num_new_tokens=0
returns the ENTIRE prompt. 10K prompt × 3 chunks = 30K false tokens.
4. scheduler.py — num_cached_tokens tracking for prefix caching.
5. mamba_cache.py — GatedDeltaNet state management.
6. patch_model_runner.py — prefix_cache_hit stays True in chunked-prefill
chunk 2+, causing undersized block_tables and crash.
Also: conditional qwen3_5.py deployment (CCCL JIT pattern) — if Docker
image already has a working qwen3_5.py (with corex integration), don't
overwrite it. Only deploy ours if the image version is missing.