fix(tools): fail-loud native-crash retry for test:coverage:check (#1278) - #1292
Merged
Conversation
The deno test --coverage subprocess has died by SIGSEGV (exit 139) three times under load with no test assertion failure, blocking a release-tier gate by random crash. Classify the test-run exit: codes below 128 are real failures and fail immediately without retry; signal exits (128 + signo) are retried up to --crash-retries (default 2), each crash reported loudly on stderr, and crash exhaustion fails the gate explicitly. Coverage semantics unchanged: thresholds, scopes and full denominator untouched.
Deploying openelement with
|
| Latest commit: |
20edcaa
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://b65fca80.lessjs.pages.dev |
| Branch Preview URL: | https://fix-1278-coverage-sigsegv-re.lessjs.pages.dev |
Contributor
|
APIError: Insufficient Balance |
This was referenced Sep 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1278
Problem
test:coverage:checkhas died by SIGSEGV (exit 139) three times — Beta.1 CI run 33715486563 at 73a7900, a local run at 18778c9, and the first autoflow-ci run of PR #1291 (rerun green). Each time the crash was in thedeno test --coveragesubprocess (tools/check-coverage.tsreported "tests failed with code 139") while every other gate passed: a native-binding crash (rolldown/workerd class) under load, not a product signal. The gate is release-tier (tiers: ['ci', 'release']intools/autoflow/policy.ts), so a random crash could block a release.Owner
v0.44 implementer (B2.13 early slice under stage issue #1288, umbrella #1155).
Before
Any non-zero exit from the coverage test run — assertion failure or native crash alike — threw
tests failed with code Nand failed the gate on the first occurrence. A random SIGSEGV blocked the gate exactly like a real regression, and a silent manual rerun hid the flake from the record.After
tools/check-coverage.tsclassifies the test-run exit code:--crash-retries 2, i.e. max 3 attempts). Each retry starts from a clean.coverage-checkdir so a crashed attempt can't poisondeno coveragewith partial profiles.[check-coverage] NATIVE CRASH … attempt N/M (#1278)), and a recovered run prints a closing WARNING with the crash count — flakes stay visible and countable in CI logs.Coverage semantics are untouched: thresholds, scopes, and the full-denominator logic are unchanged.
Why tool-level retry, not workflow-level
The gate reaches CI and release exclusively through the autoflow policy command
deno task test:coverage:check(tools/autoflow/policy.ts,deno task autoflow:ciin.github/workflows/autoflow-ci.yml). Putting the retry inside the tool means:Why-not-second-owner
Bounded single-owner slice: one tool file plus its new test file; no frozen-semantics paths (
freeze:semantics:checkgreen), no workflow or governance edits.Root-cause investigation
Attempted, not cheaply reachable:
deno testalready runs test modules serially by default (verified locally: two 2 s test files take ~4 s with and withoutDENO_JOBS=1). The concurrency is inside tests — spawned subprocesses exercising npm/native bindings — so runner-level serialization is not a reachable fix.The fail-loud retry is therefore the delivered fix; the loud crash counter keeps the flake measurable so a future root-cause attempt has data.
Evidence
tools/check-coverage.test.ts(7 tests, all green): exit classification; crash-without-assertion-failure retries then passes with per-crash reports; assertion failure fails immediately with the runner invoked exactly once; crash exhaustion after the bounded attempt count fails loudly;maxAttemptsvalidation.deno runchildren exiting 139/1/0):crashes=2, two loud reports, exit 0tests failed with code 1, immediate, exit 1, no retrydeno task test:coverage:check(runs the entire repo suite incl. the new tests): PASS, all thresholds met (packages: 81.94/85.12/90.13%; tools/lib: 77.56/85.92/79.22%).deno fmt --check,deno lint,deno checkon touched files: clean.deno task arch:check,type-safety:check,text-integrity:check,freeze:semantics:check: PASS.deno task pack:dry-runanddeno task package-artifacts:check: PASS.Scope
tools/check-coverage.ts— exit classification + bounded fail-loud retry;--crash-retriesflag (default 2).tools/check-coverage.test.ts— new, proves the retry contract.Risk
Low. Worst case a native crash adds up to two extra full test runs before the gate fails (bounded, and each crash is loud in logs). Real failures are never retried. If the crash turns out to be deterministic rather than flaky, the gate still fails after 3 attempts — fail-closed, never silent PASS.