# PR #33173 完整报告

- 仓库：`sgl-project/sglang`
- 标题：docs: rewrite the runtime-context skill for the namespace-bag config model
- 合并时间：2026-08-02 00:00
- 原文链接：http://prhub.com.cn/sgl-project/sglang/pull/33173

---

# 执行摘要

- 一句话：重写 runtime-context 技能文档，适配 namespace-bag 配置模型
- 推荐动作：值得精读。这份 PR 是理解 SGLang 新配置架构（RuntimeContext + namespace bags）最直接的入口，尤其适合配置系统维护者和经常被 agent 改动波及的模块 owner。重点看三处：tier 表中 raw config seed 与 resolved config 的职责切分、"Reads that legitimately stay on a ServerArgs instance" 章节（per-runner / per-instance 边界）、以及护栏清单（writer ratchet、namespace-coverage lint、migration-deferral ratchet）。整个 review 交锋过程本身就是一份 " 配置模型迁移边界情况清单 "，比正文更有学习价值。

# 功能与动机

PR body 明确指出：".claude/skills/sglang-runtime-context skill still described the retired resolve-at-end contract (a single resolved ServerArgs as the source of truth, ServerArgs.override as the mutation entry) — actively misleading for anyone touching config now." 即旧的技能文档描述的是已被迁移淘汰的配置契约，会对任何接触配置代码的开发者（包括 Claude Code agent）产生误导。本 PR 作为 RFC #30696 follow-up stack 的最后一块拼图，需要把文档对齐到已落地的 namespace-bag 模型。

# 实现拆解

纯文档变更，只改一个文件 .claude/skills/sglang-runtime-context/SKILL.md，按以下步骤完成重写：

1. **重写 frontmatter 与 tier 总表**：description 更新为 "publish + namespace config bags"，把原来单一 config 层拆成 raw config seed（get_server_args()）与 resolved config（get_exec()/get_memory()/.../get_device() 等 11 个命名空间 bag）两层，并分别标注生命周期：seed 在进程入口发布、last-publish-wins、只读；bag 只在 publish 时投影、变更仅限 get_context().override。
2. **以 "Config: publish + namespace bags" 章节替换 "resolve-at-end" 章节**：说明 ServerArgs 是 pristine 种子，业务代码不读它做决策；publish(server_args, role=...) 按进程入口逐角色发布；SGLANG_ROLE_NAMESPACES=record/enforce 记录并限制各角色可读的命名空间；嵌套发布用 get_context().preserve_config() 包裹（如 draft-worker 构建）。
3. **新增 "Reads that legitimately stay on a ServerArgs instance" 章节**：区分 per-runner fork 字段（draft-worker deepcopy 重写的 attention_backend、load_format 等）、per-instance 边界（tokenizer-manager 家族、mm processor）、整体对象传递；并说明 get_parallel() 的 dual 语义：live 拓扑属性（@property）优先于 config bag 叶子，live-shadowed sizes 的读取规则单独成段。
4. **重写测试惯用语与护栏清单**：从旧的 override_server_args 改为 publish-seeding（测试通过真正发布注入配置，而不是伪造 accessor 或 SimpleNamespace）；强调 per-file 测试运行避免 leaked-publish 掩盖问题；护栏扩展为 writer ratchet（ServerArgs.override 逐步退役）、namespace-coverage lint（test_server_args_namespaces.py 双向校验）、migration-deferral ratchet，以及 strict mutation 无条件守卫。
5. **按 review 迭代修正**：把 publish-once 改为 last-publish-wins；恢复被删掉的 mid-resolution（resolved_view/self._resolved()）小节并注明 adaptive_spec_params 例外；将 live-shadowed fail-loud 收窄到 DCP 与 pre-dist-init；补 detokenizer 进程不 publish 的例外；把 mm processor 的 last-publish-wins 残留标记为已知漏洞；为 SGLANG_ROLE_NAMESPACES=record 补充 torch.compile 追踪代码内的读取不被观测的说明。

关键文件：
- `.claude/skills/sglang-runtime-context/SKILL.md`（模块 技能库；类别 docs；类型 documentation；符号 RuntimeContext.publish, RuntimeContext.preserve_config, RuntimeContext.override, declare_load_time_override）: 唯一变更文件。重写了 runtime-context 架构技能文档，从已废弃的 resolve-at-end 契约更新为 publish + namespace config bags 模型，是 config-namespace 迁移栈的收尾文档。

关键符号：RuntimeContext.publish, RuntimeContext.preserve_config, RuntimeContext.override, declare_load_time_override, resolved_view


# 评论区精华

Review 由 Codex 机器审阅与作者自审构成，围绕 " 文档表述不能比实现更乐观 " 展开，核心交锋如下：

- **raw config 生命周期**：Codex 指出 `RuntimeContext.set_server_args()` 明确允许覆盖，多 Engine / tokenizer 构建会再发布，文档写 publish-once 会误导。作者答复："Fixed — the tier table now states the actual lifecycle: published at process entry, re-publish is last-publish-wins (in-process tokenizer build, multi-Engine) and re-projects the bags."
- **draft 配置隔离范围**：Codex 指出只有 `build_draft_tp_worker()` 会安装私有 draft bags，EAGLE/Frozen-KV/MultiLayer/Standalone 直接构造 `TpModelWorker(is_draft_worker=True)` 时跳过 publish、共享目标进程 bags，draft 侧声明会污染目标配置。作者两次修正（declare 小节与 pitfall 小节）后才闭合。
- **strict mutation 守卫的真实行为**：Codex 指出 `SGLANG_STRICT_CONFIG_MUTATION` 已不再是控制开关，`ServerArgs.__setattr__` 在物化后无条件拒绝写入，环境变量只是遗留 harness 标志。作者确认并改为无条件描述。
- **mid-resolution 小节被删后恢复**：作者自审发现重写后丢掉了 `resolved_view` / `self._resolved()` 的中段读取契约；随后恢复 "Mid-resolution reads (inside the pipeline only)" 小节，并接受 Codex 意见补回 `adaptive_spec_params` 例外（pipeline 调用的 helper 可用 `resolved_view`）。
- **live-shadowed sizes 的 fail-loud 过宽**：作者自审指出 attn-CP / moe-DP 在 dist init 后总是安装（size=1 别名），只有 DCP 可选；Codex 又补充 `attn_dcp_size` / `attn_dcp_rank` 在未初始化时通过 `get_dcp_group_no_assert()` 返回合成值 1/0。最终收窄为：config-intent 读 `server_args.X`，fail-loud 只针对 DCP 与 pre-dist-init。
- **detokenizer / launcher 例外**：Codex 指出 detokenizer 进程从不 publish，launcher 在 Rust-server / 非零 rank / multi-tokenizer 模式下也不一定 publish。作者修复了 detokenizer 例外并限定描述范围；launcher 未见明确闭合回复，但 r3 disposition 判定 clean。
- **mm processor 残留漏洞**：Codex 指出 `BaseMultimodalProcessor.process_mm_data()` 仍通过 `get_server_args()` 读 `base_gpu_id` / `rl_on_policy_target`，多 Engine 共进程时存在 last-publish-wins 问题。作者选择在文档中将其标注为已知漏洞而非推广模式。

 - raw config 生命周期应为 last-publish-wins (correctness): 作者改为：published at process entry; re-publish is last-publish-wins（in-process tokenizer build、multi-Engine）并重新投影 bags。
 - draft 配置隔离仅限 preserve_config 构建 (correctness): 作者两次修正（declare 小节与 pitfall 小节），将隔离保证限定在 preserve_config 路径；跳过 publish 的 draft 加载共享进程 bags，声明必须 draft-safe。
 - 严格 mutation 守卫实际上无条件生效 (correctness): 文档改为 " 物化后无条件生效 "，bag 密封一并说明；环境变量仅作为 legacy 标志提及。
 - mid-resolution（resolved_view）小节被删后恢复 (design): 恢复 "Mid-resolution reads (inside the pipeline only)" 小节；并接受 Codex 意见补回 `adaptive_spec_params` 例外（pipeline 调用的 helper 可用 `resolved_view`）。
 - live-shadowed sizes 的 fail-loud 说明过宽 (correctness): 规则保留 config-intent → `server_args.X`（property 总是胜出）；fail-loud 收窄为 DCP + pre-dist-init，并叫出合成默认值。
 - detokenizer / launcher 进程不 publish 的例外 (correctness): 作者修复 detokenizer 例外并限定描述为 publishing process entries；launcher 未见明确回复，r3 disposition 判定 clean，但该分支仍建议后续验证。
 - multimodal processor 的 last-publish-wins 漏洞 (correctness): 作者在 per-instance 边界小节中将其标注为已知 last-publish-wins hole，不作为可复制模式；代码层未改。
 - namespace 记录的编译盲区与 parallel 例外 (design): record 模式说明补充 "audit with compilation disabled"；parallel 审计例外未见明确闭合记录，文档以 dual semantics 方式另行说明。

# 风险与影响

- 风险：本 PR 不触碰任何运行时代码，但存在以下风险：

- **文档与实现同步风险（主要）**：SKILL.md 描述的是迁移中期状态——`ServerArgs.override` 正在被 writer ratchet 逐步淘汰、launcher 等进程的发布行为尚未完全收敛。后续 PR 一旦完成 writer 迁移或改变 launcher 行为，这份文档会再次失真；纯文档没有 CI 测试保护，只能靠人工 review 维持。
- **误导迁移风险**：若读者按文档把 detokenizer / launcher 侧代码迁移到 bag 访问器，会直接触发 `ValueError: config namespace ... not published`。文档已尽力标注例外，但 launcher 分支的闭合情况在 review 中未见明确记录。
- **已知残留**：`BaseMultimodalProcessor.process_mm_data()` 的 last-publish-wins 漏洞被文档标记为已知，但这属于代码层问题，文档只能减轻影响、不能根治。
- **无回归 / 性能 / 安全风险**：不涉及任何运行时逻辑。
- 影响：SKILL.md 是 Claude Code 编写 SGLang 代码时的必读指南，本次重写直接影响后续所有接触 server_args / 配置相关代码的开发者与 AI agent 的行为：

- **对团队**：确保新贡献不再按已废弃的 resolve-at-end 契约往 `ServerArgs.override` 上写，减少配置模型迁移的返工成本。
- **对系统**：零运行时影响。
- **对迁移栈**：作为 RFC #30696 的 4/4 收尾，补齐了文档债，使配置命名空间迁移形成闭环。
- 风险标记：纯文档变更无代码防护 , 描述易随迁移推进失真 , launcher 发布例外未完全闭合 , mm processor 已知 last-publish-wins 漏洞

# 关联脉络

- PR #33013 config: read resolved config via namespace accessors: 落地 namespace bags 模型（160 文件 628 处迁移），本 PR 正是为其重写技能文档，使其不再描述已废弃的 resolve-at-end 契约。
- PR #33012 runtime_context: record the publishing process role: 引入 per-role 发布与 SGLANG_ROLE_NAMESPACES 记录机制，SKILL.md 中的角色强制章节直接源自该 PR。
- PR #33011 config: preserve resolved config across nested publishes + mutation ratchets: 引入 preserve_config 与 writer/migration ratchet，SKILL.md 中的护栏清单由此而来。
- PR #33179 [CI] Fix runtime context setup in flat logprob tests: 同一 runtime_context 迁移系列的后续修复，验证新模型下的观测与迁移路径，与本 PR 同属配置迁移闭环。