fix(browser): prove PID-safe browser crash recovery evidence - #148
Conversation
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: trueThanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
OpenCode cannot approve yet because required coverage evidence did not pass.
Review outcome
1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence
-
Problem: The required coverage-evidence job result was
failure, so OpenCode cannot establish approval sufficiency for this head. -
Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.
-
Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports
successwith required evidence or explicit no-source not-applicable evidence. -
Regression test: Keep the approval branch checking
needs.coverage-evidence.result == successbefore posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present. -
Result: REQUEST_CHANGES
-
Reason: coverage-evidence result was
failure, so required test/docstring evidence was not proven for current headcb49d4c6c26b32e2bdab5634622624b47a6ca8f3. -
Head SHA:
cb49d4c6c26b32e2bdab5634622624b47a6ca8f3 -
Workflow run: 32237343063
-
Workflow attempt: 1
Coverage evidence
Coverage Decision
- Result: FAIL
- Test evidence: not proven passing
- Docstring evidence: not proven passing when configured
- Failure count: 1
Changed-File Evidence Map
flowchart LR
PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
Evidence --> S1["CI script: run_mv3_compatibility.py"]
S1 --> I1["review and security gate shell path"]
I1 --> R1["Review risk: CI script: run_mv3_compatibility.py"]
R1 --> V1["bash -n plus Strix self-test"]
Evidence --> S2["Test: test_agent_task_browser_crash_recovery_contract.py"]
S2 --> I2["regression suite"]
I2 --> R2["Review risk: Test: test_agent_task_browser_crash_recovery_contract.py"]
R2 --> V2["targeted test run"]
OpenCode Review Overview
Pull request overviewOpenCode cannot approve yet because required coverage evidence did not pass. Review outcome1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence
Coverage evidenceCoverage Decision
Changed-File Evidence Mapflowchart LR
PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
Evidence --> S1["CI script: run_mv3_compatibility.py"]
S1 --> I1["review and security gate shell path"]
I1 --> R1["Review risk: CI script: run_mv3_compatibility.py"]
R1 --> V1["bash -n plus Strix self-test"]
Evidence --> S2["Test: test_agent_task_browser_crash_recovery_contract.py"]
S2 --> I2["regression suite"]
I2 --> R2["Review risk: Test: test_agent_task_browser_crash_recovery_contract.py"]
R2 --> V2["targeted test run"]
|
Ordinarily merge #148 at 0135984 after the inherited sandbox contract reproduced RED. Preserve every parent production change and the existing ordinary shared-deadline delta, child tests, failure evidence and exact process identity boundaries. All 253 Linux Python contracts pass without skips; full Rust 1.97.1 gates and numerical production coverage remain 100%. Keep Draft and the canonical workflow startup failure distinct from source verification. No workflow, dependency, timeout or acceptance-gate change. Commit-Message-Assisted-by: Codex (via Codex) Signed-off-by: Seongho Bae <me@seonghobae.me>
seonghobae
left a comment
There was a problem hiding this comment.
Current-head operability finding on 0135984f1bc1f68d89d7777f49c4999474105a12, using the already-executed real-browser RED rather than another blind rerun.
MV3 artifact 9977680352 records Chrome/ChromeDriver 150.0.7871.129, all four sandbox-enabled browser lanes at 0/3, and browser-crash trials at failure_stage=session_create with only failure_type=RuntimeError / reason_code=runtime_error. That evidence proves fail-closed startup failure, but it cannot distinguish the causal classes #212 must choose between.
The current runner makes that ambiguity structural: every ChromeDriver process sends stdout/stderr to DEVNULL, while _json_request parses a WebDriver error payload only to special-case no such window; every other value.error/message, including session not created, is collapsed to generic RuntimeError and the response details are discarded. The crash classifier therefore cannot produce more specific startup evidence even when ChromeDriver supplied it. Re-running the unchanged workflow cannot improve the RCA.
Preserve the no---no-sandbox boundary. Before another hosted browser rerun, add the smallest credential-safe diagnostic boundary: retain the bounded WebDriver error code as a typed value (at minimum session not created) and classify only an allowlisted set of startup causes from bounded ChromeDriver diagnostics into closed reason codes, with raw response/log text, profile paths, page data and credentials excluded from the artifact. A focused contract should prove that a representative session-creation error produces the safe typed reason while arbitrary/unrecognized text remains session_not_created/unknown and is never emitted. Then the next real pinned-Chromium run can distinguish a sandbox/helper failure from a different browser-startup defect and hand the exact cause to #212 instead of treating the current coarse category as root cause.
This is diagnostic/operability authority only. It must not add a fallback launch, restore --no-sandbox, weaken the 3-trial denominator, or turn cleanup success into browser success.
|
Exact-head diagnostic repair landed as The prior real-browser failure remains the executed RED: Manifest V3 run This repair keeps the sandbox and all repeatability/cleanup gates unchanged. It adds a typed, redacted TDD evidence:
Successor runs are newly materialized and remain non-terminal:
Keep Draft. These queued runs are not passing evidence; the next real pinned-Chromium artifact must establish the allowlisted startup cause before #212 chooses any workflow-side helper repair. |
|
Exact-head RCA update — PR #148 @ Manifest V3 Compatibility run The paired causal boundary is unchanged and stronger than a blind retry: current #148 fails closed without sandbox-disabling arguments, while #43 @ |
seonghobae
left a comment
There was a problem hiding this comment.
Exact-head RCA extension on 2323ff54e7bcad4c37eddfeb9274562982d52ac5: the bounded session_not_created repair is working, but the current runner still cannot refine startup_reason=unknown from ChromeDriver process diagnostics. Both _run_browser_pass and _run_agent_task_browser_pass launch ChromeDriver with stdout=subprocess.DEVNULL and stderr=subprocess.STDOUT; _classify_webdriver_session_startup_reason therefore sees only the W3C response value.message. The exact hosted artifact from MV3 run 34232690664 remains 0/3 at session creation with _WebDriverSessionNotCreatedError / session_not_created / startup_reason=unknown. Re-running the unchanged head cannot recover process-output evidence that this code discards.
Treat this as a source-side diagnostic RED distinct from #212's workflow-helper authority. The smallest safe repair should stream/drain ChromeDriver diagnostics through a bounded closed-vocabulary classifier while retaining no raw diagnostic bytes, paths, profile names, capabilities, page data, or secret-shaped text. The regression should include the sandbox marker split across read chunks plus hostile path/secret markers and prove that only reviewed reason codes survive; unrecognized diagnostics remain unknown. The capture must not introduce a PIPE deadlock, retry, alternate launch, broader egress, or --no-sandbox fallback. After exact repository GREEN, rerun pinned Chrome/ChromeDriver 150.0.7871.129; only then may a classified helper/AppArmor diagnostic be used as causal evidence for #212. Until then, keep the helper repair technically plausible but not proven by #148's current unknown evidence.
|
Writer lease ACTIVE — exact |
|
Writer lease RELEASED — current exact |
|
Writer lease ACTIVE — exact |
seonghobae
left a comment
There was a problem hiding this comment.
Current exact-head RCA for CI 34256771021: the bounded process-diagnostic production repair is present, but the two follow-up contracts added on 2b8e0e2... and 0e320aa... are not yet implemented. tests/test_chromedriver_process_diagnostic_contract.py now requires (1) the shared launch argv to include --verbose without --log-path, and (2) _drain_chromedriver_diagnostics to accept existing text-mode process doubles while retaining no raw diagnostic state. At 0e320aa..., _start_chromedriver still launches only [chromedriver, --port, --allowed-ips], and _drain_chromedriver_diagnostics raises TypeError for every non-bytes chunk. Therefore the Python repository-contract failure is causal and local; do not weaken either regression. Minimal repair: add --verbose only to the shared ChromeDriver argv, and normalize a str chunk to UTF-8 bytes inside the drain boundary before feeding _ChromeDriverStartupDiagnostic, while rejecting other chunk types and continuing to discard raw content. Preserve the binary PIPE in production, no --log-path, no retry/no --no-sandbox, 3-trial denominators, and the closed sandbox_unavailable|unknown evidence vocabulary. Exact real-browser artifact 10068188981 still reports session-create 0/3 with startup_reason=unknown, so no sandbox-helper causality is established until this repository RED is fixed and the pinned browser is rerun.
seonghobae
left a comment
There was a problem hiding this comment.
Current-head follow-up on the credential-safe ChromeDriver diagnostic repair: the async drain and the session-failure classifier are not synchronized. _start_chromedriver launches a daemon thread, but _create_chromedriver_session checks diagnostic.startup_reason immediately when the W3C session not created response arrives. If ChromeDriver emits No usable sandbox just before/after that response and the drain thread has not consumed the relevant bytes yet, a genuine reviewed process diagnostic is still recorded as unknown. Adding --verbose and StringIO normalization alone can therefore make repository contracts GREEN while leaving the real-browser classifier timing-dependent.
Please keep the existing active source lease and add a RED that deterministically delays the diagnostic feed until the session error path has begun, then proves classification waits only for a bounded, explicit diagnostic handoff—not an arbitrary sleep and not process EOF. The minimum repair should expose a bounded synchronization primitive/state from the drain boundary (or an equivalent reviewed design), preserve continuous draining and raw-byte non-retention, and return unknown on timeout. Do not wait indefinitely for ChromeDriver to exit, do not retain logs, and do not change the browser trial denominator or sandbox policy. This is independent of whether the eventual root cause is the setuid helper/AppArmor; it is about making the closed classifier deterministic on the evidence it already owns.
Partial implementation of #28. Current exact head is
5a86b28bb84643c3296c937a0480d70c9229ed6c, base is current #1473dff28d9bf2dd27b72507e39979d51b8bf140fb4, and the branch remains open, Draft and mergeable.Buyer/security boundary
This slice proves browser-crash recovery and teardown without disabling Chromium sandboxing. All four real-Chromium launch paths contain no
--no-sandboxescape. A rejected browser startup remains one failed trial; ChromeDriver/process teardown and temporary-profile cleanup remain evidence about cleanup only and are never promoted to browser/task success.The browser-crash lane retains PID/start-time identity before signalling, uses the existing PID-safe process observers, preserves the first causal browser failure when cleanup also fails, bounds secondary cleanup evidence to typed failure names, and keeps the 3-trial denominator unchanged.
Credential-safe session-start diagnosis
Predecessor
2323ff54e7bcad4c37eddfeb9274562982d52ac5repaired the W3C response boundary: structuredsession not createdresponses become_WebDriverSessionNotCreatedErrorwith closed error codesession_not_created, while onlysandbox_unavailableandunknownmay enter evidence. The exactNo usable sandboxresponse diagnostic maps tosandbox_unavailable; all other response detail maps tounknown. Raw response text, arbitrary diagnostics, profile/executable paths and secret-shaped values are not retained.Review
5143478858identified the remaining blind spot: all four ChromeDriver launch sites discard process output withstdout=subprocess.DEVNULL/stderr=subprocess.STDOUT, so response-level classification cannot consume ChromeDriver process diagnostics.Current commit
5a86b28bb84643c3296c937a0480d70c9229ed6cis the deliberate test-first RED for that finding. It addstests/test_chromedriver_process_diagnostic_contract.pyand requires:_ChromeDriverStartupDiagnosticthat retains only a closed startup reason and no raw diagnostic/path/secret state;No usable sandboxrecognition even when the reviewed marker crosses read chunks;unknown; andstdout=subprocess.PIPEreplacing discarded process output.No production runner source changed in this RED commit. Do not weaken or delete these contracts to restore CI.
Exact-head repository RED
CI
34249189712is terminal failure on exact5a86b28...as required by TDD.102138926823checked out exact5a86b28...and failed atCheck Python repository contractsafter running 259 tests: four errors because_ChromeDriverStartupDiagnostic/_drain_chromedriver_diagnosticsdo not yet exist, plus one failure because the runner still containsstdout=subprocess.DEVNULL.102138926424completed success because the commit is test-only. That does not override the repository-contract RED.The next causal source repair is the minimum implementation needed to satisfy these five contracts while preserving no-retry/no-
--no-sandbox, four browser lanes and all 3-trial denominators.Exact-head real-Chromium RED
Manifest V3 Compatibility
34249189613, job102138926057, also checked out exact5a86b28..., downloaded pinned Chrome/ChromeDriver150.0.7871.129, executed the real fixture and failed. Artifact10065380771, digestsha256:b01486c703d2614fd2444ad41785812c0e966779465a70792e53e02551ea9a2f, records all four browser lanes at 0/3 during session creation; browser-crash trials remain_WebDriverSessionNotCreatedError / session_not_created / startup_reason=unknownwith profiles cleaned.This repeat confirms that the test-only commit did not alter browser behavior. It still does not prove that the startup cause is the sandbox helper, AppArmor, harden-runner, or another runner restriction. Do not relabel
unknownassandbox_unavailableor infer causality from cleanup success.Canonical sandbox-helper owner boundary
Issue #212 remains the canonical current-workflow owner. PR #43 exact
6f3134d18d3118aab33d28048671dc71a5f47b77separately proved that this pinned Chrome generation can run sandboxed when the archivechrome_sandboxhelper is root-owned, mode4755, and bound throughCHROME_DEVEL_SANDBOX. That is technical feasibility evidence for #43's leaf workflow generation, not transferable workflow authority or GREEN for this branch.Protected
AGENTS.mdreserves.github/workflows/**mutation for the authorized workflow-owner path. The current order remains two-lane rather than circular: complete #148's bounded credential-safe process-diagnostic source repair and independently reconstruct/adopt the validated least-privilege helper mechanics against the current protected workflow generation under #212 without weakening lifecycle/concurrency, harden-runner/egress or immutable pins. Only a fresh exact-head pinned-Chromium run after a causal change may establish browser GREEN.Do not restore
--no-sandbox, reduce trials, broaden egress/permissions, copy an obsolete workflow blob, force-push/destructively rebase, or treat session/driver/profile cleanup as browser success.Review and remaining gates
All currently returned inline review threads are resolved. Review
5143478858remains the predecessor exact-head COMMENT finding now materialized as the5a86b28...RED contract; it is not an approval. HistoricalCHANGES_REQUESTEDsubmissions on predecessor heads are not current approval. Keep Draft.Merge/release readiness still requires the bounded process-diagnostic implementation, a fresh exact-head repository GREEN (Python contracts, formatting, Rust workspace tests, strict Clippy, rustdoc and exact owned-production coverage), canonical current-generation sandbox-helper owner repair if fresh evidence establishes it as causal, a new exact-head real pinned-Chromium GREEN, current central security/review/ruleset satisfaction, protected-parent integration in normal dependency order, and the separate #28 action → observed post-condition → evidence → browser/process/profile teardown composition.
No workflow/ruleset/secret mutation, Ready transition, self-approval, merge, tag, release, publication, force update or destructive restack is performed by this PR-state refresh.