diff --git a/knowledge/repos/afd-plugin/_index.md b/knowledge/repos/afd-plugin/_index.md index 162aeff5e..c07b1b36e 100644 --- a/knowledge/repos/afd-plugin/_index.md +++ b/knowledge/repos/afd-plugin/_index.md @@ -44,3 +44,6 @@ sources: | 核对 connector/graph/DBO 当前支持组合 | [execution-platforms](components/execution-platforms/architecture.md) | v0.26 CUDA/Ascend 平台现状 | 默认 briefing 只加载本入口和仓库规则;深层 owner 页面由 changed-file route 或 `doc_search` / `doc_read` 按需读取。 +- [AFD plugin 评审规则:上游漂移与跨文档隐含不变量](rules-seed-vllm-omni-rebase-upstream-api-drift.md) +- [适用于任何 AFD PR review 的通用规则。先读这一页,再读本仓库的 rules.md 和对应的组件 owner 页。](../../general/review/rules.md) +- [以下情况读这一页,判断是否应先改上游:新增或刷新 compat patch、复制 vLLM/vLLM-Ascend 函数,或在 MoE routing、graph、forward context 上偏离原生实现。](../../general/review/guides/upstream-first-for-algorithm.md) diff --git a/knowledge/repos/afd-plugin/_routes.yaml b/knowledge/repos/afd-plugin/_routes.yaml new file mode 100644 index 000000000..f93136f31 --- /dev/null +++ b/knowledge/repos/afd-plugin/_routes.yaml @@ -0,0 +1,160 @@ +# Direct-mode owner routing for afd-plugin, written by kb init (pin 9cae2d2ddaae). +schema_version: 1 +owners: +- owner: components + path: repos/afd-plugin/components/_index.md + signals: + - components + scope_prefixes: + - afd_plugin/connectors/ + - afd_plugin/model_executor/ + - afd_plugin/compat/ +- owner: attention-runtime + path: repos/afd-plugin/components/attention-runtime/_index.md + signals: + - attention runtime + scope_prefixes: + - afd_plugin/v1/worker/attention_model_runner.py +- owner: connectors + path: repos/afd-plugin/components/connectors/_index.md + signals: + - connectors + scope_prefixes: + - afd_plugin/connectors/ + - afd_plugin/distributed/ +- owner: ffn-runtime + path: repos/afd-plugin/components/ffn-runtime/_index.md + signals: + - ffn runtime + scope_prefixes: + - afd_plugin/v1/worker/ffn_model_runner.py +- owner: model-integration + path: repos/afd-plugin/components/model-integration/_index.md + signals: + - model integration + scope_prefixes: + - afd_plugin/model_executor/ +- owner: plugin-boundary + path: repos/afd-plugin/components/plugin-boundary/_index.md + signals: + - plugin boundary + scope_prefixes: + - afd_plugin/__init__.py + - afd_plugin/v1/__init__.py +- owner: execution-platforms + path: repos/afd-plugin/components/execution-platforms/_index.md + signals: + - cuda graph + - acl graph + - graph + - FULL_DECODE_ONLY + - DBO + - ubatch + - profiler + - npu + - ascend + - csrc + - aclnn + - a2e + - e2a + - CANN + - build + - MLA graph + - stream + scope_prefixes: + - afd_plugin/compat/profiler.py + - afd_plugin/compat/npu/forward_context.py + - afd_plugin/compat/npu/ops.py + - afd_plugin/compat/npu/profiler.py + - afd_plugin/v1/worker/cuda_graph.py + - afd_plugin/v1/worker/dbo.py + - afd_plugin/v1/worker/npu/forward_context.py + - afd_plugin/v1/worker/npu/mla_graph.py + - afd_plugin/v1/worker/npu/npu_ubatch_wrapper.py + - afd_plugin/v1/worker/npu/ubatch_utils.py + - afd_plugin/v1/worker/npu/ubatching.py + - csrc/ + - setup.py + - MANIFEST.in + - docs/design/module/execution_platforms.md + - docs/npu/CAM_ASYNC_ROUTED_OPS.md + - tests/unit/compat/test_profiler.py + - tests/unit/compat/test_ascend_ops.py + - tests/unit/compat/npu/test_profiler.py + - tests/unit/package/test_ascend_build_files.py + - tests/unit/v1/worker/test_cuda_graph.py + - tests/unit/v1/worker/test_dbo.py + - tests/unit/v1/worker/test_npu_mla_graph.py + - tests/unit/v1/worker/test_npu_device_contract.py + - tests/unit/v1/worker/test_npu_runtime.py +- owner: compatibility + path: repos/afd-plugin/components/compatibility/_index.md + signals: + - patch + - monkey patch + - compat + - bump vllm + - vllm upgrade + - vllm-ascend + - EngineCore + - engine core + - async dp + - config_validation + - force load balance + - routing simulator + - upstream + scope_prefixes: + - afd_plugin/compat/ + - afd_plugin/model_executor/routing_simulator.py + - docs/design/module/compatibility_and_patches.md + - tests/unit/compat/ + - tests/unit/model_executor/test_routing_simulator.py +- owner: e2e-ci + path: repos/afd-plugin/rules.md + signals: + - e2e + - ci + - buildkite + - github actions + - workflow + - gsm8k + - accuracy + - e2e runner + - test + - docker + - pre-commit + - lint + scope_prefixes: + - tests/e2e/ + - tests/conftest.py + - tests/unit/test_e2e_runner.py + - tests/unit/test_e2e_process_utils.py + - tests/unit/test_dsv4_e2e.py + - .agents/skills/run-e2e/ + - .buildkite/ + - .github/ + - docker/ + - docs/design/module/e2e_testing.md + - docs/npu/TESTING.md + - .pre-commit-config.yaml + - .markdownlint.yaml +- owner: docs-recipes + path: repos/afd-plugin/rules.md + signals: + - docs + - readme + - recipe + - design doc + - AGENTS.md + - support matrix + - known gaps + - deployment + - guide + scope_prefixes: + - README.md + - recipe/ + - docs/ + - AGENTS.md + - CLAUDE.md + - .claude/ + - .agents/ diff --git a/knowledge/repos/afd-plugin/rules-seed-vllm-omni-rebase-upstream-api-drift.md b/knowledge/repos/afd-plugin/rules-seed-vllm-omni-rebase-upstream-api-drift.md new file mode 100644 index 000000000..6834341e8 --- /dev/null +++ b/knowledge/repos/afd-plugin/rules-seed-vllm-omni-rebase-upstream-api-drift.md @@ -0,0 +1,124 @@ +--- +title: "AFD plugin 评审规则:上游漂移与跨文档隐含不变量" +created: 2026-09-30 +updated: 2026-09-30 +type: rule +tags: [afd-plugin] +sources: [] +--- + +# AFD plugin 评审规则:上游漂移与跨文档隐含不变量 + +## AFD-I15 — 保持 CPU-safe 导入边界,CUDA/Ascend 类互不继承 + +- `vllm` 只是 optional extra,默认的 `uv run pytest` 要能在没有 CUDA wheel 的 CPU/macOS 环境运行。以下模块在导入时不能 import torch/vLLM 的 CUDA 运行时、`torch_npu` 或 `vllm_ascend`: + - 顶层 `afd_plugin`; + - 图策略 helper(`validate_cuda_graph_mode()`); + - `afd_plugin/connectors/factory.py`。 +- factory 使用 lazy loader。注册新 connector 时要保持惰性加载,不能在 factory 模块顶层 import `connectors/gpu` 或 `connectors/npu` 的实现。 +- Ascend 原生算子通过 `ensure_cam_p2p_ops_available()` 在 connector 初始化时才加载。算子缺失应该在 connector 初始化时报错,不能在包导入时报错。 +- NPU 类不能继承 CUDA AFD 类,反过来也一样。例如 `AFDNPUFFNModelRunner` 直接继承 vLLM-Ascend 的 `NPUModelRunner`,不继承 `GPUFFNModelRunner`。共享逻辑放在 config、connector payload、metadata、validation 或小 helper 里。 + + + +## AFD-I16 — 新增 connector 或 connector 配置字段时要多处同步 + +- 只在 `AFDConnectorFactory` 注册是不够的。配置层有一份独立的硬编码 allow-list(即 README 中 `connector` 允许的三个名字),它不从 factory 派生。不同步的话,新 connector 会在配置校验阶段被拒绝。 +- 实现要放在 `afd_plugin.connectors.gpu` 或 `afd_plugin.connectors.npu` 下,继承 `AFDConnectorBase`,并实现闭合 schema 的 `parse_extra_config()`,未知字段必须报错。`P2pNcclAFDConnector` 的 `connector_extra_config` 必须是空映射。 +- `compat/npu/feature_validation.py` 通过 factory 解析同一份 schema。新增字段时要在这里拒绝不支持的组合。 +- 要明确是否安装 `control_plane`。`GPUFFNModelRunner` 构造时断言 `connector.control_plane is not None`,所以 CUDA connector 必须提供 control plane。运行时只能按 `connector.control_plane is None` 分支,不能按具体类名判断。 +- 不要假设所有 connector 的 world 排序相同: + - `P2pNcclAFDConnector` 和 `CAMP2pAFDConnector` 是 FFN-first,要求 `num_attention_ranks >= num_ffn_ranks`,但不要求整除; + - `CAMAsyncAFDConnector` 是 Attention-first。 + + + +## AFD-I17 — connector 构造必须轻量,集体 rendezvous 延迟到权重加载之后 + +- 构造函数和 `parse_extra_config()` 不能创建 process group、communicator 或算子注册。这些都只能在 `init_afd_connector()` 里完成。 + - Attention 在 `load_model()` 末尾初始化,时间点在 AFD/Ascend ubatch wrapper 安装之后; + - FFN 在 `initialize_from_config()` 中初始化,时间点在空 KV-cache surface 之后、daemon 线程启动之前。 +- 如果把初始化提前到权重加载之前,两个角色就不能再重叠加载权重。rendezvous 必须在 Attention 做显存 profiling 或首次 forward 之前完成。 +- `close()` 必须满足: + - 清理该 connector 自己创建的 registry、pending queue、communicator 和 process group。 +- connector 变更要测试 cleanup,以及重试或重新初始化。 +- 模型代码可以通过 forward metadata 调用 connector 的 data-path 方法,但不拥有这些资源。 + + + +## AFD-I18 — 特性组合矩阵分散在多份文档,放宽或收紧时要整体一致 + +- `compute_gate_on_attention`: + - CUDA V1 + P2P 两个值都可以,取决于模型是否支持; + - Qwen3 MoE 和 Qwen3.5/3.6 只允许 `false`; + - 任何 V2 部署只允许 `false`; + - CAMP2P 要求通用字段和 connector-local 的同名字段都为 `false`; + - CAM async 要求通用字段为 `true`,`async_moe_ubatching` 同样要求 `true`。 +- 图模式:CUDA(V1 和 V2)只接受 `FULL_DECODE_ONLY`;Ascend V2 还接受 `FULL`;CAM async 只允许 eager。 +- DBO 和 ubatching: + - V1 原生 ubatching 只接受恰好两个 ubatch; + - V2 在两个平台上都拒绝 DBO 和 ubatching; + - CAM async 拒绝原生 DBO,它只有 AFD 自己管理的两阶段 `async_moe_ubatching`,两者不能混为一谈。 +- 不支持的组合必须在 config、worker 或 runner 初始化阶段失败。 +- 改动矩阵中任意一项时,都要同步以下三处:README 的「Known gaps」、`execution_platforms.md` 的 tested runtime matrix、对应 validator 的测试。 + + + +## AFD-I19 — README 和设计文档对 ModelRunnerV2 的支持说法互相矛盾 + + - 设计文档和 E2E 契约记录了 CUDA V2 的 DP2/TP2 eager/graph 证据,CI 在 `l4_4` 上按 node ID 运行 4 个 `afd-v2-*` 用例。 +- 评审时不要根据 README 把 V2 代码当成死代码,因此删除代码、跳过测试或放松校验。 +- 改动 `attention_model_runner_v2.py`、`npu/attention_model_runner_v2.py` 或 `AFDMetadataProviderMixin` 的 PR,必须保证 `afd-v2-{eager,graph}-{dp2,tp2}` 继续通过。 +- Ascend V2 只有单元测试证据,没有硬件 E2E。文档或 PR 描述里不能写成已经过硬件验证。 +- V2 的限制是两个角色共同遵守的契约。FFN 虽然不用原生 V2 runner,也必须运行同一个 topology/feature validator。只改 Attention 侧校验是不完整的。 +- 改变 V2 支持说法的 PR,要同时让 README 的 Known gaps、「Using the Plugin」和设计文档保持一致。 + + + +## AFD-I20 — 临时替换上游符号时,必须在 `finally` 中恢复,并纳入升级审计 + +- 以下作用域替换都必须在 `finally` 中恢复所有符号和 runner 状态,异常路径也一样: + - worker 在 `init_device()` 中替换 runner 符号; + - dummy run 和 V2 执行时包装 `create_forward_context`; + - V2 捕获时包装输入准备; + - full-graph replay 的实例级 hook; + - 构建多个 DBO ubatch 时临时禁用 Attention metadata cache。 +- 新增这类接缝时,要补恢复路径和错误路径的单测,可参照 `tests/unit/v1/worker/test_attention_model_runner.py` 对 DBO workaround 的覆盖。 +- 还要确保新接缝进入 `compatibility_and_patches.md` 里的作用域接缝清单。它们不是进程级 import-time patch,漏登记的话下次升级 vLLM 时容易被漏审。 +- 优先用作用域级或实例级替换。不要把 AFD 自有行为藏进方便的进程级全局 hook。 + + + +## AFD-I22 — vLLM-Ascend 基线只以源码 commit 记录 + +- 仓库不在 `pyproject.toml` 里声明 vLLM-Ascend 依赖,也没有 v0.26 的发布容器 tag。兼容证据就是 commit `80d8c194f` 加上已记录的 NPU 验证。 +- 不要为了「补上依赖」去加包依赖,也不要把 v0.19.1rc1 镜像当作 v0.26 运行时。 +- 刷新 Ascend patch 时,要引用确切的 vLLM-Ascend 源码 commit,并附上受影响路径的 NPU unit/E2E 证据。 +- 如果前移基线,以下几处的 `80d8c194f` 要一起更新:README 的 Ascend 表格和 Environment 段、`compatibility_and_patches.md`、`execution_platforms.md`。 +- v0.19.1rc1 基于 PCP 的部署在 v0.26 上不支持。legacy PCP8 recipe 只对应 `release/v0.19.1rc1`,不能当作 v0.26 支持的证据。 + + + +## AFD-I23 — Ascend 原生算子的构建选择与打包 + +- `setup.py` 只在检测到 `torch_npu`、CANN 环境变量或默认 toolkit 路径时构建 Ascend 扩展,GPU 构建默认跳过。 +- 环境变量的作用:`AFD_BUILD_ASCEND_OPS=1/0` 显式覆盖自动检测;`AFD_SKIP_ACLNN_BUILD=1` 只在产物已存在时跳过 ACLNN vendor build。改动不能让 CPU/GPU 环境默认触发 CANN 构建。 +- 构建要在 `csrc/npu` 下完成 CANN vendor build,并打包 `_cann_ops_custom`(`setup.py` 和 `MANIFEST.in` 属于同一个 owner)。`csrc/gpu` 只是保留目录,目前没有插件自己的 CUDA 扩展。 +- `CAMAsyncAFDConnector` 需要全部四个 `torch.ops.afd_ascend.afd_async_*` 算子。910C 包注册了它们,950 包没有注册,不要在 950 目标上假设这些算子存在。 +- routed-only 算子的 host tiling 以 MiB 为单位读取 `HCCL_BUFFSIZE`。host helper 不查询实际窗口大小,所以引入或修改 `hccl_buffer_size` 覆盖时,要保证两者取值一致。 +- 构建或原生算子的变更,要跑对应单测(如 `tests/unit/package/test_ascend_build_files.py`、`tests/unit/compat/test_ascend_ops.py`),并提供硬件 E2E 证据。 + + + +## AFD-I24 — E2E 的 CI 用例选择:PR 门禁和 2A1F 用例的边界(文档内部有冲突) + +- PR 门禁只能按 pytest node ID 选以下用例: + - 使用不超过 4 个设备、2 Attention + 2 FFN 的 legacy 用例; + - 4 个 CUDA V2 DP2/TP2 用例。 +- README 推荐的本地冒烟用例 `afd-eager-2a1f` 不能进 PR 门禁。 +- `e2e_testing.md` 内部有冲突:一处说 2A1F 是「local-only」「run outside CI」;accuracy gate 表却把 DeepSeek `afd-graph-dbo-2a1f` 和 Qwen3 MoE/Qwen3.6 MoE 用例(Qwen3.6 套件是 2A1F)列进 weekly。 +- 修改 `.buildkite/` 或 `.github/` 的调度时,2A1F 用例只能出现在 scheduled/weekly job 里,并应顺手让文档说法一致。 +- CI 不能设置 `AFD_GSM8K_LIMIT`,也不能降低 `AFD_GSM8K_THRESHOLD`、样本数或必选用例集。DBO 用例要保留 24 个样本的下限和 12 个并发请求。 +- CUDA 的 legacy 矩阵和 V2 矩阵各是一个独立的 40 分钟 job。更慢的覆盖放到 scheduled job。 + + diff --git a/knowledge/repos/afd-plugin/rules.md b/knowledge/repos/afd-plugin/rules.md index 5ab5213eb..34f43e62b 100644 --- a/knowledge/repos/afd-plugin/rules.md +++ b/knowledge/repos/afd-plugin/rules.md @@ -1,7 +1,7 @@ --- title: "AFD plugin 仓库规则" created: 2026-08-05 -updated: 2026-08-06 +updated: 2026-09-30 type: rule tags: [afd-plugin, review, config, distributed, model-executor] sources: @@ -45,3 +45,96 @@ sources: - AFD-4b:GPU/NPU E2E 必须通过 AFD 仓库 `.agents/skills/run-e2e/SKILL.md` 或仓库测试入口运行,记录 backend、设备数、模型路径、vLLM/vLLM-Ascend/CANN/torch 版本、拓扑、connector、graph/DBO/async 配置和 skipped 原因。 - AFD-4c:性能、精度或硬件支持 claim 必须给可复现证据:硬件型号、软件版本、driver/toolchain、rank 拓扑、命令、日志或 pytest node id;CPU import/config smoke 不能替代硬件证据。 - AFD-4d:changed files 没有命中 adapter route 时,必须把 unmatched path 明确留给 host reviewer 继续人工审,不得把它当作已覆盖。 + +## AFD-I1 — ModelRunnerV2 的支持状态在 README 与设计文档之间互相矛盾,改 V2 时两边都要核对 + +- README 的 Known gaps 写着 V2 不受支持,还要求设置 `VLLM_USE_V2_MODEL_RUNNER=0`。设计文档和 E2E 文档却写着 CUDA V2 已经实现,DP2/TP2 用例也在 PR CI 里。凡是改动 `attention_model_runner_v2.py`、`npu/attention_model_runner_v2.py` 或 V2 校验逻辑的 PR,都要确认 README 与设计文档说法一致;行为变了就同步更新 README。 +- 写支持声明时要分清证据:CUDA V2 有 DP2/TP2 eager 和 graph 的 E2E 证据;Ascend V2 只有单元测试证据。PR 描述和文档都不能说 Ascend V2 经过了硬件验证。 +- V2 的约束和 V1 不同,不能直接套用 V1 的约束: + - 拒绝 DBO 和 ubatching; + - 要求 `compute_gate_on_attention=false`、PP=PCP=DCP=1、角色 rank 数等于 DP×TP、静态 EP; + - CUDA V2 只能用 eager 或 `FULL_DECODE_ONLY`,Ascend V2 还可以用 `FULL`。 +- FFN 虽然不使用原生 V2 runner,但会执行同一套配对拓扑校验。修改 V2 约束时,Attention 和 FFN 两侧的校验要一起改。 + + + +## AFD-I2 — 新增或重命名 connector 时,配置 allow-list 和 factory 注册要同时改 + +- 配置里的 connector 名称 allow-list 是硬编码的,不从 `AFDConnectorFactory` 的注册表生成。只在 factory 里注册,配置校验仍会拒绝新名称。所以要检查 `role`/`connector` 校验和 factory 是否一起改了。 +- factory 的 loader 必须是懒加载,并且要解析成 `AFDConnectorBase` 的子类。导入 factory 时不能连带导入 CUDA 或 Ascend 的实现。 +- 新 connector 要实现 `parse_extra_config()`,对 `connector_extra_config` 使用封闭 schema,遇到未知字段就报错。`P2pNcclAFDConnector` 的 extra config 必须为空。 +- 实现文件放在对应后端的包下:`afd_plugin.connectors.gpu` 或 `afd_plugin.connectors.npu`。 +- 同时更新三张表:README 的 connector 表、Attention runtime 的 runtime selection 表、FFN runtime 的 runtime selection 表。 + + + +## AFD-I4 — `compute_gate_on_attention` 的合法取值因 connector、模型和 runner 而不同,而且有两个同名字段 + + - `P2pNcclAFDConnector`:true、false 都支持; + - 同步 NPU 的 `CAMP2pAFDConnector`:公共字段和 connector 本地字段都必须是 `false`; + - `CAMAsyncAFDConnector`:公共字段必须是 `true`,`async_moe_ubatching` 也依赖 `true`; + - Qwen3 MoE、Qwen3.5/3.6 以及所有 V2 路径:都拒绝 `true`。 +- CAMP2P 有两个同名字段:`AFDConfig` 上的公共字段,和 `connector_extra_config.compute_gate_on_attention`。改动其中一个的解析或校验时,要确认另一个也被检查到了。 +- 不支持的组合必须在执行前失败,由 `compat/npu/feature_validation.py` 或 worker 初始化负责拦截。不能在运行时悄悄回退。 + + + +## AFD-I6 — 控制面的副作用必须在正式图捕获之外完成 + +- `send_dp_metadata_list` 和 `update_state_from_dp_metadata` 必须在进入 `torch.cuda.graph(...)` 或 `torch.npu.graph(...)` 之前执行。图里只能捕获模型和数据面的操作。 +- 不带 ubatch 的捕获要先显式发送 padded shape。带 ubatch 的捕获由平台 wrapper 按 stage 发送。 +- V2 的要求: + - 每个原生 descriptor 只能发布一次 warmup payload 和一次 capture payload; + - 原生 full-graph replay 不会创建 `ForwardContext`,所以 replay 前必须通过实例级 hook 发布 padded shape; + - 所有临时 hook 都要在 `finally` 里恢复。 +- FFN 的图 key 由 `make_ffn_graph_key()` 或 stage token 数生成,NPU 还要加上 A/F 拓扑。key 缺失时必须回退到 eager,不能报错,也不能复用错误形状的图。 +- CUDA 图模式只接受 `FULL_DECODE_ONLY`,其他模式必须在运行前就被拒绝。 + + + +## AFD-I7 — 临时替换上游符号时必须在 `finally` 里恢复,并把替换点列入升级审计 + +- 以下临时替换不在 `compat/patches/` 目录下,但都属于上游适配点: + - CUDA worker 在 `Worker.init_device()` 期间替换 runner 符号; + - dummy run 和 V2 执行时包装 `create_forward_context`; + - V2 捕获时包装原生 input preparation; + - full-graph replay 时安装 manager hook; + - DBO 构建期间关闭 Attention metadata cache。 +- 这些替换都必须在 `finally` 里恢复符号和 runner 状态。PR 要带上恢复路径和出错路径的测试。 +- 新增类似的替换时,要在 `compatibility_and_patches.md` 里登记,并写明移除条件(参照 vLLM #48659 那一项的写法)。升级上游时,这些替换点都要纳入审计。 + + + +## AFD-I9 — `register_afd` 导入补丁是 best-effort 的,对应的运行时路径必须能发现补丁缺失并报错 + +- 核心补丁在同一个 `try` 里导入,失败只打 debug 日志,可能出现只装上一部分的情况。新补丁如果加进这个块,依赖它的运行时路径就必须检查补丁是否已安装(比如检查 sentinel 或保存的原函数),缺失时明确报错,不能带着错误结果继续服务。 +- 保存了原函数的补丁,在 reload 时不能用自己的 wrapper 覆盖已保存的原函数。初始化要么幂等,要么有显式守卫。 +- Ascend 补丁要等 Ascend 插件完成平台初始化后才能应用。只用 CUDA 的注册路径不能导入 vLLM-Ascend。 +- 新增或修改补丁时,要同步更新 inventory 表:守卫方式、幂等性、验证方式和移除条件。还要为非 AFD 分支写回归测试。 + + + +## AFD-I10 — CPU 安全的导入边界:公共模块不能在导入时拉入设备栈 + +- `vllm` 是可选 extra,默认的 `uv run pytest` 要能在 CPU 或 macOS 上运行。顶层包、公共配置和校验、版本检查、图策略 helper(包括 `validate_cuda_graph_mode()`),以及 connector factory,都不能在模块级导入 `torch`、`vllm`、`torch_npu`、`vllm_ascend` 或 `afd_plugin._C_ascend`。 +- 原生算子只在 connector 初始化时懒加载,例如 `ensure_cam_p2p_ops_available()`。缺少算子时应在 connector 初始化阶段失败,不能在 import 时失败。 +- CUDA 或 Ascend 的 runtime 模块本身可以导入真实设备依赖,但公共模块不能反过来在导入时引用它们。 + + + +## AFD-I11 — 依赖方向和平台隔离:不能跨平台继承,也不能反向依赖角色 worker + +- NPU 的 AFD 类不能继承 CUDA 的 AFD 类,反过来也一样。平台扩展只能继承对应的上游类。`GPUFFNModelRunner` 保持为插件自有的最小 runner,`AFDNPUFFNModelRunner` 直接继承 `NPUModelRunner`。 +- connector、模型和其他共享模块不能 import Attention 或 FFN 的 worker/runner 实现。生产代码不能依赖 `tests/e2e` 下的测试 harness。 +- 代码按后端放置:connector 放在 `afd_plugin.connectors.gpu` 或 `afd_plugin.connectors.npu`,原生源码放在 `csrc/npu` 或 `csrc/gpu`。 +- `compat/patches` 不能用来存放 AFD 自有的功能。 + + + +## AFD-I12 — E2E gate 的拓扑:PR gate 只能用 2A2F 且不超过 4 张卡;文档对 2A1F 是否进 CI 说法矛盾 + +- 加入 PR gate 的 AFD 用例必须是 2A2F,而且最多用 4 张不同的卡。2A1F、16 卡的 DSV4 用例和 async CAM 的 NPU 冒烟用例都不能进 PR gate。 +- 文档自相矛盾:E2E-INV-002 和 2A1F 那一节都说 2A1F 只在本地跑、不进 CI;但 weekly 的准确率 gate 包含 DeepSeek 的 `afd-graph-dbo-2a1f`,Qwen3.6 的默认套件也是 2A1F。PR 如果把 2A1F 用例放进定时 CI,必须同时修正相关文档,不能留下矛盾。 +- 默认情况下,harness 触发 `SIGKILL` 必须判定用例失败。只有 async CAM 的 NPU 场景有例外:它通过 run id 和角色标记扫描 `/proc/*/environ` 来清理进程。这个例外不能扩展到其他用例。 + +