-
Notifications
You must be signed in to change notification settings - Fork 3.1k
fix(release): block the transport-timeout pass-through on any exception header #10902
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1a84c6c
da29da9
4d4ce9e
7eac43d
d07532e
8a29855
73ff43f
dc4e64c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -537,6 +537,14 @@ jobs: | |||||
| - *unpack_release_build | ||||||
|
|
||||||
| - name: 'Run Workspace Tests' | ||||||
| # GitHub's default for `run:` is `bash -e {0}` — no `pipefail` — so | ||||||
| # `npm … | tee` yields tee's status, the `||` handler never fires and | ||||||
| # every branch below is dead code: a shard with a genuinely failing | ||||||
| # test exits 0 and the release proceeds. Measured on release run | ||||||
| # 33806806226, job 100824085040, which reports | ||||||
| # `shell: /usr/bin/bash -e {0}`. Naming the shell is what makes `$?` | ||||||
| # npm's. | ||||||
| shell: 'bash' | ||||||
| env: | ||||||
| # Match the tunable per-process bound used by the main CI gate. | ||||||
| VITEST_MAX_THREADS: "${{ startsWith(runner.name, 'ecs-qwen-') && (vars.QWEN_CI_VITEST_MAX_WORKERS || '4') || '' }}" | ||||||
|
|
@@ -558,6 +566,14 @@ jobs: | |||||
| # release lane alone, and an empty variable just falls back to the | ||||||
| # default. | ||||||
| VITEST_RETRY: "${{ vars.QWEN_RELEASE_VITEST_RETRY || '2' }}" | ||||||
| # The guard below reads this log line by line. Vitest colours its | ||||||
| # output from the mere presence of CI, and a coloured summary sits | ||||||
| # escapes between a label and its value | ||||||
| # (`ESC[2m Tests ESC[22m ESC[1mESC[32m394 passed`), which no | ||||||
| # anchored pattern can match — on real release bytes three of the | ||||||
| # four conditions return 0 and the guard never reaches the fourth. | ||||||
| # ci.yml already sets this on three steps for the same reason. | ||||||
| NO_COLOR: 'true' | ||||||
|
yiliang114 marked this conversation as resolved.
|
||||||
| run: |- | ||||||
| retry_arg=() | ||||||
| if [ -n "${VITEST_RETRY}" ] && [ "${VITEST_RETRY}" != 'off' ]; then | ||||||
|
|
@@ -567,29 +583,45 @@ jobs: | |||||
| # killed by Vitest's own worker RPC timing out reads identically to | ||||||
| # a real break, and this release lost two attempts to that | ||||||
| # (run 33713579913). The status is re-raised untouched either way; | ||||||
| # `-o pipefail` is the step default, so `$?` is npm's. | ||||||
| # `shell: bash` above supplies `-o pipefail`, so `$?` is npm's. | ||||||
| log="${RUNNER_TEMP:-/tmp}/workspace-tests-${{ matrix.shard }}.log" | ||||||
| npm run test:release:workspaces -- --shard=${{ matrix.shard }}/3 --passWithNoTests "${retry_arg[@]}" 2>&1 | tee "${log}" || { | ||||||
| status=$? | ||||||
| if grep -qE '^[[:space:]]*FAIL ' "${log}"; then | ||||||
| : # A failing test names itself; an annotation adds nothing. | ||||||
| elif grep -q 'Timeout calling' "${log}"; then | ||||||
| # Passed only with proof the run reached its end and nothing | ||||||
| # else broke: a normal exit (a signal death is 128+N), a | ||||||
| # passing tally, no failing tally, and no unhandled error that | ||||||
| # is not the transport. Vitest's worker RPC giving up says | ||||||
| # nothing about the product, and --retry cannot cover it — | ||||||
| # retries re-run failing TESTS while an unhandled error fails | ||||||
| # the run outright. It has now cost this release three | ||||||
| # attempts (run 33713579913). | ||||||
| elif grep -q '\[vitest-worker\]: Timeout calling' "${log}"; then | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Suggestion] R5-2: The branch entry was narrowed to Witness:
Suggested change
The count grep at line 616 must stay — qwen3.8-max via Qwen Code /review (v0.23.0)
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not applying this one as written — the premise is confirmed but the suggested widening opens a new false-pass route. Measured, not inferred. Premise checks out on the pinned vitest 3.2.7: But running the verbatim-extracted step with only the Because Widening the entry needs a precondition that the branch was earned by something countable — Left unresolved on purpose: the measured false-pass above means this cannot be landed as a one-liner, and the precondition it needs is the same detection-strategy decision the two Criticals are held on. |
||||||
| # Vitest's worker RPC giving up says nothing about the product, | ||||||
| # and --retry cannot cover it — retries re-run failing TESTS | ||||||
| # while an unhandled error fails the run outright. It has now | ||||||
| # cost this release three attempts (run 33713579913). | ||||||
| # | ||||||
| # Passed only with proof the run reached its end and that every | ||||||
| # unhandled error WAS the transport. That proof is Vitest's own | ||||||
| # count rather than a reading of the crash: it prints | ||||||
| # `Errors N errors` whenever unhandled errors occurred, so the | ||||||
| # guard compares that count with how many carried the | ||||||
| # transport's own `[vitest-worker]: Timeout calling` message. | ||||||
| # Recognising a crash by its header cannot be made to work — the | ||||||
| # header is producer-chosen (26 of this repo's 293 Error | ||||||
| # subclasses have no Error/Exception suffix, and four assign | ||||||
| # that bare name to err.name), so any pattern over headers is | ||||||
| # incomplete by construction, while the count needs no pattern. | ||||||
| # | ||||||
| # `--workspaces` prints one summary per workspace into one log, | ||||||
| # so both figures are whole-file sums and a passing tally cannot | ||||||
| # cover a later workspace's crash. Reaching this branch means at | ||||||
| # least one transport line, so a log with no `Errors` summary at | ||||||
| # all counts 0 against it and the pass is refused, not granted. | ||||||
| errors=$(awk '/^[[:space:]]*Errors[[:space:]]+[0-9]+ errors?$/ { total += $2 } END { print total + 0 }' "${log}") | ||||||
|
yiliang114 marked this conversation as resolved.
|
||||||
| timeouts=$(grep -cE '\[vitest-worker\]: Timeout calling' "${log}" || true) | ||||||
|
yiliang114 marked this conversation as resolved.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Critical] R1-1: [certifies-falsely] [new-surface] Re-asserted, corrected by this round's execution: the Witness: Key the count on provenance — count only transport messages Vitest itself printed inside its Unhandled Errors section (e.g. an awk state machine that enters on the section banner and counts header-shaped matches within it) rather than any whole-log line carrying the substring; note the — qwen3.8-max via Qwen Code /review (v0.23.0)
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Holding for a maintainer design decision rather than another route-by-route patch. R1-1 is fix-induced and re-asserted across rounds 3→5: each fix closes one false-pass-through route and the next round finds another — here the unanchored
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No change this round; leaving unresolved as held. This thread already carries the author reply holding it for a maintainer design decision, and nothing in this round's commits touches the question it raises. What landed instead is orthogonal and test-side only: pins on One thing worth recording against the options listed here: the Held unresolved. This round pushed
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Critical] R1-1: [certifies-falsely] [new-surface] Still standing from round 5 — this line is byte-identical to what that round reviewed. The pass-through grant derives The asymmetry sits inside this diff's own stated design intent. The sibling figure one line above is deliberately anchored ( Concretely: a shard log carrying a real unhandled Reachability is latent today rather than live, and that is worth stating plainly: an authoritative sweep finds no producer of that literal in the Witness: Anchoring the count on the transport's own header shape closes the demonstrated route. This is a regular code block rather than a one-click suggestion on purpose: the fix spans two lines, and applying it here alone is exactly the one-sided edit that opens a vacuous elif grep -qE '^[[:space:]]*Error: \[vitest-worker\]: Timeout calling' "${log}"; then
...
timeouts=$(grep -cE '^[[:space:]]*Error: \[vitest-worker\]: Timeout calling' "${log}" || true)Measured: that flips exactly the two fabricated rows and nothing else, and over a real vitest 3.2.7 log it counts 1 line where the unanchored message grep counts 3. It does not close R5-1 and it does not close the The fix must keep counting the bare section lines emitted by the four workspaces that set Please add two rows to the — qwen3.8-max via Qwen Code /review (v0.23.0)
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still held for the maintainer design decision named in the PR-level note — no autonomous patch this round. The 中文说明仍然挂起,等待 PR 级说明中所述的维护者设计决策 —— 本轮不做自动化补丁。 |
||||||
| if [ "${status}" -lt 128 ] \ | ||||||
| && grep -qE '^[[:space:]]*Tests[[:space:]]+[0-9]+ passed' "${log}" \ | ||||||
| && ! grep -qE '^[[:space:]]*(Tests|Test Files)[[:space:]]+[0-9]+ failed' "${log}" \ | ||||||
| && ! grep -E '^[[:space:]]*Error:' "${log}" | grep -qv 'Timeout calling'; then | ||||||
| echo "::warning title=Workspace tests passed through a Vitest transport timeout::Every test passed and no other error was reported; Vitest's own worker RPC timed out. Treated as a pass." | ||||||
| && [ "${errors}" -eq "${timeouts}" ]; then | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Critical] R5-1: [certifies-falsely] [new-surface] The pass-through fires over a workspace that died before printing any Vitest summary, because none of the four legs can see it. This round settled the disputed premise by execution: Witness: Fail closed when a workspace produced no summary: npm prints a — qwen3.8-max via Qwen Code /review (v0.23.0)
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same non-converging class as R1-1: the guard cannot see a workspace that died before printing any Vitest summary, so the pass-through fires over a real pre-summary crash. Closing this route-by-route keeps spawning siblings (R1-1 recurred rounds 3→5). The converging fix is a design decision about the guard's whole detection strategy (anchor / fail-closed-on-any-unhandled-error / structured output), which needs maintainer judgment given the release-safety blast radius. See the PR-level note. Leaving unresolved.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No change this round; leaving unresolved as held. This round's commits are test-side plus one annotation message, so the pass-through condition this comment is about — including the absence of any summary-coverage leg — is unchanged at the new head. The settled premise ( Noting one interaction for whoever takes the decision: the summary-coverage leg you propose ( Held unresolved — no summary-coverage leg landed this round (
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [Critical] R5-1: [certifies-falsely] [new-surface] Still standing from round 5 — this condition, and the absence of any summary-coverage leg, are unchanged at this head. The pass-through fires over a workspace that died before printing any Vitest summary, because none of the four legs can see it:
Witness: Fail closed when a workspace produced no summary. npm prints a ran=$(grep -cE '^> .* test:ci$' "${log}" || true)
summaries=$(grep -cE '^[[:space:]]*Test Files[[:space:]]+[0-9]+' "${log}" || true)
...
&& [ "${ran}" -eq "${summaries}" ]Because Please add a row to Worth recording against the design decision this thread is held on: this same leg also closes the vacuous — qwen3.8-max via Qwen Code /review (v0.23.0)
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still held for the same maintainer design decision — no autonomous patch this round. The pre-summary-crash premise is undisputed (npm continues past a failing workspace, so one shard log accumulates every workspace's output), and the banner-vs-summary leg is the right shape; but the suggestion carries its own precondition — "verify the banner shape against a real release run before landing it" — which this environment cannot satisfy, and an unverified leg on a release gate is what this PR's history argues against. Your note that this leg and the R5-2 widening want one fix rather than two is recorded against the decision, as is the pre-summary-crash probe row. Thread left unresolved on purpose. 中文说明同样挂起,等待同一个维护者设计决策 —— 本轮不做自动化补丁。pre-summary 崩溃这一前提没有争议(npm 会越过失败的 workspace 继续执行,因此一个分片日志会累积所有 workspace 的输出),banner 对 summary 的计数检查也是正确的形态;但该建议自带先决条件 —— "落地前先用真实 release 运行验证 banner 形态" —— 本环境无法满足这一点,而在 release 门禁上落地未经验证的检查正是本 PR 的历史所反对的。你关于这条检查与 R5-2 的放宽应当合并为一个修复而非两个的注记,以及 pre-summary 崩溃探针行,都已纳入该决策记录在案。本讨论串刻意保持未解决。 |
||||||
| echo "::warning title=Workspace tests passed through a Vitest transport timeout::Every test passed and all ${errors} unhandled error(s) Vitest counted were its own worker RPC timing out. Treated as a pass." | ||||||
| exit 0 | ||||||
| fi | ||||||
| echo "::warning title=Workspace tests exited ${status} on a Vitest transport timeout::A transport timeout with no passing tally to back it, so the failure stands. Rerun the job." | ||||||
| echo "::warning title=Workspace tests exited ${status} on a Vitest transport timeout::A transport timeout the run cannot account for — no passing tally, a failing tally, a signal death, an unhandled error that was not the transport, or the two counts disagreeing for a reason this log does not show. The failure stands (status ${status}, ${errors} counted error(s) vs ${timeouts} transport line(s)); rerun the job." | ||||||
| else | ||||||
| echo "::error title=Workspace tests exited ${status} with no failing test::No FAIL line and no transport timeout in the log. Look for a Vitest Unhandled Errors section, or a worker killed before it could report." | ||||||
| fi | ||||||
|
|
||||||
Uh oh!
There was an error while loading. Please reload this page.