LearnNewsExamplesServices
Frontmatter
id16161
titleE2E lifecycle receipt does not normalize rejected Chrome launch exits
stateClosed
labels
bugdeveloper-experienceaitesting
assigneesneo-gpt-emmy
createdAtJul 30, 2026, 11:59 AM
updatedAtJul 30, 2026, 1:11 PM
githubUrlhttps://github.com/neomjs/neo/issues/16161
authorneo-gpt-emmy
commentsCount0
parentIssue16151
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtJul 30, 2026, 1:11 PM

E2E lifecycle receipt does not normalize rejected Chrome launch exits

Closed Backlog/active-chunk-11 bugdeveloper-experienceaitesting
neo-gpt-emmy
neo-gpt-emmy commented on Jul 30, 2026, 11:59 AM

Context

Parent #16151 retained a real macOS Google Chrome startup abort whose faulting path is _RegisterApplication → TransformProcessType → ChromeMain. The process died before Playwright yielded a usable Browser fixture.

The E2E runner already exposes enough bounded evidence to make this class machine-readable:

  • Playwright 1.61.1 races browser readiness against process exit. When launch rejects, its error includes <process did exit: exitCode=..., signal=...> in the browser log.
  • Reporter onError(error, workerInfo) receives errors outside test execution plus the producing project when Playwright can bind one.
  • Reporter onTestEnd(test, result) receives fixture-launch failures bound to the exact test project.
  • Existing local error artifacts preserve this shape for the related early-exit family, including signal=SIGTRAP, no yielded Browser fixture, forced-kill escalation, and kill EPERM.

Neo's test/playwright/e2e/custom-reporter.js currently writes static system/project information at run start and a terminal count to stdout. It does not normalize either reporter error path into the retained benchmark-system-info.json receipt. The generic Playwright report can contain the raw multi-line error, but downstream diagnosis must rediscover project, launch profile, transport state, exit code, and signal by scraping prose.

The first focused unit run also exposed a prerequisite in that same owner: on this restricted Codex seat, Node's os.uptime() throws EPERM. The reporter reads it outside its existing best-effort system-info guard, so onBegin() aborts before creating the JSON receipt. Optional host telemetry must not erase mandatory lifecycle evidence.

Live duplicate sweep: the latest open queue plus searches for pre-transport Chrome exit provenance, browser launch exit signal Playwright reporter, and RegisterApplication SIGABRT reporter found only parent #16151 and its single-owner child #16159.

The Problem

An early Chrome process exit already fails the affected test, but Neo retains no small, privacy-bounded lifecycle record that answers:

  • which Playwright project owned the launch;
  • which Neo E2E launch profile was active;
  • whether a usable Browser fixture was ever established;
  • which exit code or signal Playwright observed;
  • whether the same event surfaced through both reporter paths.

The missing normalization is why a macOS dialog can become the practical diagnostic surface even though the runner already held more precise launch-boundary evidence.

The Architectural Reality

  • Playwright owns browser creation and graceful/forced cleanup for ordinary test fixtures.
  • The E2E reporter owns run-level retained diagnostic metadata.
  • Playwright can construct a pipe transport before connectToTransport() rejects. Reporter callbacks do not expose that internal boundary, so transport state must be recorded as not-observable.
  • A reporter must classify only the exact rejected-launch process-exit shape. A generic browser has been closed error can occur after a healthy transport and must not be relabeled.
  • The process-exit line is the authoritative code/signal source. Absence must remain null, never be guessed from platform or dialog timing.
  • Reporter callbacks can surface the same failure twice; one process event must produce one receipt.
  • Raw launch command lines and user-data paths are not needed for this contract and must not be copied into the normalized record.

The Fix

  1. Add a pure classifier to the existing E2E reporter for Playwright's exact rejected-launch process-exit shape.
  2. Make nonessential host facts, including uptime and macOS CPU probes, fail soft without emitting shell noise or preventing the run receipt.
  3. Capture both onError(error, workerInfo) and onTestEnd(test, result) so global/fixture launch failures share one path.
  4. Retain a deduplicated browserLifecycle.launchExits collection in benchmark-system-info.json with project, Neo launch profile, browserObjectEstablished: false, transportState: not-observable, exit code, signal, abnormal/clean disposition, and a bounded classification—not the raw command line. Persist when the incident arrives, not only at terminal.
  5. Unit-test positive parsing, negative classification, profile binding, duplicate collapse, and the restricted-host telemetry fallback.
  6. Run one controlled non-GUI early-exit falsifier using a process that exits before Playwright yields a Browser; the runner must fail and the retained receipt must name the project/profile/code without launching a visible browser.

Contract Ledger

Target Surface Source of Authority Proposed Behavior Fallback Docs Evidence
Browser launch rejection with process exit Playwright browser startup log + reporter worker/test project Persist one bounded lifecycle record Keep the ordinary Playwright failure; unknown fields remain null Reporter JSDoc Pure parser units + controlled non-GUI exit
Healthy or post-launch browser error Exact classifier boundary No rejected-launch record Generic Playwright reporting remains authoritative Inline avoided-trap guard Negative unit corpus
Duplicate reporter delivery Normalized incident identity Collapse to one record Preserve first bounded source attribution Reporter JSDoc Duplicate-delivery unit
Operator/browser privacy Neo E2E receipt contract Store no raw command line, URL, title, profile path, or personal browser content Omit rather than broaden Ticket + JSDoc Serialized-receipt assertion
Restricted host telemetry Existing reporter system-info block Optional facts fail soft and lifecycle receipt still writes null/existing fallback, no shell noise Reporter JSDoc Injected/seat EPERM unit

Decision Record impact

none.

Acceptance Criteria

  • A browser-launch rejection plus non-clean process-exit line classifies as a launch exit.
  • The receipt records project, active Neo E2E profile, browserObjectEstablished: false, transportState: not-observable, exit code, and signal; unavailable values remain null.
  • A generic post-launch disconnect and an unrelated normal teardown do not classify; a clean process exit coupled to a rejected browserType.launch() still records with abnormal: false.
  • Delivery through both reporter hooks produces one retained incident.
  • The serialized receipt excludes raw launch command lines, URLs, titles, user-data paths, and personal browser content.
  • An os.uptime()/platform-probe failure cannot prevent the bounded JSON receipt; unavailable optional host facts fail soft without shell noise.
  • A controlled non-GUI process exit fails the Playwright run and creates the expected launch receipt without claiming transport state.
  • Existing E2E reporter output and focused unit coverage remain green.

Out of Scope

  • Reading or deleting macOS DiagnosticReports.
  • Suppressing crash dialogs.
  • Changing Playwright's browser ownership or cleanup implementation.
  • Adding launch admission, sleeps, process-name cleanup, or a shared browser server.
  • Proving the root cause of _RegisterApplication aborts.
  • Replacing the generic JSON/HTML Playwright reporters.

Avoided Traps

  • Do not infer transport state from browserType.launch() rejecting.
  • Do not classify every browser has been closed string as a launch-process exit.
  • Do not infer SIGABRT from the platform or dialog.
  • Do not persist the raw launch command line merely because Playwright includes it.
  • Do not create a second browser lifecycle to test the reporter.
  • Do not turn a diagnostic reporter into the browser owner.

Related

  • Parent: #16151
  • #16159 / PR #16160 — removes the redundant no-op presenting owner.
  • #15664 / #15813 — distinct GPU SIGTRAP family whose artifacts establish the same Playwright process-exit log grammar.

Origin Session ID: 019fac4d-7844-7422-9486-7f73ccf308f5

Retrieval Hint: "Playwright reporter rejected browser launch process exit project profile signal"

tobiu referenced in commit 0974e03 - "fix(testing): retain rejected Chrome launch exits (#16161) (#16162) on Jul 30, 2026, 1:11 PM
tobiu closed this issue on Jul 30, 2026, 1:11 PM