diff --git a/knowledge/repos/vllm-omni/ci/rules-amd.md b/knowledge/repos/vllm-omni/ci/rules-amd.md index 7422b5415..b93551373 100644 --- a/knowledge/repos/vllm-omni/ci/rules-amd.md +++ b/knowledge/repos/vllm-omni/ci/rules-amd.md @@ -1,7 +1,7 @@ --- title: "AMD/ROCm CI 规则" created: 2026-09-05 -updated: 2026-09-10 +updated: 2026-09-14 type: rule tags: [vllm-omni, ci] sources: ["PR #6704", "PR #6830", "PR #6884", .buildkite/amd/, tests/helpers/clean.py, tests/helpers/stage_config.py, tests/buildkite/test_amd_pipeline.py, tests/e2e/offline_inference/test_qwen3_omni_colocate_async.py, "PR #7234"] @@ -42,3 +42,10 @@ confidence: high - 强制:`mi300_1` 一类单卡 model job 的 pytest marker 必须 `not (cards_2 or … or cards_8)`,同时保留无 `cards_1` 的 legacy 单卡用例;真正需要双卡的用例(如 LTX2 Ulysses parity)改到已有双卡 lane,并声明 `rocm` 资源与 `device_count >= world_size` 早失败。 - 禁止:让 `cards_2+` 测试在单卡 worker 上 spawn rank1→GPU1 导致 `invalid device ordinal`;用邻近 green shard 宣称 multi-GPU routing 已修好。 - 验收:pipeline argv/collection 断言单卡 job 排除 multi-card markers、双卡 job 收集目标文件;硬件 marker helper 覆盖 ROCm 声明。^[PR #7234] + +## OMNI-CI-2i — ROCm Dockerfile 必须与 CI 的 vLLM release 对齐并在构建期 canary + +- 触发:修改 `docker/Dockerfile.rocm` 的 `BASE_IMAGE` / `VLLM_VERSION_OR_COMMIT_HASH` / `USE_NIGHTLY_BUILD`、`.buildkite/amd` 的 image build 命令,或 AMD 运行时因缺失 vLLM API 失败。 +- 强制:默认 `BASE_IMAGE` tag 与可选 source rebuild 的 `VLLM_VERSION_OR_COMMIT_HASH` 都必须等于 `docker/Dockerfile.ci` 的 `VLLM_BASE_TAG`;AMD build 不得 `--build-arg` 覆盖这两个默认。可选 nightly 重装之后、业务层拷贝之前,必须用当前 Omni 依赖的 vLLM API 做 image-build canary,构建失败优于整 lane runtime 失败。 +- 禁止:只升 Omni 代码而留下过期 ROCm base;把 canary 推到测试阶段;用自定义 source pin 却不更新 `tests/buildkite/test_rocm_dockerfile.py`;把 Docker pin 误当成非 Docker 安装会自动装上匹配 vLLM。 +- 验收:静态回归断言 ROCm base/source ref 跟踪 CI tag、默认 `USE_NIGHTLY_BUILD=0`、AMD build 不覆盖上述 arg、canary 位于 nightly 块之后;故意错位 pin 必须失败。^[PR #7395] diff --git a/knowledge/repos/vllm-omni/components/configuration/rules-legacy-engine-args.md b/knowledge/repos/vllm-omni/components/configuration/rules-legacy-engine-args.md index 8135708c2..b89c42e9d 100644 --- a/knowledge/repos/vllm-omni/components/configuration/rules-legacy-engine-args.md +++ b/knowledge/repos/vllm-omni/components/configuration/rules-legacy-engine-args.md @@ -1,7 +1,7 @@ --- title: "legacy engine args 投影隔离" created: 2026-09-05 -updated: 2026-09-10 +updated: 2026-09-14 type: rule tags: [vllm-omni, components, config] sources: ["PR #6783", vllm_omni/engine/stage_init_utils.py, tests/engine/test_build_engine_args_no_mutate.py, "PR #5929", "PR #7237"] @@ -31,3 +31,10 @@ confidence: high - 强制:把该 alias 标为非 stage 字段;在 `log_stats` 等 canonical 值已由 launcher/`__init__` 消费后,于 resolver 边界 `pop` 残余 alias,使 structured ownership 看不到它。标准与 headless 启动都必须消费。 - 禁止:让 residual `disable_log_stats` 落入 `resolve_omni_config` / `VllmOmniConfig` 并报 “no structured config owner”;为通过校验而放宽真正的 stage engine-arg ownership。 - 验收:断言字段在 `_NON_STAGE_ENGINE_CLI_FIELDS` 且不在 global stage CLI fields;engine 与 headless 解析后 kwargs/`cli_overrides` 不含该 alias;带 alias 的 TTS/structured pipeline 仍能构造。^[PR #7237] + +## VOMNI-CFG-1u — 用户可见的 upstream ModelConfig CLI 必须有 typed stage owner + +- 触发:文档/示例使用的全局 ModelConfig CLI(如 `served_model_name`、`allowed_local_media_path`、`allowed_media_domains`、`max_logprobs`、`logprobs_mode`、`mm_processor_kwargs`、`mm_processor_cache_type`、`hf_token`、`hf_config_path`、`generation_config`、`override_generation_config`、`enable_prompt_embeds`)在 `from_pipeline_config` 报无 owner,或新增同类 upstream ModelConfig 输入。 +- 强制:把字段同时加入 `_ModelEngineOverrides` 与 `OmniStageModelConfig`,类型跟随 vLLM `EngineArgs`,默认 `None`,使 `_project_omni_config_fields` 只投影用户显式值,并经 typed/legacy engine-args 到达各 stage。不得把这些 ModelConfig 输入塞进 `_NON_STAGE_ENGINE_CLI_FIELDS` 来绕过 ownership。 +- 禁止:仅因 legacy `build_stage_runtime_overrides` 仍能透传就让 structured ownership 拒绝文档命令;把尚未归属的非 ModelConfig 开关(如 `enable_lora`/`speculative_config`)一并放行。 +- 验收:对至少两个 pipeline key 参数化断言显式全局值进入每个 stage 的 `model_config`,并用 typed `build_engine_args_dict_from_omni_stage_config` 读回同一集合;字段集合 census 必须包含这些 owner。^[PR #7390] diff --git a/knowledge/repos/vllm-omni/components/diffusion/rules-lora.md b/knowledge/repos/vllm-omni/components/diffusion/rules-lora.md index e73e11ae0..9f4ee7917 100644 --- a/knowledge/repos/vllm-omni/components/diffusion/rules-lora.md +++ b/knowledge/repos/vllm-omni/components/diffusion/rules-lora.md @@ -1,7 +1,7 @@ --- title: "Diffusion LoRA 规则" created: 2026-09-02 -updated: 2026-09-09 +updated: 2026-09-14 type: rule tags: [vllm-omni, components, diffusion] sources: ["PR #2783", docs/user_guide/diffusion/lora.md, vllm_omni/config/omni_config.py, vllm_omni/config/stage_config.py, vllm_omni/diffusion/data.py, vllm_omni/diffusion/lora/loader.py, vllm_omni/diffusion/lora/manager.py, vllm_omni/diffusion/lora/layers/base_linear.py, vllm_omni/diffusion/models/qwen_image/pipeline_qwen_image.py, vllm_omni/diffusion/models/wan2_2/pipeline_wan2_2.py, vllm_omni/diffusion/models/wan2_2/pipeline_wan2_2_i2v.py, vllm_omni/diffusion/utils/tf_utils.py, vllm_omni/diffusion/worker/diffusion_worker.py, vllm_omni/engine/async_omni_engine.py, vllm_omni/entrypoints/cli/serve.py, tests/diffusion/lora/test_loader.py, tests/diffusion/lora/test_lora_manager.py, tests/entrypoints/test_async_omni_diffusion_config.py, "PR #5500", "vllm_omni/diffusion/models/ltx2/ltx2_adapter_parser.py", "vllm_omni/diffusion/models/ltx2/ltx2_phase_adapter.py", "PR #6070", "PR #6476", "PR #6550", vllm_omni/diffusion/models/minimax_h3/lora.py, "PR #6268", benchmarks/kernels/benchmark_diffusion_lora_expand.py, tests/diffusion/lora/test_base_linear.py, "PR #7195"] @@ -137,3 +137,10 @@ confidence: high - 强制:deactivate 只 `suspend_lora()`(保存并清零 `_diffusion_lora_active_slices`),保留 stacked A/B;同一 adapter_id 与同一 rounded scale 再激活时 `resume_lora()` 复原掩码,禁止整层 `reset_lora`+rebind。`_suspended_adapter_id` 在真实 reset、rank 驱动的 `create_lora_weights`、新 bind 开始、以及 remove 被 suspend 的 adapter 时必须清空;不同 adapter 或不同 scale 仍走完整 rebind。 - 禁止:把 suspend 当成可丢弃的 upload;resume 覆盖后注册的新 layer 的 inactive mask;在失败 bind 后仍保留旧 suspended 身份。 - 验收:CPU 覆盖 suspend/resume、同 id+scale 不 re-upload、不同 scale/id 走 rebind、remove suspended 触发 reset、中途失败后 inactive,以及 add_adapter 后新 layer 不被错误 resume。^[PR #7195] + +## DIFF-2ag — LoRA/ModelOpt 默认只保留通用组件名与通用 fused 映射 + +- 触发:修改 `DiffusionLoRAManager` 默认扫描组件、ModelOpt `DEFAULT_PACKED_MODULES_MAPPING`,或 pipeline/model 的 `_lora_components` / `_dit_modules` / `packed_modules_mapping`。 +- 强制:manager 默认只扫描通用 diffusers 名 `transformer`、`transformer_2`、`unet`;模型专用属性(如 Bagel 的 `bagel`)必须由 pipeline 经 `_dit_modules` 或 `_lora_components` 声明。ModelOpt 默认只保留通用 attention 融合(`to_qkv`、`add_kv_proj`);模型专用融合(如 Z-Image `w13`)必须写在模型 `packed_modules_mapping` 并由 adapter 合并。 +- 禁止:把 `dit`/`bagel`/`w13` 等模型私有名硬编码进共享默认;在未扫描真实 denoiser 时宣称 adapter 已生效(零层绑定、输出等同 base)。 +- 验收:Bagel/同类测试 pipeline 必须显式 `_lora_components` 才能发现层;Z-Image 映射在模型侧声明后仍可解析;去掉声明后不得靠框架默认偷跑。^[PR #5907] diff --git a/knowledge/repos/vllm-omni/components/distributed/rules.md b/knowledge/repos/vllm-omni/components/distributed/rules.md index d693a2d07..619055d56 100644 --- a/knowledge/repos/vllm-omni/components/distributed/rules.md +++ b/knowledge/repos/vllm-omni/components/distributed/rules.md @@ -1,7 +1,7 @@ --- title: "Distributed 传输规则" created: 2026-08-05 -updated: 2026-09-08 +updated: 2026-09-14 type: rule tags: [vllm-omni, components, distributed] sources: ["PR #5744", "PR #5976", "PR #6001", "PR #6089", "PR #6834", vllm_omni/diffusion/distributed/parallel_state.py, tests/diffusion/distributed/test_expert_parallel_layout.py, vllm_omni/distributed/omni_connectors/adapter.py, vllm_omni/distributed/omni_connectors/kv_transfer_manager.py, vllm_omni/distributed/omni_connectors/transfer_adapter/chunk_transfer_adapter.py, vllm_omni/distributed/omni_connectors/transfer_adapter/base.py, vllm_omni/worker/omni_connector_model_runner_mixin.py, tests/distributed/omni_connectors/test_kv_recv_tp_consensus.py, tests/distributed/omni_connectors/test_chunk_transfer_adapter.py, tests/worker/test_omni_connector_mixin.py, "PR #5146", "PR #6021", "PR #6033", "PR #6360", "PR #6406", "PR #6626", "PR #6529", "PR #7136"] @@ -142,3 +142,10 @@ confidence: high - 强制:CUDA Mooncake 依赖必须钉在包含 acknowledged TCP writes 的版本(`0.3.12` 起);`batch_transfer_sync_write` 返回成功后,destination 内存必须已更新到可读状态,不能只表示本地 send 入队。回归必须在 receiver 被挂起时证明 completion 不会提前返回,恢复后再断言目的端字节一致。 - 禁止:降级到无 ACK 的 TCP 实现却不更新测试合同;把 RDMA 路径的 completion 语义外推到 TCP;或在 completion 前启动依赖 destination 内容的零拷贝消费。 - 验收:强制 TCP 的挂起-恢复测试覆盖「停止期间不完成、恢复后成功且字节匹配」;依赖声明与该测试同步变更。^[PR #7136] + +## DIST-1l — parked async-chunk sender 收到终态 update 必须先投递 terminal chunk + +- 触发:修改 `OmniSchedulerMixin.add_request`、`OmniChunkTransferAdapter.save_async` / sender cleanup,或 realtime/async-chunk 在 `WAITING_FOR_STREAMING_REQ` 上的终态竞态。 +- 强制:当终态 update(`resumable=False`)落在已 parked 且 `has_active_sender` 的 session 上时,不得只走 upstream 的本地 `FINISHED_ABORTED`。必须先 `force_request_finished` 入队携带 `finished` 的 request-terminal chunk(必要时推进 `_omni_segment_generation` 以通过 dedup),再本地 finish。`terminal_pending` 必须挡住丢弃该 chunk 的 cleanup,直到 connector 接受。 +- 禁止:假设 orchestrator 的一次性 StreamingUpdate 对下游 receiver 足够;在 `finish_requests` 之后才尝试 enqueue terminal;让 cleanup 在 terminal 上线前回收 generation,导致下游卡在 `WAITING_FOR_CHUNK` 直至输入超时。 +- 验收:覆盖 parked+active-sender 终态、非 sender/非 parked 回退、`force_request_finished` 顺序、terminal_pending 与 deferred cleanup;证明下游经 payload `finished` 结束,而不是仅靠 600s stall。^[PR #6889] diff --git a/knowledge/repos/vllm-omni/components/model-executor/rules-loader-contract.md b/knowledge/repos/vllm-omni/components/model-executor/rules-loader-contract.md index 3bf0435ca..7fd588394 100644 --- a/knowledge/repos/vllm-omni/components/model-executor/rules-loader-contract.md +++ b/knowledge/repos/vllm-omni/components/model-executor/rules-loader-contract.md @@ -1,7 +1,7 @@ --- title: "loader 合同" created: 2026-09-04 -updated: 2026-09-05 +updated: 2026-09-14 type: rule tags: [vllm-omni, components, model-executor] sources: ["PR #4730", "PR #4765", "PR #4958", "PR #5777", "PR #5824", vllm_omni/model_executor/model_loader/, "PR #5910", "PR #6119", "PR #5791", "vllm_omni/model_executor/models/common/qwen3_code_predictor.py", "vllm_omni/platforms/npu/_310p/patch/qwen3_tts.py", "PR #6138", "PR #6640", vllm_omni/engine/stage_init_utils.py, tests/engine/test_async_omni_engine_stage_init.py, tests/engine/test_stage_engine_args.py, "PR #6830", vllm_omni/engine/arg_utils.py, tests/engine/test_arg_utils.py, "PR #6803", vllm_omni/model_executor/models/mimo_audio/mimo_audio_llm.py, vllm_omni/model_executor/models/mimo_audio/mimo_audio.py] @@ -114,3 +114,10 @@ confidence: high 覆盖。审计中 `MiMoAudioToken2WavForConditionalGenerationVLLM` 与 `CovoAudioCode2WavForConditionalGeneration` 的同类缺口仍须由各自 owner 单独确认。 ^[PR #6803] + +## EXEC-2j — `SupportsMultiModal` 实现必须显式覆盖 `embed_multimodal` + +- 触发:Omni 模型类实现/继承 `get_multimodal_embeddings`,或对齐 vLLM V1 encoder profiling / runtime 的 `embed_multimodal` 调用。 +- 强制:concrete 类必须 override `embed_multimodal` 并委托到现有 `get_multimodal_embeddings`(或等价实现);不得依赖 Protocol stub 的默认 `None`。同目录 sibling wrapper 已委托时,LLM/核心类必须保持同一合同。 +- 禁止:只实现旧 `get_multimodal_embeddings` 却让 V1 profiling/runtime 落入 stub;把远处的 `NoneType` 启动失败当成权重/registry 问题。 +- 验收:无权重构造 + monkeypatch 断言 `embed_multimodal` 转发 kwargs 并返回 embeddings;去掉 override 时测试必须看到 stub 的 `None`。^[PR #7384] diff --git a/knowledge/repos/vllm-omni/components/serving/rules-request-input.md b/knowledge/repos/vllm-omni/components/serving/rules-request-input.md index 495c86590..edf3a7b1e 100644 --- a/knowledge/repos/vllm-omni/components/serving/rules-request-input.md +++ b/knowledge/repos/vllm-omni/components/serving/rules-request-input.md @@ -1,7 +1,7 @@ --- title: "请求输入合同" created: 2026-09-04 -updated: 2026-09-04 +updated: 2026-09-14 type: rule tags: [vllm-omni, components, serving] sources: ["PR #3805", "PR #5374", "PR #5885", "PR #6598", vllm_omni/data_entry_keys.py, vllm_omni/engine/async_omni_engine.py, vllm_omni/entrypoints/openai/, vllm_omni/entrypoints/omni_base.py, vllm_omni/engine/orchestrator.py, vllm_omni/inputs/, tests/engine/test_async_omni_engine_input.py, tests/engine/test_orchestrator_error_handling.py, tests/entrypoints/test_omni_entrypoints.py, tests/entrypoints/openai_api/test_invalid_audio_speech.py, tests/entrypoints/openai_api/test_serving_speech.py, "PR #5181", "PR #6182"] @@ -139,3 +139,10 @@ engine 生命周期见 [engine 生命周期规则](rules-engine-lifecycle.md); - 强制:transform 只操作 Stage-0 copy;原始 prompt 保留给 downstream,并在 transform 前后保持同一 global request ID。只把已处理的 metadata 合并回原始视图,先移除 transform-owned stale keys。临时目录只通过内部 `REQUEST_ARTIFACT_DIRS_KEY` 交给 request state;preprocess、companion build、enqueue 前失败立即回收,admit 后由 orchestrator 在所有 terminal cleanup 路径回收,且内部 key 不得进入 stage payload。 - 禁止:把 transformed prompt 当作 downstream 原始媒体、让旧 prepared descriptor 跨请求复用、在 ownership 已交给 orchestrator 后由 frontend 提前删除,或让异常路径泄漏转码目录。 - 验收:覆盖 transform replacement/copy、request ID 与 metadata merge、成功 terminal/abort、preprocess/companion/enqueue 异常以及无 artifact control;断言 downstream 看见原始媒体+允许的 processed meta,目录恰好由当前 owner 回收,内部 key 未传输。^[PR #5885] + +## SERV-4r — `vllm serve --omni` 必须在校验期要求显式 model + +- 触发:修改 `OmniServeCommand.validate`、`--omni` 启动路径、`model`/`model_tag`/`explicit_keys`,或部署 YAML 与 checkpoint 来源关系。 +- 强制:`--omni` 下 model 只能来自非空 positional `model_tag`,或出现在 `explicit_keys` 中的非空 `--model`。`--deploy-config` / stage YAML 只携带 per-stage engine args,checkpoint 始终由 `args.model` 注入,不得凭 YAML 存在判定“已提供 model”。空/空白 model 视为未提供,并在 validate 期以明确 `ValueError` 失败。 +- 禁止:依赖 vLLM `ModelConfig` 默认 `Qwen/Qwen3-0.6B` 进入 Omni/diffusion 路由;把默认模型缺失伪装成深层 diffusion-registry `Model class … not found`;让仅 `--deploy-config` 或空 `--model "$MODEL"` 绕过守卫。 +- 验收:`["serve","--omni"]`、仅 deploy-config、空/空白 positional/`--model` 均 raise “requires an explicit model”;positional、`--model`、以及显式 model+deploy-config 不得触发该守卫。^[PR #4167] diff --git a/knowledge/repos/vllm-omni/components/serving/rules-upstream-compat.md b/knowledge/repos/vllm-omni/components/serving/rules-upstream-compat.md index 25074b5ab..9b48ab8bb 100644 --- a/knowledge/repos/vllm-omni/components/serving/rules-upstream-compat.md +++ b/knowledge/repos/vllm-omni/components/serving/rules-upstream-compat.md @@ -1,7 +1,7 @@ --- title: "Serving upstream 兼容规则" created: 2026-09-02 -updated: 2026-09-05 +updated: 2026-09-14 type: rule tags: [vllm-omni, components, serving] sources: ["PR #5976", "PR #5957", vllm_omni/engine/stage_engine_startup.py, vllm_omni/entrypoints/openai/api_server.py, vllm_omni/entrypoints/utils.py, vllm_omni/request.py, tests/engine/test_stage_engine_startup_cache_env.py, tests/config/test_endpoint_policy.py, "PR #5036", "PR #6642", "PR #6773", "PR #6707", vllm_omni/config/endpoint_policy.py] @@ -55,3 +55,10 @@ confidence: high `tests/config/test_endpoint_policy.py`;API-server 路径仍仅为其 `ImportError` fallback 的静态合同。 PR 描述报告该 suite `4 passed`,批准 review 的边界是 static review、merge tree 与 CI,且明确未执行 untrusted fork code;因此不能扩展为完整 vLLM 版本兼容或端到端声明。^[PR #6707, merged 2026-09-02] + +## SERV-7e — realtime/video-stream 音频事件必须使用 `response.output_audio.*` + +- 触发:修改 realtime WebSocket、video stream serving、示例客户端或协议文档中的音频 delta/done 事件名。 +- 强制:服务端发出的增量与终态音频事件类型必须是 `response.output_audio.delta` / `response.output_audio.done`(及配套 transcript 命名),与已迁移的 OpenAI realtime 合同一致;示例与测试断言同一集合。 +- 禁止:在任一生产发送路径残留 legacy `response.audio.delta` / `response.audio.done`;只改文档/示例而漏改 `realtime_connection` 或 `serving_video_stream`/`video_stream_base`。 +- 验收:duplex/realtime/video-stream 测试收集到的音频事件类型集合等于 `response.output_audio.*`,且不接受仅 legacy 名作为成功合同。^[PR #7426] diff --git a/knowledge/repos/vllm-omni/models/cosmos3/rules.md b/knowledge/repos/vllm-omni/models/cosmos3/rules.md index 2b1008121..c995beeb1 100644 --- a/knowledge/repos/vllm-omni/models/cosmos3/rules.md +++ b/knowledge/repos/vllm-omni/models/cosmos3/rules.md @@ -1,7 +1,7 @@ --- title: "Cosmos3 规则" created: 2026-07-20 -updated: 2026-09-05 +updated: 2026-09-14 type: rule tags: [vllm-omni, models, diffusion] sources: ["PR #4657", "PR #5001", "PR #5634", "PR #6049", docs/features/session_state_manager.md, recipes/cosmos3/Cosmos3-Nano.md, vllm_omni/diffusion/models/cosmos3/, vllm_omni/model_extras/cosmos3.py, vllm_omni/model_extras/registry.py, vllm_omni/experimental/world_models/adapters/state_cosmos3_adapter.py, vllm_omni/platforms/rocm/platform.py, tests/diffusion/models/cosmos3/test_session_memory_equivalence.py, tests/diffusion/models/cosmos3/test_cosmos3_pipeline.py, "PR #6107", "PR #5614", "PR #6325", "PR #6913", "PR #6920"] @@ -159,3 +159,10 @@ confidence: high 4×GB300 multi-chunk transfer(Ulysses 4、VAE patch parallelism 4、tiling,1280×720、101 frames、24 FPS、 53-frame chunks、5 conditional frames、2 steps),确认完成且 metadata/video 为 101 frames at 24 FPS。 该证据不构成广泛 parity、质量或性能声明。^[PR #6920] + +## COSMOS-1c — Distilled Cosmos3 必须在加载前拒绝 CFG parallel + +- 触发:scheduler `_class_name` 判定 distilled Cosmos3、修改 `cfg_parallel_size` admission,或 distilled 路径的 `guidance_scale` / `negative_prompt` 语义。 +- 强制:在加载 tokenizer/组件之前,若 distilled 且 `cfg_parallel_size > 1`,立即 `ValueError`,并指引 `--cfg-parallel-size 1` 与 `--ulysses-degree` 做多卡。distilled 路径强制 `guidance_scale=1.0`;调用方显式请求其他值时 `warning_once`,并说明 `negative_prompt` 不影响生成。 +- 禁止:静默忽略 CFGP 导致无收益的重复实例;先加载权重再报并行非法;把 distilled 的 guidance override 写成仍消费 negative branch。 +- 验收:参数化覆盖 distilled/non-distilled × `cfg_parallel_size`/`ulysses_degree`,断言 distilled+CFGP>1 在组件加载前失败;guidance resolver 覆盖显式非 1.0 的 warning 与强制 1.0。^[PR #7427]