diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index d02aba8da8..4b832123dc 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -507,7 +507,7 @@ jobs: group: loopx-python-test-shard-${{ matrix.shard }} queue: max cancel-in-progress: false - # All four shards were still progressing at 83-94% when the 45m job + # All shards were still progressing at 83-94% when the 45m job # deadline cancelled run 37916979857. Reserve setup/reporting headroom # without changing test-level deadlines, collection or worker count. timeout-minutes: 60 diff --git a/docs/development/testing-and-quality.md b/docs/development/testing-and-quality.md index 279516e9e6..9195c47f74 100644 --- a/docs/development/testing-and-quality.md +++ b/docs/development/testing-and-quality.md @@ -122,7 +122,7 @@ shell;不能因为过滤了 `CI` 就恢复采集。不能按系统、安装渠 `python-tests.yml` publishes `merge-gate` for every open pull request. Code, workflow, policy and unknown paths require the existing `pytest` aggregate -(including TypeScript checks and all four Python shards), Stage 2C correctness +(including TypeScript checks and all six Python shards), Stage 2C correctness aggregate, and Windows tests to succeed. Failed, cancelled, missing or unexpectedly skipped results cannot pass the gate. The client-only exception below retains common checks and substitutes packaged Dashboard qualification @@ -223,8 +223,8 @@ The [job exemption policy](ci-impact-selection.md) additionally permits pure Dashboard-client changes to skip backend Python/Windows and Stage2c, while requiring frontend type-check/build, scoped coverage and real packaged Dashboard browser smoke. Backend-only TS/lint/minimum-Node jobs are also exempt. -Mixed, prompt, dependency and unknown changes stay full. Full Python runs four -complete shards and combines all four coverage files. The `ci:full` label forces +Mixed, prompt, dependency and unknown changes stay full. Full Python runs six +complete shards and combines all six coverage files. The `ci:full` label forces full qualification; main stays full. No selected-only report impersonates full coverage. 新的前端豁免由目标分支已审阅的策略控制;CI 自身变更仍全量验证。 @@ -699,7 +699,7 @@ An explicitly loaded CI observer also streams pytest-owned phase durations from the xdist controller. Read the downloaded log with `node scripts/ci/pytest_timing.ts JOB_LOG`; incomplete evidence remains incomplete and does not replace JUnit, coverage or the required gate. See the -[timing observation boundary](ci-impact-selection.md#four-complete-python-shards). +[timing observation boundary](ci-impact-selection.md#six-complete-python-shards). Full Python shards also opt into `--ci-stall-after 120` on the existing pytest observer: a long-running test attempts to print its executing thread's Python stack without terminating it or changing its result. This cooperative diagnostic needs the @@ -730,7 +730,7 @@ Linux 全套测试分到六台 hosted runner,每台保留两个 xdist worker CI 同时在 xdist controller 流式记录 pytest 原生 phase 耗时。下载日志后用 `node scripts/ci/pytest_timing.ts JOB_LOG` 回读;不完整证据保持不完整,不能替代 JUnit、coverage 或必过门禁。归属与测量边界见 -[分片耗时记录](ci-impact-selection.md#four-complete-python-shards)。 +[分片耗时记录](ci-impact-selection.md#six-complete-python-shards)。 全量 Python 分片在既有 pytest observer 上显式启用 `--ci-stall-after 120`:测试 超过该时长就尝试输出其执行线程的 Python 栈,不终止测试或改变结果。此协作式诊断 需要解释器调度观察线程,无法诊断始终占有 GIL 的原生代码。栈用于诊断,不能只凭 diff --git a/scripts/ci/test_review_gate.py b/scripts/ci/test_review_gate.py index 7afface007..9efe533523 100644 --- a/scripts/ci/test_review_gate.py +++ b/scripts/ci/test_review_gate.py @@ -58,7 +58,7 @@ def test_closed_pr_cancels_same_lane_and_skips_qualification(self): def expression(value, action, *, number=17, event="pull_request"): ref = "refs/heads/main" if action == "closed" or event != "pull_request" else f"refs/pull/{number}/merge" github = SimpleNamespace(event_name=event, ref=ref, event=SimpleNamespace( - action=action, number=number, pull_request=None)) + action=action, number=number, pull_request=SimpleNamespace(number=number))) return eval(value.strip().removeprefix("${{").removesuffix("}}").strip() .replace("&&", "and").replace("||", "or").replace("!cancelled()", "not cancelled()"), {"__builtins__": {}}, {"github": github, "always": lambda: True,