fix(ci): retain and retry the observed Playwright runtime corruption
CI and Deploy / test (push) Failing after 1h18m39s
CI and Deploy / deploy (push) Has been skipped

This commit is contained in:
cesnimda
2026-10-20 15:17:02 +02:00
parent cc7977131a
commit d1fcd23087
3 changed files with 69 additions and 3 deletions
+11 -3
View File
@@ -312,9 +312,16 @@ jobs:
# checksum-valid npm download (`true` became `tr<garbage>e`, or a stray `break` appeared). # checksum-valid npm download (`true` became `tr<garbage>e`, or a stray `break` appeared).
# Retry only that unmistakable source-corruption signature from a new isolated cache. # Retry only that unmistakable source-corruption signature from a new isolated cache.
# Ordinary Axe violations and application assertions remain terminal. # Ordinary Axe violations and application assertions remain terminal.
if grep -q "AxeBuilder.analyze" "$smoke_log" \ if { grep -q "AxeBuilder.analyze" "$smoke_log" \
&& grep -Eq "page\.evaluate: (ReferenceError|SyntaxError)" "$smoke_log"; then && grep -Eq "page\.evaluate: (ReferenceError|SyntaxError)" "$smoke_log"; } \
echo "Axe runtime source appears corrupted — reinstalling the locked dependencies from a fresh cache and retrying the complete suite once..." || { grep -Eq 'node_modules/playwright-core/lib/utilsBundle\.js:[0-9]+' "$smoke_log" \
&& grep -Fq 'const { items }$= this;' "$smoke_log" \
&& grep -Fq 'SyntaxError: Missing initializer in destructuring declaration' "$smoke_log"; }; then
echo "Browser runtime source appears corrupted — reinstalling the locked dependencies from a fresh cache and retrying the complete suite once..."
mkdir -p .artifacts/browser-runtime-attempt-1
cp "$smoke_log" .artifacts/browser-runtime-attempt-1/smoke.log
if [ -d test-results ]; then cp -a test-results .artifacts/browser-runtime-attempt-1/; fi
if [ -f .artifacts/playwright-results.json ]; then cp .artifacts/playwright-results.json .artifacts/browser-runtime-attempt-1/; fi
rm -rf node_modules rm -rf node_modules
npm_cache="$(mktemp -d)" npm_cache="$(mktemp -d)"
npm ci --no-audit --no-fund --cache "$npm_cache" npm ci --no-audit --no-fund --cache "$npm_cache"
@@ -336,6 +343,7 @@ jobs:
name: browser-diagnostics name: browser-diagnostics
path: | path: |
job-tracker-ui/.artifacts/playwright-results.json job-tracker-ui/.artifacts/playwright-results.json
job-tracker-ui/.artifacts/browser-runtime-attempt-1/
job-tracker-ui/test-results job-tracker-ui/test-results
retention-days: 7 retention-days: 7
@@ -0,0 +1,9 @@
# Playwright runtime corruption signature — 20 October 2026
Corrected release run831 did not reach deployment. Its browser lane encountered Chromium target crashes and an installed Playwright parser failure at `node_modules/playwright-core/lib/utilsBundle.js:35841`: `const { items }$= this;`, followed by `SyntaxError: Missing initializer in destructuring declaration`. A worker then exited before executing its cases. Only46 browser attempts appear in the terminal log; this is not a completed331-case regression. An ordinary preview-visibility assertion also failed and is retained, rather than labelled an infrastructure success.
This resembles earlier runner dependency/download corruption, but the job container was removed before its installed bytes could be compared with the lockfile archive. Neither persistent filesystem corruption nor faulty hardware is proven. The full900-entry diagnostic ZIP was downloaded and CRC-checked: SHA256 `f6d8e9659ca824bb12d283913f6e16f3933974bbc5e11c78e3524d8712e75632`. Original logs and traces remain retained.
The workflow already allows one complete-suite retry after its narrowly recognized Axe source-corruption signature, using a new npm cache and the unchanged lockfile. Extend that same bounded policy only when all three observed Playwright indicators occur together: the exact dependency path/line marker, the exact malformed statement and the exact parser error. Ordinary application assertion failures, target crashes alone, user-source syntax errors and incomplete signatures remain terminal. The six policy tests execute the actual Bash guard and pass. No assertion, browser inventory, timeout, ordinary retry, dependency integrity or release gate is relaxed.
Before the existing reinstall/retry, preserve the first smoke log, JSON report if available and complete traces/screenshots under `.artifacts/browser-runtime-attempt-1`; include them in the same always-uploaded artifact. A subsequent successful retry must still complete the entire browser suite; failure remains blocking. This does not repair or qualify the underlying runner, prove the preview assertion resolved or establish deployment success. Production/operator, physical hardware/runtime and manual application qualifications remain open. P5-13 and model activation are unchanged.
+49
View File
@@ -0,0 +1,49 @@
"""Exercise the actual workflow's narrow corruption guard, without starting CI."""
import os
from pathlib import Path
import shutil
import subprocess
import tempfile
import unittest
WORKFLOW = Path(__file__).resolve().parents[1] / '.gitea/workflows/ci-deploy.yml'
BASH = str(Path('C:/Program Files/Git/bin/bash.exe')) if os.name == 'nt' else shutil.which('bash')
class BrowserRuntimeRetryTests(unittest.TestCase):
def permits_retry(self, log):
text = WORKFLOW.read_text(encoding='utf-8')
end = text.index(' echo "Browser runtime source appears corrupted')
start = text.rfind('\n if ', 0, end) + 1
guard = text[start:end]
self.assertTrue(guard.strip().startswith('if '))
with tempfile.TemporaryDirectory() as folder:
fixture = Path(folder) / 'smoke.log'
fixture.write_text(log, encoding='utf-8')
result = subprocess.run([BASH, '-c', guard + '\nexit 0\nelse\nexit 1\nfi'],
env={**os.environ, 'smoke_log': fixture.as_posix()}, capture_output=True, text=True)
self.assertIn(result.returncode, [0, 1], result.stderr)
return result.returncode == 0
def test_captured_playwright_source_corruption(self):
self.assertTrue(self.permits_retry('/workspace/node_modules/playwright-core/lib/utilsBundle.js:35841\n'
'const { items }$= this;\nSyntaxError: Missing initializer in destructuring declaration'))
def test_existing_axe_source_corruption(self):
self.assertTrue(self.permits_retry('AxeBuilder.analyze\npage.evaluate: ReferenceError: invalid runtime source'))
def test_application_assertion_stays_terminal(self):
self.assertFalse(self.permits_retry('expect(region).not.toBeVisible() failed'))
def test_browser_crash_alone_stays_terminal(self):
self.assertFalse(self.permits_retry('Error: page.evaluate: Target crashed'))
def test_user_javascript_syntax_error_stays_terminal(self):
self.assertFalse(self.permits_retry('src/example.js:1\nconst { items }$= this;\nSyntaxError: Missing initializer in destructuring declaration'))
def test_incomplete_signature_stays_terminal(self):
self.assertFalse(self.permits_retry('node_modules/playwright-core/lib/utilsBundle.js:35841\nSyntaxError: Missing initializer in destructuring declaration'))
if __name__ == '__main__':
unittest.main()