# KVC-Router：面向 Agentic 多轮 LLM Serving 的 Session-Aware 调度算法

**性质**：论文级形式化规范——用于团队内部对齐 + 外部读者 onboarding。
**对象**：项目团队（统一术语）；论文 reviewer（算法定义）。
**最近更新**：2026-05-11。

本文给出本项目所开发的 **KVCache-Centric Router**（以下简称 "KVC-Router"）调度算法的形式化、与实现无关的定义。本文设计为可直接被论文引用，并作为"KVC 到底在谈论什么调度算法"的标准回答。

对应的参考实现位于：
- `src/agentic_pd_hybrid/policies.py` — `KvAwarePolicy`、`RoutingState`
- `src/agentic_pd_hybrid/replay.py` — orchestration：admission RPC、reset-on-success、fallback chain
- `third_party/sglang/python/sglang/srt/managers/scheduler.py` — D-worker 端的 admission 决策

---

## 1. 问题定义

我们要服务一群多轮 agentic LLM session（如 Claude Code、Codex、Cursor 等 coding agent），底层是异构 worker 池，分成：
- **Prefill workers**（`P`）：GPU 常驻的模型副本，针对长输入 prompt 的 batched prefill 做了优化。
- **Decode workers**（`D`）：GPU 常驻的模型副本，配备 session-aware KV cache（"SessionAwareCache"），具备：(i) 跨 turn 保留 session 的 KV 状态；(ii) 在本地已缓存的 prefix 上做 append-prefill，无需绕回 `P`。

在一个 agent turn 内，请求 `r` 到达时其对话 prefix 已经从前序 turn 累积；**新增**的 tokens（工具输出、用户消息等）构成小规模 **append**。驱动 KVC 设计的根本观察是：

> 当 prefix KV **已经驻留在将要解码该请求的 D worker 上**，请求的 first-token 延迟仅由 *append* 大小决定（典型 O(10²–10³) tokens），而非完整 prompt 大小（典型 O(10⁴–10⁵) tokens）。

Router 的工作就是最大化满足上述条件的请求占比，同时尊重容量约束、不造成 session 无限饿死。

### 1.1 优化目标

给定来自 `S` 个 session 的请求流 `R = (r_1, r_2, ...)`，最小化 SLO 加权的 TTFT 与端到端延迟混合：

```
   minimize   E[ w_ttft · TTFT(r) + w_lat · E2E_Latency(r) ]
   subject to  capacity[d] ≤ K_d   对任意 D worker d 在任意时刻 t,
               没有 session 被永久拒绝服务.
```

参考实现中通过 measurement 隐式取 `w_ttft = 1, w_lat = 1`；per-D KV 池预算 `K_d` 取 SGLang 启动时上报的 `max_total_num_tokens`。

---

## 2. 系统模型与记号

### 2.1 集合

| 符号 | 含义 |
|---|---|
| `P = {p₁, …, p_|P|}` | Prefill worker 池 |
| `D = {d₁, …, d_|D|}` | Decode worker 池 |
| `S` | Session 标识符集合（由上游 agent runtime 分配） |
| `H` | KV block hash 的全集（本实现中每 `BLOCK_TOKEN_BUDGET = 24` tokens 对应一个 hash） |

### 2.2 请求

一个请求 `r` 是一个元组：

```
   r = ⟨ s(r),  t(r),  prefix_hashes(r),  append_len(r),  input_len(r) ⟩
```

其中：
- `s(r) ∈ S` — session id
- `t(r) ∈ ℕ` — 该 session 内的 turn index（0 = 首轮）
- `prefix_hashes(r) ⊂ H` — 覆盖请求输入 prefix 的 block hash 集合
- `append_len(r) ∈ ℕ` — 新到达、**不在** `prefix_hashes(r)` 中的 token 数
- `input_len(r) = (|prefix_hashes(r)| · 24) + append_len(r)` — 总 token 数

### 2.3 Router 状态 (`Σ`)

Router 跨请求维护的全局状态：

| 字段 | 类型 | 语义 |
|---|---|---|
| `resident[d]` | `set[H]` | Router 估计的 D `d` 当前 SessionAwareCache 中常驻的 block hash 集合（router 端估计，真值在 worker 上） |
| `pin[s]` | `D ∪ {⊥}` | Session `s` 最近一次成功服务的 D；`⊥` 表示从未见过 |
| `inflight[d]` | `ℕ` | 当前已派发给 `d` 但尚未完成的请求数 |
| `assigned[d]` | `ℕ` | 累计派发到 `d` 的路由决策次数（负载 tie-breaker） |
| `rejects[s,d]` | `ℕ` | per-(session, D) 的 admission 拒绝计数（v2 引入的 migration 机制） |

### 2.4 超参数

| 符号 | 默认值 | 描述 |
|---|---|---|
| `α`（`sticky_bonus`） | 1 | 匹配 `pin[s]` 的 D 在评分中获得的 bonus |
| `τ_reject`（`migration_reject_threshold`） | 3 | (s, d) 被拒绝达此次数后，d 对 s 进入 blacklist |
| `τ_append`（`kvcache_direct_max_uncached_tokens`） | 8192（v2） | 走 Direct-to-D 路径允许的最大 append 长度 |
| `K_d` | 取自 SGLang `max_total_num_tokens` | per-D 的 KV 池预算 |
| `ρ` | 0.95 | 容量高水位线（隐式由 SGLang 强制） |
| `ε`（最大 fallback 重试数） | `|D| - 1` | router 在退化到 vanilla PD-disagg 之前最多探测几个 D |

### 2.5 路由结果

路由决策 `δ(r)` 取以下四种之一：

| Mode | 含义 | KV transfer |
|---|---|---|
| `Direct(d)` | r 完全在 D `d` 上执行；D 在其常驻 KV 上做 append | **无**（快路径） |
| `Seed(d)` | Session 首轮：P 做完整 prefill，KV 通过 mooncake 传到 `d` | 完整 input |
| `Reseed(d)` | Session 之前在某个 D' 上，但已不再常驻；按 Seed 处理 | 完整 input |
| `Fallback(p, d)` | Vanilla pd-disagg 路径（其它 D 均被 blacklist 或拒绝） | 完整 input |

---

## 3. 算法

KVC-Router 由三个相互配合的过程组成：
- **Algorithm 1 (`Route`)**：router 端基于评分的候选选择。
- **Algorithm 2 (`Admit`)**：D-worker 端的 admission 决策（在 D scheduler 中执行，非 router）。
- **Algorithm 3 (`Dispatch`)**：端到端 orchestration，把 Route + Admit + reset-on-success 串起来。

### 3.1 Algorithm 1：`Route(r, Σ)` — 基于评分的候选选择

```
输入：请求 r，状态 Σ
输出：候选 d* ∈ D（若所有 D 都被过滤后仍无候选，退化分支兜底返回最少被拒的 D）

 1.  blacklisted ← { d ∈ D : Σ.rejects[s(r), d] ≥ τ_reject }
 2.  C ← D ∖ blacklisted                                  // 候选 D 集合
 3.  if C = ∅ :                                           // 退化
 4.       return argmin_{d ∈ D} Σ.rejects[s(r), d]        // 选最少被拒的 D
 5.  for each d ∈ C :
 6.       overlap(d)  ← |prefix_hashes(r) ∩ Σ.resident[d]|
 7.       sticky(d)   ← 1 if Σ.pin[s(r)] = d else 0
 8.       infl(d)     ← Σ.inflight[d]
 9.       assn(d)     ← Σ.assigned[d]
10.       score(d)    ← ⟨ overlap(d) + α·sticky(d),       // 主项
                          sticky(d),                       // tie-1
                          −infl(d),                        // tie-2（负载小者占优）
                          −assn(d) ⟩                       // tie-3
11.  return argmax_{d ∈ C} score(d)                       // 按字典序最大
```

**说明**：
- 评分是 **4 元组按字典序比较**，不是单个标量——这样避免在不同维度之间调权重。
- 第 10 行的主项 `overlap + α·sticky` 同时奖励 KV 复用与 session stickiness。取 `α=1`、`overlap` 以 block（24 tokens）为单位时，**任何一次 hash 命中都压制纯 sticky 的候选**。
- 第 1–4 行的 blacklist 过滤防止永久绑死在已饱和的 D 上；与 Algorithm 3 的 reset-on-success 配合，限定了 migration 频率。

### 3.2 Algorithm 2：`Admit(d, r, M, K)` — D-worker admission 决策

在 D worker 自己的 scheduler 内部执行（非 router），这是 **KVC 的机制核心**：每个 D 自治判断能否把 `r` 当作 Direct（append-only）服务，还是必须改走 P 路径。

```
输入：D worker d，请求 r，d 上本地常驻的 session 集合 M_d，KV 池预算 K_d
输出：⟨can_admit ∈ {True, False},  mode ∈ {Direct, Seed, Reseed, ⊥},  reason⟩

 1.  used_tokens ← Σ_{s' ∈ M_d} resident_tokens(s', d)     // D 自己的 bookkeeping
 2.  cap_ok ← (used_tokens + input_len(r)) ≤ ρ · K_d        // 高水位线 ρ ≈ 0.95

 3.  if s(r) ∈ M_d :                                        // session 在 d 上有常驻
 4.       if append_len(r) ≤ τ_append  and  cap_ok :
 5.           return ⟨True, Direct, ∅⟩                      // → 快路径
 6.       elif append_len(r) > τ_append :
 7.           return ⟨False, ⊥, "real-large-append"⟩
 8.       else :
 9.           return ⟨False, ⊥, "no-d-capacity"⟩

10.  else :                                                 // session 在 d 上无常驻
11.       if cap_ok :
12.           mode ← Seed if t(r) = 0 else Reseed
13.           return ⟨True, mode, ∅⟩                        // → 经 P 做 KV seeding
14.       else :
15.           return ⟨False, ⊥, "session-not-resident-no-capacity"⟩
```

**说明**：
- 该过程通过同步 HTTP RPC（`/admit_direct_append`）从 router 调用。RPC 阻塞直到 D scheduler 给出权威答复——这是 v5 引入的 **"worker-mode admission"**，替换了更早的 router-端容量估算（系统性偏乐观）。
- reason 字符串被回传给 router，用于：(i) 在 Algorithm 3 中驱动 fallback chain；(ii) 标注 `execution_mode` 字段便于分析。

### 3.3 Algorithm 3：`Dispatch(r, Σ)` — 端到端 orchestration

```
输入：请求 r，状态 Σ
输出：执行模式 μ ∈ {Direct, Seed, Reseed, Fallback}

 1.  retries ← 0
 2.  tried ← ∅
 3.  while retries < ε :
 4.       d* ← Route(r, Σ \ {对 tried 中的 d 已 bump 过的 rejects})
 5.       if d* = ⊥ : break                                  // 无候选
 6.       resp ← Admit(d*, r)                                // RPC 到 D scheduler
 7.       if resp.can_admit :
 8.           Σ.rejects[s(r), d*]  ← 0                       // ◀ reset-on-success（v2）
 9.           Σ.pin[s(r)]          ← d*
10.           Σ.inflight[d*]       ← Σ.inflight[d*] + 1
11.           if resp.mode = Direct :
12.                在 d* 上完整执行 r（append-prefill + decode）
13.                return Direct
14.           else :                                          // Seed 或 Reseed
15.                p ← round_robin_next(Σ, P)
16.                在 p 上做 r 的 prefill
17.                经 mooncake 把 KV(r) 从 p 传到 d*
18.                在 d* 上 decode r
19.                return resp.mode
20.       else :
21.           Σ.rejects[s(r), d*]  ← Σ.rejects[s(r), d*] + 1
22.           tried ← tried ∪ {d*}
23.           retries ← retries + 1
24.
25.  // ε 次重试耗尽——退化 Fallback 到 vanilla pd-disagg
26.  p ← round_robin_next(Σ, P)
27.  d ← round_robin_next(Σ, D)
28.  通过 ⟨p, d⟩ 走 pd-disagg(r)
29.  return Fallback
```

**维持的关键不变量**：

1. **不会静默过载**：一个 D 永不接受会让 `used_tokens > ρ · K_d` 的请求（Algorithm 2 第 2 行）。
2. **不存在永久饿死**：对任意 session `s`，只要曾在某 D `d*` 上成功过一次，之后 `Σ.rejects[s, d*] = 0`（Algorithm 3 第 8 行）。因此 blacklist 计数器不会对仍在某处成功获得服务的 session 累积——这阻止了 **v1 的 thrashing 病理**：原本 blacklist 计数器单调增长 + 退化 fallback 形成自放大的 round-robin 死循环。
3. **migration 有界**：一个 session 从 D `a` 迁移到 D `b` 必须经过连续 `τ_reject` 次在 `a` 上失败、期间无任何成功。每个 session 生命周期内的最坏 migration 次数 ≤ `(|D| − 1) · τ_reject`。

### 3.4 Reset-on-success：为什么这是关键修复（v1 → v2 演化）

v1 实现**省略了** Algorithm 3 第 8 行——一旦 `(s, d)` 累积 `τ_reject` 次拒绝，d 对该 session **整个 run 永久 blacklist**。实测（Migration v1，见 `docs/MIGRATION_V1_FINDINGS_ZH.md`）触发了自放大的失效模式：

```
session s 在 d 上稳定服务 70 个 turn
       ↓ 瞬时 burst 让 d 短暂饱和
3 次到 d 的 admission 被拒 → rejects[s,d] = 3 → d 对 s 永久 blacklist
       ↓ s 迁到 d'，d' 也在负载中 → 被拒 → blacklist
       ↓ d'' 同理
所有 D 都 blacklist → 退化 fallback round-robin → 每次重试都 bump 一次计数器
                   → s 永远在 D 之间 thrashing，每次都丢失 KV residency
```

reset-on-success 关上了这个回路：只要 `s` 在任一 d 上真正完成一次 Direct，针对该 session 的 blacklist 立刻清零。该机制只对**持续性**（不是瞬时性）容量压力触发。

---

## 4. 性质

### 4.1 Theorem 1（在有界 ε 下无永久饿死）

*假设 `τ_reject ≥ 1` 且每个 D worker 的容量非零。则对任意能在 admission 时容下的 session `s`，Algorithm 3 在至多 `|D| · τ_reject` 次重试内返回 `{Direct, Seed, Reseed}` 之一；之后任意一次 Direct 成功即可清空 `s` 的所有 blacklist。*

**证明概要**：每次循环要么成功（return）、要么恰好让某个 `rejects[s, d]` 计数器 +1（第 21 行）。经过 `|D| · τ_reject` 次迭代后，每个 D 要么对 `s` 已被 blacklist（`Route` 第 1 行会过滤），要么已成功（已终止）。在所有 D 都被 blacklist 的饱和点，`Route` 第 3 行返回最少被拒的 D，打破对称性，强制取得进展。∎

### 4.2 Theorem 2（fast-path 命中下限）

*假设 session `s` 在 D `d` 上已积累 KV residency `R_s ⊂ H`，且在某 turn `t > 0` 提交的请求 `r` 满足 `prefix_hashes(r) ⊆ R_s`、`append_len(r) ≤ τ_append` 且 admission 容量充足。则 Algorithm 3 将 `r` 路由为 Direct(d)。*

**证明概要**：由 Algorithm 1，`overlap(d) = |R_s|` 取得最大值；结合 `α·sticky(d) ≥ 1`，d 的字典序得分严格高于任何 `prefix_hashes(r) ⊈ R_{s,d'}` 的 d'。故 `Route` 返回 d。`Admit(d, r)` 进入 `s ∈ M_d ∧ append ≤ τ_append ∧ cap_ok` 分支，返回 Direct。∎

这是 **支持架构设计的机制级保证**：只要 residency、append 大小、容量三者同时成立，快路径就被**确定性地**选中；KVC 在典型场景下的 TTFT 优势是结构性属性，不是概率性。

### 4.3 复杂度

每个请求：
- `Route`：`O(|D|)`（每个候选 D 算一次 score）。生产规模下 `|D| ≤ 8`，主要开销在 Python 层，≪ 1 ms。
- `Admit`：D scheduler 内部 O(1)（查自己的 bookkeeping，无全局锁）。
- Router 层的单请求总开销：`O(|D|)` 计算 + 1 次到目标 D 的 HTTP RTT（loopback 亚毫秒，跨机数据中心约 1 ms）。

---

## 5. 与 baseline 的对比

| 性质 | Vanilla pd-disagg | DP（cache-aware） | **KVC-Router**（本文） |
|---|---|---|---|
| P/D 分离 | 是（`|P| + |D|` GPU） | 否（每个 worker fused P+D） | 是 |
| 跨 turn cache locality | 无（每个请求都 P→D 传 KV） | 仅在单 fused worker 内部走 hash prefix 路由 | session 钉在某 D 上，本地 append-prefill |
| 同 session cache 集中度 | 无 | 散到 `|D|` 个 worker（每个占 1/|D|） | 集中在一个 D（整段常驻） |
| 最坏 turn-2 prefill 工作量 | 完整 input 经 P→mooncake→D | 在目标 worker 上做完整 prefill（带 prefix cache 命中） | 本地 `append_len ≤ τ_append` tokens |
| 容量感知 admission | 无（router 盲发） | 隐式靠 worker 队列深度 | 显式的 per-D `Admit()` 决策 |
| Migration 机制 | N/A | N/A | 带 reset-on-success 的 reject-counter blacklist |
| Idle prefill 成本 | 是——P 永远在算 | 否 | 是——P 只在 cache miss 时启用（本工作 SWE-Bench 评测下约 8% 请求） |

KVC 的关键架构权衡：**用 P 端 GPU 闲置换 D 端 TTFT 稳定性**。在 per-session cache 复用率高的 agentic workload 上（Inferact 的 Codex trace 报告 94.2% cache hit；我们的 SWE-Bench replay 实测 91.6% Direct 命中），这个交换显著有利。在 session 短或 cache hit 低的 workload 上，权衡反转、DP 胜出。

---

## 6. 符号速查表

| 符号 | 含义 |
|---|---|
| `P, D` | Prefill / Decode worker 池 |
| `s(r), t(r)` | 请求 r 的 session id 与 turn index |
| `prefix_hashes(r)` | r 输入 prefix 的 KV block hash |
| `append_len(r)` | r 中新增（未缓存）部分的 token 数 |
| `Σ.resident[d]` | Router 对 d 缓存 block 集合的估计 |
| `Σ.pin[s]` | session s 最近一次成功的 D |
| `Σ.rejects[s,d]` | per-(s,d) 的 admission 拒绝计数 |
| `α` | sticky bonus 权重（默认 1） |
| `τ_reject` | migration 阈值（默认 3） |
| `τ_append` | Direct 路径允许的 max append 大小（v2 默认 8192） |
| `K_d` | D worker d 的 KV 池预算 |
| `ρ` | 容量高水位（默认 0.95） |
| `ε` | fallback 重试上限（默认 `|D| − 1`） |
| `δ(r)` | 路由决策：`Direct(d)` / `Seed(d)` / `Reseed(d)` / `Fallback(p, d)` |

---

## 7. 本工作评测中实际使用的默认参数

| 参数 | 取值 | 说明 |
|---|---|---|
| `|P|, |D|` | 1, 3（1P3D 配置） | 单机 4× H100 80GB |
| `α` | 1 | |
| `τ_reject` | 3 | |
| `τ_append` | 8192 | v2 调优后取值（v0/v1 用 2048） |
| `K_d` | 92104 tokens | SGLang 按 `mem_fraction_static=0.835` 自动算出 |
| `ρ` | 隐式 ~0.95 | 由 SGLang 的 `max_total_num_tokens` 强制 |
| `ε` | 2 | `|D| − 1 = 2` |
| 每次 run 的 session 数 | 52 | SWE-Bench 50sess trace |
| 总请求数 | 4449 | |
| Time-scale | 1.0（真实 trace 时序） | |
| 并发 | 32 | |

---

## 8. Anti-patterns（KVC **不**是什么）

1. **KVC 不仅仅是 kv-aware routing**。DP 和 KVC 都可以跑 `kv-aware` policy；KVC 在此之上加了三件事：(i) session 钉定，(ii) worker 端 admission，(iii) 带 reset-on-success 的 migration。如果在比较 "KVC vs DP" 时缺这三个要素的任何一个，**测的就不是 KVC 与 DP 的差异**。

2. **KVC 在 policy 项里不直接感知容量**。`Route` 不查 per-D 容量；容量感知完全经由 `Admit` 拒绝来传导。我们刻意做了这层分层——把容量判断放进 `Route` 会引入"换 D"的决策空间，导致 orphan KV 滞留问题。

3. **KVC 不保证 load balance**。一个 session 若能舒服地装在某个 D 上，可能永远钉在那里，而其它 D 大部分时间空闲。在低容量压力下这是设计意图；高压力下 Theorem 1 的 migration 会触发再均衡。

4. **`Fallback` 不是"降级路径"**。它和 vanilla pd-disagg 请求结构性等价，延迟特征相同。KVC 的价值在于让 Fallback 占比在典型 agentic workload 下 ≪ 10%。

---

## 9. 公开问题（reviewer 关注点）

以下问题在当前评测中尚未解决，主动列出以保持透明：

1. **Session 钉定相对于纯 P/D disaggregation 的边际贡献是多少？** 需要 `naive 1P3D` 对照实验（vanilla SGLang xPyD，不带 KVC 层）——仓库当前缺失（见 `docs/V2_DEEP_ANALYSIS_ZH.md §4.7`）。

2. **Algorithm 3 在更高压下行为如何**（例如 ts=10 加速、session 数 ≫ |D|·K_d/peak_input）？当前 ts=1 评测对应真实 agentic 区间，但算法在更高负载下的鲁棒性未经实验验证。

3. **真 RDMA 下的 reseed 代价**：本次评测的 3–7 s reseed 延迟由两段组成——P 端 re-prefill（1.5-3s）+ P→D mooncake transfer（1.5-4s）。当前 sweep 用的是 TCP loopback；启用 IB/RoCE（节点有 mlx5_0/_1 @ 200 Gb/s × 2 active，需在 sweep 加 `--force-rdma --ib-device mlx5_0`）只能压缩 transfer 段到 ~200ms，**不动 re-prefill 段**。预期 TTFT p99 从 1.28s 降到 ~0.7s（仍输 DP 0.43s）。待独立验证。

4. **D→P 增量 KV 同步（核心 future-work 缺口）**：reseed 长尾的真正消除需要让 P 端 backup 跟上 D 的 direct-to-D append 增长。经独立 forensic 审查，**当前代码、vendored SGLang、mooncake 三层均无 D→P KV transfer 实现**：mooncake `MooncakeKVManager` 是 PREFILL=sender / DECODE=receiver 的硬角色分支（`add_transfer_request` 上有 `assert disaggregation_mode == PREFILL` 硬约束），`BaseKVSender` / `BaseKVReceiver` 抽象无 bidirectional slot，`session_aware_cache.release_session` 在驱逐时只调 `kv_pool_allocator.free()` 无出站，`_commit_prefill_backup_residency` 唯一 caller 是 seed/reseed 路径；`capacity-backup` policy 的真实语义只是"reseed 完不关 P streaming session"——backup 是 seed-time 的静态快照，不随 direct-to-D append 同步。要实现 D→P 增量同步，工程量 ~1-2 周，最难的不是 mooncake 加 D-sender / P-receiver 角色（~400 LOC），而是 **SGLang radix tree 改成允许从外部 worker 喂数据**——radix cache 当前假设单一生产者（本 worker model 输出）。这是论文里最值得做的 contribution 之一。

5. **v2 代码路径下的确定性**：v0 代码库的 ts=1 N=3 categorical 确定性已经证实；新增的 reset-on-success 分支与 threshold=8192 路径未被独立 re-validate。两个额外的 N=1 run 即可解决。

---

## 10. 论文引用建议

论文中提到本算法时建议表述：

> "We use the KVC-Router scheduling algorithm (Algorithms 1–3 of [our paper], formally defined in our supplementary materials). The router selects a decode worker by lexicographic scoring on `(overlap+α·sticky, sticky, −inflight, −assigned)` (Algorithm 1), defers the admission decision to the chosen worker via a synchronous RPC (Algorithm 2), and maintains a per-(session, decode worker) rejection counter that is reset on every successful Direct admission (Algorithm 3). This last detail — reset-on-success — is what distinguishes our v2 from the unstable v1 implementation that exhibits self-amplifying session thrashing."

---

**附录 A — 算法步骤到代码实现的对照**

| 算法步骤 | 文件 | 符号 |
|---|---|---|
| `Route` 第 5–11 行 | `policies.py:189–202` | `KvAwarePolicy.select` 内层循环 |
| `Route` 第 1–4 行（blacklist 过滤 + 退化分支） | `policies.py:182–187, 204–211` | `migration_reject_threshold`，`select` 的 fallback |
| `Admit` | `third_party/sglang/python/sglang/srt/managers/scheduler.py` | `handle_admit_direct_append_request` |
| `Dispatch` 第 8 行（reset-on-success） | `replay.py: _run_request` | finish 路径中的 reset |
| `Dispatch` 第 21 行（记录 reject） | `replay.py: _run_request` | `state.record_admission_reject(...)` |
| 超参数 `τ_append` | CLI flag | `--kvcache-direct-max-uncached-tokens` |
| 超参数 `τ_reject` | CLI flag | `--kvcache-migration-reject-threshold` |
