Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 4 additions & 10 deletions BENCHMARK.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,7 @@ Before using a benchmark in launch-facing latency copy or progress claims, run:

```bash
python tools/check_benchmark_artifacts.py --source testbox --runner blacksmith-testbox --artifact <artifact-name> --run-url <run-url> --enforce-phase2 --enforce-launch --json
python tools/check_launch_latency_claim.py
python tools/check_launch_latency_claim.py --benchmark-json .benchmark-data/results/<testbox-bench-full-strict>.json --source testbox --artifact <artifact-name> --run-url <run-url>
python tools/render_project_tables.py --table launch
```

The checker is intentionally stricter than a benchmark smoke. It rejects
Expand Down Expand Up @@ -307,14 +305,10 @@ case means. The `click_button` case measured 89.61 ms for Rustwright versus
662.44 ms for Python Playwright after the fix.

The attempted local `strict` 3-iteration comparison failed before producing
timing because the current Python Playwright reference returned a timeout call
log for `check_and_uncheck` where the existing benchmark assertion expected an
`Element is not visible` message. The attempted
`RUSTWRIGHT_UNSAFE_DOM_FASTPATH=1` old-behavior proxy also failed setup on
three local runs at `Browser.new_page: timed out after 5000 ms`, so no honest
local before-fastpath timing sample is recorded here. Treat previous DOM
fast-path benchmark claims as tainted until reproduced with trusted default
input in a capped Testbox/Docker run.
timing. The Python Playwright reference returned a timeout call log for
`check_and_uncheck`, while the benchmark expected `Element is not visible`.
Treat earlier synthetic DOM fast-path claims as tainted. The removed path cannot
serve as a valid baseline. Reproduce trusted input in a capped Testbox run.

## Client Memory: Form-Fill Diagnostic

Expand Down
31 changes: 31 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,37 @@ All notable user-facing changes to Rustwright are documented in this file.

## [Unreleased]

### Breaking

- Removed `disable_playwright_compat()`. Compatibility aliases are now a one-way
process opt-in.
- Removed `RUSTWRIGHT_UNSAFE_DOM_FASTPATH`. Click, fill, check, and select
actions always use the trusted native action path.
- Promoted one MCP behavior profile for every client. Snapshot distillation,
page headers, console deduplication, network notes, compact descriptions, and
9 KiB/200-line response limits are now the defaults.

### Changed

- `Browser.new_page()` now creates a native ephemeral browser context for each
page. Closing the page disposes its context, matching Playwright isolation.
- Navigation internals now retain response bodies and drain console and
page-error history before each navigation.
- Chromium launches now include a broader resource-safe default switch set.
- User-provided feature-list launch arguments now merge with defaults into one
switch per feature flag.

- Network request filters now accept the standard Rust `regex` syntax.

- Console and page-error event waiters now block in Rust and apply exact or
substring text filters without Python polling. Console and page-error
listeners use the persistent event pump. Once/remove cleanup detaches worker
console forwarding and page close reaps worker listener threads.

### Fixed

- Fixed native drag-and-drop to stop dispatching trailing pointer and mouse release events after a completed drop.

## [0.3.0] - 2026-08-16

### Added
Expand Down
3 changes: 1 addition & 2 deletions CODE_ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,10 @@ C-ABI bindings.
| `go/`, `java/`, `csharp/`, `ruby/`, `php/` | C-ABI language bindings (alpha surface) + per-language conformance runners. |
| `bindings/` | Cross-binding contract (`CONTRACT.md`) and shared conformance case data. |
| `benchmarks/automation_cases.py` | Shared Playwright-style automation/parity cases and benchmark workflows, including WebVoyager/Mind2Web-style workflow cases. |
| `benchmarks/run_benchmarks.py` | Rustwright and Playwright benchmark runner for a comparable workload. |
| `benchmarks/run_benchmarks.py` | Canonical Rustwright and Playwright runner for benchmark and shared parity suites. |
| `tests/test_rustwright_sync_api.py` | Main behavior/regression suite. |
| `tests/test_playwright_parity_cases.py` | Shared parity harness test entry point. |
| `tools/api_surface_audit.py` | Public API surface comparison against reference Playwright. |
| `tools/run_parity_cases.py` | Runs shared parity cases against Rustwright or reference Playwright. |
| `tools/run_antibot_benchmarks.py` | Anti-bot benchmark runner covering local smoke signals, public fingerprint adapters, and fresh/warm profile matrix checks across Rustwright and Playwright. |

## Known Architecture Debt
Expand Down
39 changes: 39 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 5 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ RUN --mount=type=cache,target=/root/.cache/pip \

COPY src ./src
COPY python ./python
# The root Cargo.toml declares `node`, `capi`, and `rust-native` as workspace
# members, so cargo must be able to load each member manifest (and its lib
# sources) to resolve the workspace before maturin builds the Python
# The root Cargo.toml declares `node`, `capi`, `rust-native`, and `agent` as
# workspace members, so cargo must be able to load each member manifest (and its
# lib sources) to resolve the workspace before maturin builds the Python
# extension — even though this image never builds those crates. Copy just the
# crate manifests and sources, not node_modules or build output.
COPY node/Cargo.toml node/build.rs ./node/
Expand All @@ -65,6 +65,8 @@ COPY capi/Cargo.toml ./capi/
COPY capi/src ./capi/src
COPY rust-native/Cargo.toml ./rust-native/
COPY rust-native/src ./rust-native/src
COPY agent/Cargo.toml ./agent/
COPY agent/src ./agent/src

RUN --mount=type=cache,target=/root/.cache/pip \
--mount=type=cache,target=/usr/local/cargo/registry \
Expand Down
18 changes: 10 additions & 8 deletions MEMORY_BENCH.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ Each passed item in `results` contains a `memory` block with:
including the driver and Chromium process tree.
- sampling provenance, interval, availability, and sample count.

The sampler uses the same method as `benchmarks/async_concurrency_load.py`: it
walks parent/child PIDs with `ps`, reads RSS in KiB, samples every 50 ms, and
retains the independent peak for the root and whole tree. It takes one baseline
before entering the implementation run, then samples on a daemon background
thread; case timers continue to wrap only the operation under test, so `ps`
calls are not executed on the latency hot path. If `ps`, the tree walk, or an
individual RSS read is unavailable, the corresponding value is `null` and the
benchmark continues.
On Linux, the sampler reads parent PIDs and `VmRSS` directly from
`/proc/<pid>/status`. Other platforms fall back to `ps`. It samples every 50 ms
and retains independent peaks for the root process and the full process tree. It
takes one baseline before the implementation run, then samples on a daemon
background thread. Case timers still wrap only the operation under test.

If neither backend yields complete positive `rss_self_kb` and `rss_tree_kb`
values in KiB, both fields are unavailable for canonical evidence. `bench-full`
treats that run as failed, so the matrix cannot publish a latency-only or
partial-tree comparison.

Whole-tree RSS is normally Chromium-dominated. Report `rss_tree_kb` for the
actual end-to-end process cost and `rss_self_kb` alongside it as the available
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ server, use the standalone [`rustwright-mcp`](mcp/) package.
- **No Node driver subprocess.** `playwright-python` launches and pipes to a bundled Node driver. Rustwright's engine is native — the browser-control code runs in-process.
- **Raw CDP, in Rust.** A from-scratch async CDP client — not a wrapper around another automation library.
- **No Playwright automation fingerprint.** The driver never loads, so its signatures never appear. See [Automation detection](#automation-detection).
- **Trusted input by default.** Clicks and typing go through real CDP input events (`Input.dispatchMouseEvent`), not synthetic `element.click()` DOM calls. Untrusted DOM shortcuts are opt-in only.
- **Trusted input.** Clicks and typing always use real CDP input events (`Input.dispatchMouseEvent`), not synthetic `element.click()` DOM calls.
- **Cross-origin iframes (OOPIF).** Auto-attaches out-of-process iframe targets with flattened CDP sessions and routes `frame_locator()` across origins.
- **One engine, two languages.** The same Rust core backs the Python and Node bindings.

Expand Down
1 change: 1 addition & 0 deletions agent/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ test-support = []

[dependencies]
base64 = "=0.22.1"
regex = "=1.12.3"
rustwright = { path = "../rust-native" }
serde = { version = "1.0.194", features = ["derive"] }
serde_json = "1.0.127"
Expand Down
Loading
Loading