Skip to content

chore(deps): bump chromiumoxide to 0.9.1 (Next.js WS fix) - #232

Merged
aram-devdocs merged 1 commit into
mainfrom
chore/chromiumoxide-09
May 6, 2026
Merged

chore(deps): bump chromiumoxide to 0.9.1 (Next.js WS fix)#232
aram-devdocs merged 1 commit into
mainfrom
chore/chromiumoxide-09

Conversation

@aram-devdocs

Copy link
Copy Markdown
Owner

Summary

Investigative dep bump: see if chromiumoxide 0.9.1 fixes the Linux-only "Invalid message: data did not match any variant of untagged enum Message" CDP WebSocket warnings that surface as Request timed out on the Next.js e2e leg in CI. Local macOS works; Linux CI fails. PR #231 added wait_for plumbing for the Next.js fixture, but the WS bug fires before wait_for_selector even gets a chance to poll.

The 0.9 release reshuffled cargo features:

  • tokio-runtime is gone (tokio is now hardcoded; async-std support removed). Drop it from the workspace declaration.
  • _fetcher-rustls-tokio is gone. The fetcher now exposes fetcher + a transport (rustls/native-tls) + a zip unpacker (zip0/zip8). Pick fetcher + rustls (matches workspace reqwest rustls policy) + zip8 (the upstream default).
  • Milestone is now publicly re-exported by chromiumoxide_fetcher; updated the comment in ensure_chromium that flagged the old absence (no behavior change — still pinning to Channel::Stable).

rustls-platform-verifier (transitively pulled in by reqwest 0.13 under chromiumoxide 0.9) brings webpki-root-certs 1.0.7 into the graph. That crate carries the same CDLA-Permissive-2.0 license as the existing webpki-roots exception in deny.toml; allow-list it the same way.

Validation

  • cargo fmt --check, cargo clippy --workspace --all-targets --all-features -- -D warnings, cargo nextest run --workspace --all-features (492 tests, all green).
  • just determinism-check (3 byte-identical runs).
  • cargo deny check (advisories/bans/licenses/sources all green).
  • cargo audit clean.
  • plumb-e2e --site nextjs against system Chrome on macOS — PASS nextjs target_violations=17, byte-stable.

Rollback plan

The real verification is whether CI Linux is now green for the nextjs leg after this PR + #231. If CI Linux is green for nextjs, the leg can stay non-advisory. If it still fails with the same WS warning, drop chromiumoxide back to 0.8 and accept the Linux nextjs advisory.

Test plan

  • CI preflight (fmt, clippy, deny) green on Linux.
  • CI test suite green on Linux + macOS.
  • CI determinism job green on Linux.
  • CI Next.js e2e leg green on Linux (the load-bearing question).

🤖 Generated with Claude Code

Investigative bump to see whether chromiumoxide 0.9.1 ships a CDP
WebSocket parsing fix that resolves the Linux-only "Invalid message:
data did not match any variant of untagged enum Message" warnings
that surface as `Request timed out` on the Next.js e2e leg in CI.

The 0.9 release reshuffled cargo features:

- The `tokio-runtime` feature is gone; tokio is now hardcoded (the
  async-std runtime support upstream removed). Drop it from the
  workspace declaration.
- The `_fetcher-rustls-tokio` umbrella feature is gone; the fetcher
  now exposes `fetcher` + a transport (`rustls`/`native-tls`) + a zip
  unpacker (`zip0`/`zip8`). Pick `fetcher` + `rustls` (matches the
  workspace `reqwest` rustls policy) + `zip8` (the upstream default).
- The fetcher now publicly re-exports `Milestone`; the comment in
  `ensure_chromium` noted the old absence and is updated.

`rustls-platform-verifier` (transitively pulled in by reqwest 0.13
under chromiumoxide 0.9) brings `webpki-root-certs` 1.0.7 into the
graph. That crate carries the same CDLA-Permissive-2.0 license as
the existing `webpki-roots` exception; allow-list it the same way.

Local validation:

- `cargo fmt --check`, `cargo clippy --workspace --all-targets
  --all-features -- -D warnings`, `cargo nextest run --workspace
  --all-features` (492 tests).
- `just determinism-check` (3 byte-identical runs).
- `cargo deny check` (advisories/bans/licenses/sources all green).
- `cargo audit` clean.
- `plumb-e2e --site nextjs` against system Chrome on macOS — PASS
  (target_violations=17, byte-stable).

The real verification is whether CI Linux is now green for the
nextjs leg. If it still fails, drop chromiumoxide back to 0.8 and
accept the Linux nextjs advisory.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented May 6, 2026

Copy link
Copy Markdown
Contributor

I have enough to write the review. Let me compile it now.


PR Review: ceb28e2 + 6fda537 (merged as 3d7c1ad)

Two commits: selector-scoped [[ignore]] suppression (PR #227) and chromiumoxide 0.8 → 0.9.1 bump.


1. Determinism — PASS

  • apply_ignores iterates config.ignore in declaration order (a Vec), which is deterministic across runs. ✓
  • suggested_ignores uses BTreeSet for dedup before output — deterministic sort order. ✓
  • run_report calls buffer.sort_by(|a, b| a.sort_key().cmp(&b.sort_key())) after the rayon flat_map collect, so parallel-execution non-determinism is flattened before return. ✓
  • No HashMap/HashSet in any output path. IndexMap throughout Config. ✓
  • No SystemTime or Instant anywhere in the added code. ✓

One observation: pretty_with_ignored swallows the run_id_for_sorted error silently, returning "sha256:unavailable" as the run-ID string:

// crates/plumb-format/src/lib.rs (pretty_with_ignored)
Err(_) => String::from("sha256:unavailable"),

This is infallible by construction (the function returns String), and Violation is fully Serialize, so the error branch is unreachable. Still, an unreachable branch that silently substitutes a fixed string rather than propagating or panicking is mildly opaque. Not a blocker since the function must stay infallible.


2. Workspace layering — PASS

  • plumb-core/src/lib.rs has #![forbid(unsafe_code)]. ✓
  • plumb-format/src/lib.rs has #![forbid(unsafe_code)]. ✓
  • plumb-format imports only plumb_core internally; no cdp/mcp/cli deps. ✓
  • plumb-cli/src/commands/lint.rs calls run_report from plumb_core; formatting via plumb_format. No layer inversion. ✓
  • Rule: Send + Sync is correctly declared at crates/plumb-core/src/rules/mod.rs, enabling par_iter in run_rules. ✓

3. Error handling — PASS

  • No unwrap/expect in library crates. plumb-core has #![deny(clippy::unwrap_used, clippy::expect_used)]; plumb-format mirrors it. ✓
  • json(), json_with_ignored(), json_with_suggested_ignores(), json_with_suggested_ignores_and_ignored() all have # Errors sections. ✓
  • LintError in plumb-cli/src/commands/lint.rs is thiserror-derived; propagates through anyhow::Error::from at the CLI boundary. ✓

4. Test coverage — PASS (one observation)

Engine apply_ignores has all four match shapes: passthrough / selector-only / selector + rule_id / no-match + a determinism cross-run check + a real-engine integration test (run_report_applies_ignores_against_real_engine_output). ✓

Config serde tests cover: minimal IgnoreRule, with rule_id, unknown-field rejection, missing selector, missing reason. ✓

Observation: No test exercises the case where the same violation matches two [[ignore]] entries simultaneously (e.g., one entry matches by selector-only, another by selector+rule_id). ignore_matches short-circuits on first hit via Iterator::any, so this is fine functionally, but there's no test asserting that double-matching doesn't double-count into ignored. Low priority.


5. Documentation — PASS

  • All new public items have doc comments. ✓
  • RunReport, run(), run_many(), run_report(), apply_ignores() all documented. ✓
  • json_with_ignored and companions have # Errors sections. ✓
  • IgnoreRule.reason is documented as required, not just pub. ✓

Punch list

crates/plumb-format/src/lib.rsjson() now always emits "ignored": 0

json() delegates to json_with_ignored(violations, 0), which inserts "ignored": 0 into the envelope unconditionally. This is an additive schema change — any golden snapshot test or downstream parser that used deny_unknown_fields on the envelope will break. The commit message acknowledges it ("new key is always present"), and the tests have presumably been updated, but it's worth confirming no MCP protocol or CLI snapshot tests are silently stale. Not a blocker, but the changelog entry should call this out explicitly as a schema change.

crates/plumb-cli/src/commands/lint.rs — SARIF silently drops ignored count

// render(), OutputFormat::Sarif arm
plumb_format::sarif_with_rules(violations, &plumb_core::builtin_rule_metadata())

When [[ignore]] entries are active and format is SARIF, the ignored_count is dropped with no user signal. The GitHub Code Scanning consumer will see a reduced violation set with no indication that suppressions are in effect. This is documented in the function's doc comment, and the SARIF 2.1.0 schema leaves no slot for it — the decision is sound. But it means SARIF users cannot audit their [[ignore]] entries via CI output. Worth a docs note in docs/src/configuration.md under the [[ignore]] section.

crates/plumb-cdp/Cargo.tomlaws-lc-rs/aws-lc-sys via rustls-platform-verifier

The chromiumoxide 0.9.1 bump pulls in aws-lc-sys 0.40.0, which requires cmake at build time. This materially increases CI cold-build time and adds a C build dependency. This is driven by reqwest 0.13.3rustls-platform-verifieraws-lc-rs, not by chromiumoxide directly. The deny.toml CDLA-Permissive-2.0 exception is correctly scoped to webpki-root-certs@1.0.7. No action required unless build time regresses materially in CI.


Verdict: APPROVE

@aram-devdocs
aram-devdocs merged commit 9a62c06 into main May 6, 2026
26 of 34 checks passed
@aram-devdocs
aram-devdocs deleted the chore/chromiumoxide-09 branch May 6, 2026 19:05
aram-devdocs added a commit that referenced this pull request May 6, 2026
chromiumoxide 0.9.1 (PR #232) fixed the WebSocket 'Invalid message'
bug, so 5 of 6 framework legs are green on all 3 OSes. Next.js still
fails on Linux + Windows with 'non-deterministic output for site
nextjs: runs differ' — the WS bug is gone, but Next.js's client-side
hydration produces timing-dependent computed-style snapshots that
differ by 1-2 elements run-to-run. macOS happens to be stable.

The proper fix is converting the Next.js fixture to a pure static
export (no 'use client' components, sentinel inlined server-side).
That's a meaningful refactor and warrants its own follow-up — tracked
as #233. Until then, mark the Next.js leg advisory with a precise
rationale so the matrix can still surface real regressions on the
five framework legs that work.

The wait_for plumbing from this PR (harness WaitFor schema + runner
threading + the data-plumb-ready sentinel) stays as-is. It's
legitimately useful for any future framework that exposes a
hydration-complete sentinel via server-side rendering.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
aram-devdocs added a commit that referenced this pull request May 6, 2026
* feat(e2e): thread wait_for selector through harness

Add an optional `wait_for` block to `expected.json` so fixtures whose
first paint races Chromium's network-idle event can declare a
post-hydration sentinel selector. The harness now passes
`--wait-for <selector> --wait-ms <timeout_ms>` onto every `plumb lint`
invocation when the block is present, and stays inert (no extra flags)
for fixtures that do not need it.

`WaitFor` carries the same `deny_unknown_fields` discipline as the
parent `Expected` payload; `timeout_ms` defaults to 30_000 ms.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(e2e): nextjs fixture sets data-plumb-ready sentinel

Mount a tiny client component (`app/plumb-ready.tsx`) that flips
`document.documentElement.dataset.plumbReady = "true"` from a
`useEffect`. The marker only appears after React hydrates the tree on
the client, which is the readiness signal the harness's
`wait_for.selector` matches. The page itself stays a server component;
only the marker is `'use client'`, so the existing intentional
violations (off-grid hero padding, off-palette alert text) and their
counts are unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ci(e2e): drop continue-on-error advisory for nextjs

The Next.js leg flake the advisory was hiding came from Chromium
capturing a half-hydrated DOM under CI load. With the harness now
threading `wait_for` onto `plumb lint` and the fixture publishing a
`html[data-plumb-ready="true"]` sentinel from a `useEffect`, the wait
is deterministic and the leg can fail the matrix on regressions like
every other framework.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ci(e2e): re-add nextjs advisory until static-export refactor lands

chromiumoxide 0.9.1 (PR #232) fixed the WebSocket 'Invalid message'
bug, so 5 of 6 framework legs are green on all 3 OSes. Next.js still
fails on Linux + Windows with 'non-deterministic output for site
nextjs: runs differ' — the WS bug is gone, but Next.js's client-side
hydration produces timing-dependent computed-style snapshots that
differ by 1-2 elements run-to-run. macOS happens to be stable.

The proper fix is converting the Next.js fixture to a pure static
export (no 'use client' components, sentinel inlined server-side).
That's a meaningful refactor and warrants its own follow-up — tracked
as #233. Until then, mark the Next.js leg advisory with a precise
rationale so the matrix can still surface real regressions on the
five framework legs that work.

The wait_for plumbing from this PR (harness WaitFor schema + runner
threading + the data-plumb-ready sentinel) stays as-is. It's
legitimately useful for any future framework that exposes a
hydration-complete sentinel via server-side rendering.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
aram-devdocs added a commit that referenced this pull request May 6, 2026
)

* feat(e2e): thread wait_for selector through harness

Add an optional `wait_for` block to `expected.json` so fixtures whose
first paint races Chromium's network-idle event can declare a
post-hydration sentinel selector. The harness now passes
`--wait-for <selector> --wait-ms <timeout_ms>` onto every `plumb lint`
invocation when the block is present, and stays inert (no extra flags)
for fixtures that do not need it.

`WaitFor` carries the same `deny_unknown_fields` discipline as the
parent `Expected` payload; `timeout_ms` defaults to 30_000 ms.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(e2e): nextjs fixture sets data-plumb-ready sentinel

Mount a tiny client component (`app/plumb-ready.tsx`) that flips
`document.documentElement.dataset.plumbReady = "true"` from a
`useEffect`. The marker only appears after React hydrates the tree on
the client, which is the readiness signal the harness's
`wait_for.selector` matches. The page itself stays a server component;
only the marker is `'use client'`, so the existing intentional
violations (off-grid hero padding, off-palette alert text) and their
counts are unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ci(e2e): drop continue-on-error advisory for nextjs

The Next.js leg flake the advisory was hiding came from Chromium
capturing a half-hydrated DOM under CI load. With the harness now
threading `wait_for` onto `plumb lint` and the fixture publishing a
`html[data-plumb-ready="true"]` sentinel from a `useEffect`, the wait
is deterministic and the leg can fail the matrix on regressions like
every other framework.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ci(e2e): re-add nextjs advisory until static-export refactor lands

chromiumoxide 0.9.1 (PR #232) fixed the WebSocket 'Invalid message'
bug, so 5 of 6 framework legs are green on all 3 OSes. Next.js still
fails on Linux + Windows with 'non-deterministic output for site
nextjs: runs differ' — the WS bug is gone, but Next.js's client-side
hydration produces timing-dependent computed-style snapshots that
differ by 1-2 elements run-to-run. macOS happens to be stable.

The proper fix is converting the Next.js fixture to a pure static
export (no 'use client' components, sentinel inlined server-side).
That's a meaningful refactor and warrants its own follow-up — tracked
as #233. Until then, mark the Next.js leg advisory with a precise
rationale so the matrix can still surface real regressions on the
five framework legs that work.

The wait_for plumbing from this PR (harness WaitFor schema + runner
threading + the data-plumb-ready sentinel) stays as-is. It's
legitimately useful for any future framework that exposes a
hydration-complete sentinel via server-side rendering.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(e2e): server-render data-plumb-ready on <html> for Next.js fixture

The `<PlumbReady>` client component (PR #231) flipped
`data-plumb-ready="true"` from a `useEffect`. That made the harness's
`wait_for` selector resolve, but it didn't fix the underlying flake:
on Linux + Windows under CI load, post-hydration DOM mutations are
timing-dependent and the captured computed-style snapshot drifts by
1-2 elements run-to-run. macOS happens to be stable, the other 5
frameworks are pure static and unaffected.

Inline the readiness sentinel directly on `<html>` in
`app/layout.tsx` so it's emitted at server-render time. Drop the
`'use client'` component entirely — the fixture is now a pure static
export. The `wait_for` selector still resolves immediately on the
first DOM, which is the same DOM Chromium will capture on every run.

Intentional violation counts are unchanged (1 + 8 + 8 = 17). Verified
locally on macOS with the harness's internal 3× determinism check
passing. CI Linux + Windows green is the real verification — tracked
as #233.

* ci(e2e): drop nextjs continue-on-error advisory (closes #233)

With the Next.js fixture converted to a pure static export (no
`'use client'` component, `data-plumb-ready="true"` server-rendered
onto `<html>`), the captured DOM is byte-stable across Linux, macOS,
and Windows runs. The matrix can hold the leg to the same standard
as every other framework — drop the advisory wrapping and the
follow-up rationale comment that referenced #233.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
aram-devdocs added a commit that referenced this pull request May 7, 2026
…#237)

* feat(e2e): thread wait_for selector through harness

Add an optional `wait_for` block to `expected.json` so fixtures whose
first paint races Chromium's network-idle event can declare a
post-hydration sentinel selector. The harness now passes
`--wait-for <selector> --wait-ms <timeout_ms>` onto every `plumb lint`
invocation when the block is present, and stays inert (no extra flags)
for fixtures that do not need it.

`WaitFor` carries the same `deny_unknown_fields` discipline as the
parent `Expected` payload; `timeout_ms` defaults to 30_000 ms.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(e2e): nextjs fixture sets data-plumb-ready sentinel

Mount a tiny client component (`app/plumb-ready.tsx`) that flips
`document.documentElement.dataset.plumbReady = "true"` from a
`useEffect`. The marker only appears after React hydrates the tree on
the client, which is the readiness signal the harness's
`wait_for.selector` matches. The page itself stays a server component;
only the marker is `'use client'`, so the existing intentional
violations (off-grid hero padding, off-palette alert text) and their
counts are unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ci(e2e): drop continue-on-error advisory for nextjs

The Next.js leg flake the advisory was hiding came from Chromium
capturing a half-hydrated DOM under CI load. With the harness now
threading `wait_for` onto `plumb lint` and the fixture publishing a
`html[data-plumb-ready="true"]` sentinel from a `useEffect`, the wait
is deterministic and the leg can fail the matrix on regressions like
every other framework.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* ci(e2e): re-add nextjs advisory until static-export refactor lands

chromiumoxide 0.9.1 (PR #232) fixed the WebSocket 'Invalid message'
bug, so 5 of 6 framework legs are green on all 3 OSes. Next.js still
fails on Linux + Windows with 'non-deterministic output for site
nextjs: runs differ' — the WS bug is gone, but Next.js's client-side
hydration produces timing-dependent computed-style snapshots that
differ by 1-2 elements run-to-run. macOS happens to be stable.

The proper fix is converting the Next.js fixture to a pure static
export (no 'use client' components, sentinel inlined server-side).
That's a meaningful refactor and warrants its own follow-up — tracked
as #233. Until then, mark the Next.js leg advisory with a precise
rationale so the matrix can still surface real regressions on the
five framework legs that work.

The wait_for plumbing from this PR (harness WaitFor schema + runner
threading + the data-plumb-ready sentinel) stays as-is. It's
legitimately useful for any future framework that exposes a
hydration-complete sentinel via server-side rendering.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(e2e): server-render data-plumb-ready on <html> for Next.js fixture

The `<PlumbReady>` client component (PR #231) flipped
`data-plumb-ready="true"` from a `useEffect`. That made the harness's
`wait_for` selector resolve, but it didn't fix the underlying flake:
on Linux + Windows under CI load, post-hydration DOM mutations are
timing-dependent and the captured computed-style snapshot drifts by
1-2 elements run-to-run. macOS happens to be stable, the other 5
frameworks are pure static and unaffected.

Inline the readiness sentinel directly on `<html>` in
`app/layout.tsx` so it's emitted at server-render time. Drop the
`'use client'` component entirely — the fixture is now a pure static
export. The `wait_for` selector still resolves immediately on the
first DOM, which is the same DOM Chromium will capture on every run.

Intentional violation counts are unchanged (1 + 8 + 8 = 17). Verified
locally on macOS with the harness's internal 3× determinism check
passing. CI Linux + Windows green is the real verification — tracked
as #233.

* ci(e2e): drop nextjs continue-on-error advisory (closes #233)

With the Next.js fixture converted to a pure static export (no
`'use client'` component, `data-plumb-ready="true"` server-rendered
onto `<html>`), the captured DOM is byte-stable across Linux, macOS,
and Windows runs. The matrix can hold the leg to the same standard
as every other framework — drop the advisory wrapping and the
follow-up rationale comment that referenced #233.

* docs(mcp): add live lint_url verification; revise dogfood acceptance to exit 0 or 3 + deterministic

* docs(runbooks): correct post-V0 dogfood follow-up reference (#235#238)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant