ruby_llm-browser 0.3.0 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6c1e32269fa76e278df596a6e63e30d28506a9e7e3ada269703bad06ba870fef
4
- data.tar.gz: d103e32333352508883d3794dd6e37a4aa3058d4f2e5842ccd174c6b2b43b11e
3
+ metadata.gz: fc13ef270cc86b7c259964fe10fc0b512fa2bd4c9ba4c8b66a6af827e30478ad
4
+ data.tar.gz: d0ba262e6456375b2efbfe833203befe32fb1aae197f9584e12e0d09fcdc9e24
5
5
  SHA512:
6
- metadata.gz: 39769537e3c05f25231657f2b56ab72bda7690ac2b7e144149cac85a8d2d7de7b29e73f45a4dd41fe8e6718aa0f1535d6c2d77d5f4203469474b4a64e018dc4d
7
- data.tar.gz: 1ff61fb1a7fe9017be814634d6763938e6a6652814df76386b43ca90217f2ffad2f51429a5edec1855a431300802182c8d2ad7c9a9eb00890a6612ba9ccd7da4
6
+ metadata.gz: '0385b825edf09eeb25391c7ce77d424c022bad3ed65e0e7933b9e76232ae98705e4a99ec07a08c56be9c5f2f7896743eb147339adcbc2b9be45cdca78a0ec8ac'
7
+ data.tar.gz: 7cf3f08b5ce9128d5978d0b4a80883c91bed38f11ad51bb554970fb48494d0b3017181721b135a1f0778a2da81a455ba3461a10ab37ab954c53e82eeb8785b09
data/CHANGELOG.md CHANGED
@@ -4,6 +4,28 @@ All notable changes to this project are documented here. The format is based on
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project aims to
5
5
  follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [Unreleased]
8
+
9
+ ## [0.4.4] - 2026-10-21
10
+
11
+ ### Added
12
+
13
+ - Pinned local Stagehand SDK feasibility contracts and `bin/check-local-stagehand`.
14
+ The runner starts no Stagehand server and makes no model or provider call.
15
+ - Opt-in workbench network canaries for redirects, fetch, images, scripts, frames,
16
+ popups, Worker fetch, and WebSocket upgrade requests. Chrome tests calibrate
17
+ unrestricted and partial-denial controls, retain screenshots and request receipts,
18
+ and run in offline browser CI. They do not qualify deployment isolation.
19
+
20
+ ### Fixed
21
+
22
+ - Require an explicit local Stagehand executable matching `server_binary_sha256`
23
+ before reporting a binary pin or constructing a local SDK client. Version labels
24
+ alone can select stale cached binaries or trigger downloads in Stagehand 3.21.0.
25
+ Doctor rechecks the executable without starting it; live support remains disabled.
26
+ - Set the gem's `documentation_uri` to the hosted documentation site so RubyGems
27
+ displays its documentation link after the next release.
28
+
7
29
  ## [0.3.0] - 2026-10-19
8
30
 
9
31
  ### Added
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  An unofficial [RubyLLM](https://rubyllm.com) extension for read-only browser inspection
4
4
  and schema-checked extraction, with an optional Rails 8 adapter.
5
5
 
6
- **0.3.0 supports offline use only.** `FakeBackend` runs without credentials or network
6
+ **0.4.4 supports offline use only.** `FakeBackend` runs without credentials or network
7
7
  requests. The experimental Stagehand adapter refuses live operations; `Act` is an
8
8
  offline simulation. This project is not maintained or endorsed by RubyLLM or Browserbase.
9
9
 
@@ -16,7 +16,7 @@ offline simulation. This project is not maintained or endorsed by RubyLLM or Bro
16
16
  Use Ruby 3.2+ and RubyLLM 2.x. Add to your Gemfile, then run `bundle install`:
17
17
 
18
18
  ```ruby
19
- gem "ruby_llm-browser", "~> 0.3.0"
19
+ gem "ruby_llm-browser", "~> 0.4.4"
20
20
  ```
21
21
 
22
22
  ## Try it offline
data/docs/README.md CHANGED
@@ -5,6 +5,8 @@ stable release. The [next-version site](https://rubyllm-browser.wangyaodi.com/ne
5
5
  follows `main`. The Markdown files below are the source for those guides and ship in
6
6
  the gem.
7
7
 
8
+ - [What's New in 0.4](_getting_started/whats-new-in-0-4.md): the 0.4.4 offline hardening release.
9
+ - [Local Stagehand feasibility](_advanced/local-stagehand-deployment.md): pinned SDK contracts and browser network canaries.
8
10
  - [Getting started](_getting_started/getting-started.md): installation and an offline example.
9
11
  - [Configuration](_getting_started/configuration.md): host inputs and process defaults.
10
12
  - [Inspect and Extract](_core_features/inspect-extract.md): tools and result handling.
data/docs/RELEASING.md CHANGED
@@ -17,7 +17,10 @@ After reading this guide, you will know:
17
17
 
18
18
  ## Compatibility evidence
19
19
 
20
- The source repository's `docs/evidence/V0_3_VALIDATION.md` records local 0.3.0 checks.
20
+ The source repository's `docs/evidence/V0_4_4_VALIDATION.md` records local 0.4.4 checks.
21
+ The 0.4.4 release ships offline executable hardening and development fixtures;
22
+ live-deployment qualification remains incomplete. Historical 0.3.0 checks remain in
23
+ `docs/evidence/V0_3_VALIDATION.md`.
21
24
  `docs/evidence/V0_3_RELEASE.md` records the exact remote CI, published artifact and
22
25
  hosted documentation results. The earlier audit below is historical evidence.
23
26
 
@@ -80,6 +83,7 @@ inventory are retained in the temporary evidence directory printed by the comman
80
83
  Verify all of the following:
81
84
 
82
85
  - Core require loads no Rails, Active Record, Active Job, or Stagehand client.
86
+ - The built gem's `documentation_uri` points to the hosted documentation site.
83
87
  - The optional Rails require loads on demand.
84
88
  - The generated migration and all README-linked guides are shipped.
85
89
  - All shipped examples run using the installed artifact.
@@ -61,7 +61,9 @@ credentials. The fixture and browser libraries are excluded from the gem.
61
61
 
62
62
  ```sh
63
63
  bin/check-browser
64
- # Or include browser tests after the offline checks:
64
+ # Include the optional loopback network canaries:
65
+ bin/check-browser --network
66
+ # Include all browser tests after the offline checks:
65
67
  bin/check --browser
66
68
  ```
67
69
 
@@ -75,6 +77,14 @@ a 390px device viewport, and offline/blocked-Stagehand Doctor output. Capture sc
75
77
  active session, including on assertion failures. Inspect failure artifacts before
76
78
  retrying. Screenshots support visual review; assertions establish the expected behavior.
77
79
 
80
+ `--network` adds same-origin and cross-origin canaries, partial image denial on mobile,
81
+ and independent redirected-URL checks. CI and `bin/check --browser` include this option.
82
+ The opt-in `bin/check-local-stagehand` runner also pins the SDK feasibility bundle and
83
+ runs its HTTP contracts without starting Stagehand. See
84
+ [Local Stagehand feasibility]({% link _advanced/local-stagehand-deployment.md %}) for
85
+ request coverage and the remaining deployment gaps. Canary receipts and screenshots
86
+ are review evidence; they do not qualify network isolation.
87
+
78
88
  The Puma host and Selenium port probe bind loopback. Browser test HTTP clients allow
79
89
  loopback only; this is not a Chrome network firewall. No live provider request is part
80
90
  of this suite. Tests close their driver sessions, and Puma ends with the test process.
@@ -75,5 +75,6 @@ requests, and returned page text remains untrusted data. Review the [security mo
75
75
 
76
76
  ## Next Steps
77
77
 
78
+ * [Local Stagehand feasibility]({% link _advanced/local-stagehand-deployment.md %}) - run pinned SDK contracts and loopback canaries without a provider.
78
79
  * [Controlling source access]({% link _core_features/source-policy.md %}) - set host URL policy.
79
80
  * [Running work in Rails]({% link _advanced/rails-integration.md %}) - protect durable jobs and recovery.
@@ -0,0 +1,118 @@
1
+ ---
2
+ layout: default
3
+ title: Local Stagehand feasibility
4
+ nav_order: 5
5
+ description: Run offline checks for a pinned local Stagehand deployment and identify the remaining isolation requirements.
6
+ ---
7
+
8
+ # {{ page.title }}
9
+
10
+ {{ page.description }}
11
+
12
+ After reading this guide, you will know:
13
+
14
+ - How to run the local SDK contracts and browser canaries without a provider.
15
+ - Which parts of a local deployment need separate host controls.
16
+ - What still blocks supported live browsing.
17
+
18
+ ## Run the Offline Fixtures
19
+
20
+ ```sh
21
+ BUNDLE_GEMFILE=gemfiles/local_stagehand.gemfile bundle install
22
+ bin/check-local-stagehand
23
+ ```
24
+
25
+ The source-checkout runner pins the Ruby SDK to `stagehand 3.21.0`. It runs the
26
+ local HTTP contracts, executable identity regressions, and Chrome network canaries.
27
+ It does not start Stagehand, download a server binary, or call a model. HTTP contracts
28
+ use empty or synthetic credentials. Use `CHROME_BIN` and `CHROMEDRIVER` to select installed browser binaries.
29
+ Installing dependencies may access the package registry. Once dependencies and a
30
+ matching driver are installed, fixture execution needs only loopback access.
31
+
32
+ The runner prints an ignored `tmp/local-stagehand/` directory containing screenshots
33
+ and per-case JSON receipts. Each receipt declares `qualified: false`, the Chrome
34
+ version, expected received request kinds, and actual server counters. A successful
35
+ run establishes fixture calibration and SDK serialization, not a supported deployment.
36
+ The fixture has no user-supplied destination URL and both origins point to loopback.
37
+
38
+ You can also run `bin/check-browser --network` to combine the canaries with the
39
+ existing workbench workflows. `bin/check --browser` includes them. The network routes
40
+ are enabled only for the test instance of `dev/workbench.rb`. Normal `bin/workbench`
41
+ does not expose them. All browser dependencies remain outside runtime dependencies.
42
+
43
+ ## Understand the Controls
44
+
45
+ The same-origin control sends seven request types: fetch, image, script, iframe,
46
+ popup, Worker fetch, and a WebSocket upgrade. The cross-origin control changes the
47
+ destination from `127.0.0.1` to `localhost` on the same loopback server. An unrestricted
48
+ Chrome must reach every canary. This detects tests that appear to deny a request only
49
+ because the browser never sent it.
50
+
51
+ A third control blocks the image through the current Chrome target's CDP network
52
+ settings. The image fails while the other six canaries still arrive. The mobile test
53
+ uses keyboard activation and checks overflow. This is a partial-denial calibration;
54
+ CDP URL blocking is not the deployment's security boundary. A redirect scenario
55
+ reads the resulting URL from Chrome and checks that the destination server received
56
+ the request.
57
+
58
+ The WebSocket endpoint records the HTTP upgrade request, then returns `426`. It does
59
+ not open a tunnel. These tests do not qualify a successful WebSocket connection,
60
+ WSS, HTTPS CONNECT, DNS changes, service workers, QUIC, IPv6 routing, or a production
61
+ firewall. A later isolation run must test positive connectivity and forbidden
62
+ destinations through the actual browser namespace, including every child target.
63
+
64
+ ## Account for the Pinned SDK
65
+
66
+ The local HTTP suite uses the real SDK serializer with stubbed HTTP. It intercepts
67
+ the SDK's server manager before process creation. The assertions establish these
68
+ properties of SDK 3.21.0:
69
+
70
+ | SDK behavior | Deployment consequence |
71
+ | --- | --- |
72
+ | `browser: { type: :local, cdp_url: ... }` serializes an attached browser without Browserbase credentials | You can investigate a separately supervised Chrome instead of letting Stagehand launch it |
73
+ | Omitting the local browser type requires Browserbase credentials | A future adapter must explicitly select the local browser |
74
+ | Local mode replaces a supplied `base_url` with its managed server endpoint | Passing a local URL does not attach to an externally supervised Stagehand server |
75
+ | Navigation accepts `result: nil` | The host needs an independent, same-session final-URL check |
76
+ | Ending a session returns `success` without terminal state | The host must confirm browser termination separately |
77
+ | A lost start response raises after one request when retries are disabled | Recovery must retain quota until the supervisor resolves the owned browser |
78
+
79
+ Read the pinned [SDK source](https://github.com/browserbase/stagehand-ruby/tree/v3.21.0/lib/stagehand)
80
+ when changing these contracts. A stubbed response does not prove that a particular
81
+ server binary implements the serialized options. Server compatibility still needs
82
+ an offline, controlled deployment run before any model call.
83
+
84
+ The gem's `StagehandBackend` remains unsupported. These SDK experiments do not add
85
+ local browser attachment or Browserbase-free construction to its public API. Its
86
+ local executable diagnostic requires an absolute `STAGEHAND_SEA_BINARY` and the
87
+ host-approved `server_binary_sha256:`. See
88
+ [API and configuration]({% link _reference/api-and-configuration.md %}) for the pinning
89
+ contract and filesystem trust boundary.
90
+
91
+ ## Build the Deployment Boundary Next
92
+
93
+ The selected direction is local Stagehand with a host-controlled browser network.
94
+ Use a separately owned Linux browser namespace or equivalent enforced boundary. Keep
95
+ the Stagehand model connection outside that namespace. The browser must have no
96
+ direct route around the host's egress gateway, including loopback, host services,
97
+ IPv6, UDP, and new browser targets. A Chrome proxy flag alone does not establish this.
98
+
99
+ The gateway must enforce approved hosts and ports at connection time, reject private
100
+ and mixed public/private DNS answers, and connect to the validated numeric address.
101
+ Test denied redirects and every canary against the actual boundary. Fix the server
102
+ binary hash, browser artifact, network configuration, and gateway version in the
103
+ qualification evidence. No such deployment is qualified yet.
104
+
105
+ An independent supervisor must own the browser before the Stagehand start request,
106
+ bind it to the durable operation, enforce expiry after worker death, and confirm
107
+ process and network teardown. A lost start response must remain reconcilable without
108
+ a second start. A successful end response or a closed CDP connection alone cannot
109
+ release quota. Keep unresolved operations visible for host review.
110
+
111
+ Complete these offline deployment checks before requesting a separate live run.
112
+ Keep Stagehand and live Act disabled until the
113
+ [live-deployment acceptance criteria]({% link _reference/roadmap.md %}) pass.
114
+
115
+ ## Next Steps
116
+
117
+ - Read [Qualifying a live backend]({% link _advanced/live-backend-qualification.md %}) for the full acceptance boundary.
118
+ - Follow [Development and Testing]({% link _advanced/development-and-testing.md %}) for the regression and package checks.
data/docs/_config.yml CHANGED
@@ -108,6 +108,6 @@ code_language: ruby
108
108
  # and {{ site.examples.NAME }}. Candidates remain unreleased; the docs builder
109
109
  # reads stable docs from the latest release tag and main under /next/.
110
110
  released: true
111
- version: "0.3.0"
112
- stable_version: "0.3.0"
111
+ version: "0.4.4"
112
+ stable_version: "0.4.4"
113
113
  examples: {}
@@ -9,6 +9,6 @@
9
9
  collections:
10
10
  - reference
11
11
  - title: "What's New"
12
- url: /whats-new-in-0-3/
12
+ url: /whats-new-in-0-4/
13
13
  - title: Releases
14
14
  url: https://github.com/yorzi/ruby_llm-browser/releases
@@ -0,0 +1,81 @@
1
+ ---
2
+ layout: default
3
+ title: What's New in 0.4
4
+ redirect_from:
5
+ - /whats-new/
6
+ nav_order: 4
7
+ description: Verify local Stagehand executable identity and calibrate offline browser tests in the 0.4.4 release.
8
+ ---
9
+
10
+ # {{ page.title }}
11
+
12
+ {{ page.description }}
13
+
14
+ After reading this guide, you will know:
15
+
16
+ - How local executable identity checks change.
17
+ - How to run the pinned SDK and browser fixtures.
18
+ - Which live-deployment requirements remain incomplete.
19
+
20
+ ## Verify the Local Executable
21
+
22
+ Version 0.4.4 requires a host-approved checksum for local diagnostics:
23
+
24
+ ```ruby
25
+ backend = RubyLLM::Browser::StagehandBackend.new(
26
+ browserbase_api_key: "diagnostic-placeholder",
27
+ model_api_key: "diagnostic-placeholder",
28
+ model_name: "diagnostic-model",
29
+ server: :local,
30
+ server_binary_sha256: reviewed_sha256
31
+ )
32
+ report = RubyLLM::Browser::Doctor.new(backend: backend).report
33
+ ```
34
+
35
+ Set `STAGEHAND_SEA_BINARY` in the process environment to the absolute path of the
36
+ reviewed executable. `reviewed_sha256` is its host-approved lowercase SHA-256. The
37
+ diagnostic reads the file without running it. A missing, nonexecutable, changed, or
38
+ mismatched file fails the binary check. A version label or unchecked path is no
39
+ longer accepted as a pin. The SDK can otherwise use an existing cache or download
40
+ a server binary. See [API and configuration]({% link _reference/api-and-configuration.md %}).
41
+
42
+ The placeholders above are for diagnostics only. A passing executable check does
43
+ not enable live calls. Doctor still reports Stagehand as unsupported.
44
+
45
+ ## Calibrate the Offline Fixtures
46
+
47
+ From the source checkout, install the development bundle and run:
48
+
49
+ ```sh
50
+ BUNDLE_GEMFILE=gemfiles/local_stagehand.gemfile bundle install
51
+ bin/check-local-stagehand
52
+ ```
53
+
54
+ The runner pins Ruby SDK 3.21.0 and tests its HTTP serializer without starting
55
+ Stagehand. Chrome canaries cover redirects, fetch, images, scripts, frames, popups,
56
+ Worker fetch, and WebSocket upgrade requests. Same-origin and cross-origin controls
57
+ confirm that requests actually arrive. A partial-denial control blocks only the image.
58
+ The runner retains screenshots and request receipts with `qualified: false`.
59
+
60
+ Read [Local Stagehand feasibility]({% link _advanced/local-stagehand-deployment.md %})
61
+ for setup, coverage, and gaps. `bin/check-browser --network` and browser CI also run
62
+ the canary calibration. These tools and dependencies are development-only.
63
+
64
+ ## Find the Documentation from RubyGems
65
+
66
+ The gem's `documentation_uri` now points to the hosted documentation site. The
67
+ packaged guides and examples remain available as Markdown. Runtime dependencies
68
+ and the Rails database schema do not change in this release.
69
+
70
+ ## Live Support Remains Incomplete
71
+
72
+ Version 0.4.4 supports offline operations through FakeBackend. It does not complete
73
+ the original live-deployment milestone. Enforced browser egress, connection-time
74
+ DNS/IP checks, an independent lifecycle supervisor, expiry, and confirmed cleanup
75
+ still need deployment-specific evidence. Stagehand and live Act remain disabled.
76
+ No real provider calls or live billing qualification form part of this release.
77
+
78
+ ## Next Steps
79
+
80
+ - Follow [Upgrading]({% link _reference/upgrading.md %}) for the local diagnostic change.
81
+ - Review [the roadmap]({% link _reference/roadmap.md %}) before preparing live tests.
@@ -150,11 +150,25 @@ TTL, billing, final-URL reporting, or cleanup. `end_session` sends no request in
150
150
  release and returns `false`; the operation remains `cleanup_pending`.
151
151
 
152
152
  The constructor accepts `server: :remote`, `base_url:`, `timeout: 60.0`,
153
- `custom_headers_approved: false`, `env: ENV`, and an injected `client:` for internal
153
+ `server_binary_sha256: nil`, `custom_headers_approved: false`, `env: ENV`, and an injected `client:` for internal
154
154
  contract tests. A future live implementation must verify all relevant environment
155
155
  settings, egress across every browser request path, TTL and closure status, and provider
156
156
  billing controls before it can advertise support.
157
157
 
158
+ For local diagnostics, set process-level `STAGEHAND_SEA_BINARY` to an absolute path
159
+ and supply the host-approved lowercase SHA-256 as `server_binary_sha256:`. The file
160
+ must be a regular executable. The adapter checks its current bytes when reporting
161
+ capabilities and before constructing the SDK client. An injected `env:` must select
162
+ the same path as the real process environment. These checks do not execute the file.
163
+
164
+ `STAGEHAND_SERVER_VERSION` alone does not establish a pin. Stagehand 3.21.0 checks
165
+ its version-independent server cache before consulting that variable, and may download
166
+ on a cache miss. An explicit matching executable avoids both paths. Obtain the expected
167
+ digest through your host's artifact review; computing a digest of an untrusted file
168
+ does not establish trust. Protect the executable and its parent directories from
169
+ replacement during use. Hash checks do not provide filesystem isolation or make the
170
+ unsupported adapter live-ready.
171
+
158
172
  ## Configuration diagnostics
159
173
 
160
174
  For diagnostics without network requests, use `Doctor.new(backend:).report`. It
@@ -18,7 +18,8 @@ release notes to identify the exact source for this version.
18
18
 
19
19
  | Release | Date | Highlights |
20
20
  | --- | --- | --- |
21
- | [0.3.0]({% link _getting_started/whats-new-in-0-3.md %}) | 2026-10-19 | Opt-in Rails result delivery, durable host example, recovery and upgrade verification |
21
+ | [0.4.4]({% link _getting_started/whats-new-in-0-4.md %}) | 2026-10-21 | Verified local executable identity, pinned SDK contracts, and offline browser network canaries |
22
+ | [0.3.0]({% link _reference/whats-new-in-0-3.md %}) | 2026-10-19 | Opt-in Rails result delivery, durable host example, recovery and upgrade verification |
22
23
  | [0.2.0]({% link _reference/whats-new-in-0-2.md %}) | 2026-10-19 | Read-only tool factory, backend-aware Doctor, and agent development/browser verification |
23
24
  | [0.1.0](https://github.com/yorzi/ruby_llm-browser/releases/tag/v0.1.0) | 2026-10-18 | Offline read-only Inspect and Extract, Rails adapter, and Act simulation; live Stagehand and live Act are unsupported |
24
25
 
@@ -42,14 +42,15 @@ feedback to settle the public API.
42
42
  | --- | --- | --- |
43
43
  | 0.2.0 | Easier tool setup and clearer offline diagnostics | Two additive features, tested with no provider requests |
44
44
  | 0.3.0 | Usable Rails result delivery | A host can retrieve a job's result after the worker exits |
45
- | 0.4.0 | One supported live read-only deployment | Egress, final URL, session expiry and cleanup qualified on that deployment |
45
+ | 0.4.4 | Offline local Stagehand groundwork | Executable identity checks and calibrated browser fixtures |
46
+ | Next live milestone | One supported live read-only deployment | Egress, final URL, session expiry and cleanup qualified on that deployment |
46
47
  | 0.5.0 | Pilot feedback and recovery hardening | Plain-Ruby and Rails workflows exercised outside the test suite |
47
48
  | 1.0.0-rc.1 | Stable API candidate | Feature freeze, complete upgrade instructions, candidate package verified |
48
49
  | 1.0.0 | Supported read-only integration | All acceptance criteria below pass on the release candidate |
49
50
 
50
51
  ### 0.2.0: Two Small Features
51
52
 
52
- Version `0.2.0` adds both features below. Milestones after 0.3 remain proposed scope. See
53
+ Version `0.2.0` adds both features below. Live-deployment milestones remain proposed scope. See
53
54
  [What's New]({% link _reference/whats-new-in-0-2.md %}) for usage and
54
55
  [development and testing]({% link _advanced/development-and-testing.md %}) for validation.
55
56
 
@@ -75,7 +76,7 @@ validation precede the release tag and publication.
75
76
 
76
77
  Version `0.3.0` implements `Rails.result_delivery`, typed
77
78
  host-delivery failures, and a runnable SQLite host example with separate workers.
78
- Read [What's New in 0.3]({% link _getting_started/whats-new-in-0-3.md %}) and
79
+ Read [What's New in 0.3]({% link _reference/whats-new-in-0-3.md %}) and
79
80
  [Rails Result Delivery]({% link _advanced/result-delivery.md %}) for the current API.
80
81
  The source repository's `docs/evidence/V0_3_VALIDATION.md` records local candidate
81
82
  checks. `docs/evidence/V0_3_RELEASE.md` records remote verification and publication.
@@ -91,7 +92,15 @@ A delivery failure must be visible and must never cause the browser operation to
91
92
  again. Document delivery semantics, duplicate handling, and recovery separately from
92
93
  the operation's session state. Verify generator upgrades preserve existing records.
93
94
 
94
- ### 0.4.0: Qualify One Live Read-only Deployment
95
+ ### 0.4.4: Offline Local Stagehand Groundwork
96
+
97
+ Version 0.4.4 includes the executable identity fix, pinned SDK contracts,
98
+ browser canaries, and hosted documentation metadata fix. Read
99
+ [What's New in 0.4]({% link _getting_started/whats-new-in-0-4.md %}). This release ships the offline
100
+ foundation; the original live-deployment milestone remains open. It does not satisfy
101
+ the live acceptance criteria below or advance the project to the pilot stage.
102
+
103
+ ### Next Live Milestone: Qualify One Read-only Deployment
95
104
 
96
105
  Begin with a feasibility check of the pinned SDK and a named deployment. Determine
97
106
  whether the deployment can enforce every required browser request boundary and report
@@ -108,6 +117,13 @@ Prepare the fixtures and opt-in qualification runner offline first. Live runs re
108
117
  separate owner authorization for the deployment, data, and spending. Keep default CI
109
118
  offline. Report provider billing controls separately from the advisory cost field.
110
119
 
120
+ The selected target is a pinned local Stagehand deployment with a host-controlled
121
+ browser network. Version 0.4.4 includes executable checksum checks, local SDK
122
+ HTTP contracts, and calibrated loopback browser canaries. See
123
+ [Local Stagehand feasibility]({% link _advanced/local-stagehand-deployment.md %}). These
124
+ are offline foundations. The browser namespace, egress gateway, independent lifecycle
125
+ supervisor, server artifact compatibility, and live acceptance remain incomplete.
126
+
111
127
  If the deployment cannot meet the required controls, stop this milestone and record
112
128
  the gap. Keep live support disabled. Do not replace qualification with a boolean flag
113
129
  or promote an offline-only package to 1.0 under this plan.
@@ -2,7 +2,7 @@
2
2
  layout: default
3
3
  title: Upgrading
4
4
  nav_order: 2
5
- description: Upgrade from 0.2.0 while preserving operation data and configuring optional Rails result delivery.
5
+ description: Upgrade from 0.3.0 and configure verified local Stagehand executable identity for offline diagnostics.
6
6
  ---
7
7
 
8
8
  # {{ page.title }}
@@ -11,11 +11,11 @@ description: Upgrade from 0.2.0 while preserving operation data and configuring
11
11
 
12
12
  After reading this guide, you will know:
13
13
 
14
- - How to update an application from 0.2.0.
15
- - How to preserve existing data and enable result delivery.
16
- - Which result and worker behaviors change.
14
+ - How to update an application from 0.3.0.
15
+ - Why local binary diagnostics require a checksum.
16
+ - Which existing workflows stay supported.
17
17
 
18
- ## Upgrade from 0.2.0
18
+ ## Upgrade from 0.3.0
19
19
 
20
20
  Update your Gemfile and bundle:
21
21
 
@@ -27,41 +27,40 @@ gem "ruby_llm-browser", "~> {{ site.version }}"
27
27
  bundle update ruby_llm-browser
28
28
  ```
29
29
 
30
- This release adds no gem-managed database migration or runtime dependency. Preserve all
31
- operation, approval, and actor-lock rows. Do not rerun the install generator on an
32
- existing installation. Result storage belongs to your application.
30
+ This release adds no runtime dependency or gem-managed database migration. Preserve
31
+ all operation, approval, and actor-lock rows. Do not rerun the install generator on
32
+ an existing installation. FakeBackend and opt-in Rails result delivery retain their
33
+ existing contracts.
33
34
 
34
- ## Enable Result Delivery When Needed
35
+ ## Supply Local Executable Identity
35
36
 
36
- `RubyLLM::Browser::Rails.result_delivery` defaults to `nil`. Existing job return values
37
- remain supported. To retain results after a worker exits, follow
38
- [Rails Result Delivery]({% link _advanced/result-delivery.md %}). Configure persistence,
39
- authorized reads, idempotent writes, and recovery before enabling the callback.
37
+ The local adapter no longer treats `STAGEHAND_SERVER_VERSION` or an unchecked
38
+ `STAGEHAND_SEA_BINARY` path as a binary pin. Configure an absolute executable path in
39
+ the SDK process environment and pass `server_binary_sha256:` with its host-approved
40
+ lowercase SHA-256 when constructing `StagehandBackend`.
40
41
 
41
- A callback failure raises `Rails::ResultDeliveryError`. Queue retries do not redeliver
42
- a result. The error retains the result only in process; it is not durable storage.
43
- Recover delivery separately from browser execution. A crash before host persistence
44
- can still lose the result, so do not treat this hook as guaranteed delivery.
42
+ The local binary diagnostic fails for missing, nonexecutable, changed, or mismatched
43
+ files. An injected `env:` must select the same path as the actual process environment.
44
+ The adapter checks current file bytes without executing the file. Obtain the expected
45
+ digest through your artifact review and protect the executable during use. See
46
+ [API and configuration]({% link _reference/api-and-configuration.md %}) for the full
47
+ contract. Remote diagnostics do not require this option.
45
48
 
46
- ## Account for Immutable Results and Fenced Workers
47
-
48
- `Result` now also copies and freezes operation ID, error code and error message strings,
49
- consistent with its other fields. Mutating these attributes raises `FrozenError`;
50
- duplicate a string before changing it in host code. Caller-owned inputs stay mutable.
51
-
52
- A worker fenced during browser execution now returns `:fenced_out` and cannot deliver
53
- its stale result. Cancelled work never invokes the delivery hook, including while
54
- cleanup remains pending. Delivery failures do not change the session state or free
55
- quota. Stagehand and live Act remain unsupported.
49
+ Stagehand remains unsupported even when the binary check passes. Do not replace the
50
+ live qualification gate with a capability override. The new browser canaries calibrate
51
+ offline fixtures; they do not establish production isolation or cleanup.
56
52
 
57
53
  ## Earlier Versions
58
54
 
59
- For upgrades from 0.1.0 and earlier development snapshots, first follow the
55
+ For upgrades from 0.2.0, first read the
56
+ [0.3.0 upgrading guide](https://github.com/yorzi/ruby_llm-browser/blob/v0.3.0/docs/_reference/upgrading.md)
57
+ for result delivery, immutable results, worker fencing, and delivery recovery.
58
+ For upgrades from 0.1.0, start with the
60
59
  [0.2.0 upgrading guide](https://github.com/yorzi/ruby_llm-browser/blob/v0.2.0/docs/_reference/upgrading.md).
61
60
  Preserve operation data and use additive migrations where required.
62
61
 
63
62
  ## Next Steps
64
63
 
65
- - Read [What's New in 0.3]({% link _getting_started/whats-new-in-0-3.md %}).
66
- - Review [release history]({% link _reference/release-history.md %}) and
67
- [live-backend qualification]({% link _advanced/live-backend-qualification.md %}).
64
+ - Read [What's New in 0.4]({% link _getting_started/whats-new-in-0-4.md %}).
65
+ - Review [local deployment feasibility]({% link _advanced/local-stagehand-deployment.md %})
66
+ and [release history]({% link _reference/release-history.md %}).
@@ -1,9 +1,8 @@
1
1
  ---
2
2
  layout: default
3
3
  title: What's New in 0.3
4
- redirect_from:
5
- - /whats-new/
6
- nav_order: 4
4
+ parent: Release History
5
+ nav_order: 3
7
6
  description: Deliver Rails background results to host storage without repeating browser work on delivery failure.
8
7
  ---
9
8
 
@@ -98,11 +98,11 @@ module RubyLLM
98
98
  return nil unless backend&.capabilities&.local_mode?
99
99
 
100
100
  if backend.capabilities.local_binary_pinned?
101
- check(:local_binary, :pass, "local mode uses a host-pinned server binary or version")
101
+ check(:local_binary, :pass, "local mode reports a verified host-pinned executable")
102
102
  else
103
103
  check(:local_binary, :fail,
104
- "local mode has no host-pinned #{StagehandBackend::PINNED_BINARY_ENV} or " \
105
- "#{StagehandBackend::PINNED_VERSION_ENV}; the SDK would download a binary")
104
+ "local mode requires an absolute executable #{StagehandBackend::PINNED_BINARY_ENV} " \
105
+ "matching server_binary_sha256 in the SDK process environment")
106
106
  end
107
107
  end
108
108
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "digest"
4
+
3
5
  module RubyLLM
4
6
  module Browser
5
7
  # An experimental {Backend} adapter for the official `stagehand` Ruby SDK.
@@ -13,8 +15,8 @@ module RubyLLM
13
15
  # the SDK otherwise retries errors and timeouts
14
16
  # - never returns `cdp_url`, cookies or credentials, and reports the pinned API keys
15
17
  # as secret literals so they are scrubbed from page text and results
16
- # - refuses to construct a live client in local mode unless a host-pinned server
17
- # binary or version is present, so it never triggers the SDK's runtime download
18
+ # - refuses to construct a client in local mode unless an explicit executable
19
+ # matches the host's SHA-256, avoiding the SDK's download and version cache
18
20
  #
19
21
  # The SDK is required lazily, inside {#client}, so requiring this Gem never reads
20
22
  # Stagehand environment variables and never starts or downloads a server.
@@ -38,13 +40,15 @@ module RubyLLM
38
40
  # @param base_url [String, nil] explicit endpoint; defaults to the official remote
39
41
  # endpoint. Never read from the environment.
40
42
  # @param timeout [Numeric] per-request timeout in seconds
43
+ # @param server_binary_sha256 [String, nil] host-approved lowercase SHA-256 of
44
+ # the executable selected by process-level `STAGEHAND_SEA_BINARY`
41
45
  # @param custom_headers_approved [Boolean] whether the host approved the SDK's
42
46
  # always-merged `STAGEHAND_CUSTOM_HEADERS`
43
47
  # @param env [Hash] environment to inspect; injectable for tests
44
48
  # @param client [Object, nil] an already-built client (tests/advanced hosts)
45
49
  def initialize(browserbase_api_key:, model_api_key:, model_name:,
46
50
  server: :remote, base_url: nil, timeout: 60.0,
47
- custom_headers_approved: false, env: ENV, client: nil)
51
+ server_binary_sha256: nil, custom_headers_approved: false, env: ENV, client: nil)
48
52
  super()
49
53
  @browserbase_api_key = presence!(browserbase_api_key, :browserbase_api_key)
50
54
  @model_api_key = presence!(model_api_key, :model_api_key)
@@ -52,22 +56,14 @@ module RubyLLM
52
56
  @server = server_mode!(server)
53
57
  @base_url = base_url.nil? ? default_base_url : presence!(base_url, :base_url)
54
58
  @timeout = positive_number!(timeout, :timeout)
59
+ @server_binary_sha256 = checksum!(server_binary_sha256)
55
60
  @env = env
56
61
  @environment_snapshot = relevant_environment(env)
57
62
  @process_environment_snapshot = relevant_environment(ENV)
58
63
  @custom_headers_present = !env[CUSTOM_HEADERS_ENV].to_s.empty? || !ENV[CUSTOM_HEADERS_ENV].to_s.empty?
59
64
  @custom_headers_approved = !!custom_headers_approved
60
- @local_binary_pinned = local? && pinned_binary?
61
65
  @client_mutex = Mutex.new
62
66
  @client = client
63
- @capabilities = Capabilities.new(
64
- server_mode: local? ? :local : :remote,
65
- egress_isolation: :unverified,
66
- local_binary_pinned: @local_binary_pinned,
67
- custom_headers_present: @custom_headers_present,
68
- custom_headers_approved: @custom_headers_approved,
69
- act_supported: false
70
- )
71
67
  end
72
68
 
73
69
  # The pinned credential literals, so the redactor scrubs them from any page text
@@ -75,10 +71,11 @@ module RubyLLM
75
71
  def secrets = [ @browserbase_api_key, @model_api_key ]
76
72
 
77
73
  def capabilities
78
- return @capabilities if environment_unchanged?
79
-
74
+ unchanged = environment_unchanged?
80
75
  Capabilities.new(server_mode: local? ? :local : :remote, egress_isolation: :unverified,
81
- custom_headers_present: true, custom_headers_approved: false,
76
+ local_binary_pinned: local? && unchanged && pinned_binary?,
77
+ custom_headers_present: unchanged ? @custom_headers_present : true,
78
+ custom_headers_approved: unchanged && @custom_headers_approved,
82
79
  act_supported: false)
83
80
  end
84
81
 
@@ -178,8 +175,8 @@ module RubyLLM
178
175
 
179
176
  def build_client
180
177
  raise UnsupportedSecurityCapability, "Stagehand environment changed; rebuild the backend" unless environment_unchanged?
181
- if local? && ENV[PINNED_BINARY_ENV].to_s.empty? && ENV[PINNED_VERSION_ENV].to_s.empty?
182
- raise UnsupportedSecurityCapability, "local mode requires a process-level server pin"
178
+ if local? && !pinned_binary?
179
+ raise UnsupportedSecurityCapability, "local mode requires an executable matching the host checksum"
183
180
  end
184
181
  require "stagehand"
185
182
  Stagehand::Client.new(
@@ -279,7 +276,24 @@ module RubyLLM
279
276
  end
280
277
 
281
278
  def pinned_binary?
282
- !@env[PINNED_BINARY_ENV].to_s.empty? || !@env[PINNED_VERSION_ENV].to_s.empty?
279
+ return false unless @server_binary_sha256
280
+
281
+ path = @env[PINNED_BINARY_ENV].to_s
282
+ return false unless path.start_with?("/") && path == ENV[PINNED_BINARY_ENV]
283
+ return false unless File.file?(path) && File.executable?(path)
284
+
285
+ Digest::SHA256.file(path).hexdigest == @server_binary_sha256
286
+ rescue SystemCallError, IOError
287
+ false
288
+ end
289
+
290
+ def checksum!(value)
291
+ return nil if value.nil?
292
+ unless value.is_a?(String) && /\A[0-9a-f]{64}\z/.match?(value)
293
+ raise InvalidInput, "server_binary_sha256 must be a lowercase SHA-256 digest"
294
+ end
295
+
296
+ value.dup.freeze
283
297
  end
284
298
 
285
299
  def default_base_url
@@ -4,6 +4,6 @@ module RubyLLM
4
4
  module Browser
5
5
  # The Gem version. Development happens ahead of any public release: the packaged
6
6
  # version is not a RubyGems publication claim.
7
- VERSION = "0.3.0"
7
+ VERSION = "0.4.4"
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_llm-browser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Wang
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-19 00:00:00.000000000 Z
11
+ date: 2026-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby_llm
@@ -173,6 +173,7 @@ files:
173
173
  - docs/WORK.md
174
174
  - docs/_advanced/development-and-testing.md
175
175
  - docs/_advanced/live-backend-qualification.md
176
+ - docs/_advanced/local-stagehand-deployment.md
176
177
  - docs/_advanced/rails-integration.md
177
178
  - docs/_advanced/result-delivery.md
178
179
  - docs/_config.yml
@@ -187,7 +188,7 @@ files:
187
188
  - docs/_getting_started/configuration.md
188
189
  - docs/_getting_started/getting-started.md
189
190
  - docs/_getting_started/overview.md
190
- - docs/_getting_started/whats-new-in-0-3.md
191
+ - docs/_getting_started/whats-new-in-0-4.md
191
192
  - docs/_plugins/versioned_docs.rb
192
193
  - docs/_reference/api-and-configuration.md
193
194
  - docs/_reference/api-reference.md
@@ -195,6 +196,7 @@ files:
195
196
  - docs/_reference/roadmap.md
196
197
  - docs/_reference/upgrading.md
197
198
  - docs/_reference/whats-new-in-0-2.md
199
+ - docs/_reference/whats-new-in-0-3.md
198
200
  - docs/bin/build-api.sh
199
201
  - docs/bin/build.sh
200
202
  - docs/bin/export-api-markdown.rb
@@ -251,6 +253,7 @@ licenses:
251
253
  - MIT
252
254
  metadata:
253
255
  source_code_uri: https://github.com/yorzi/ruby_llm-browser
256
+ documentation_uri: https://rubyllm-browser.wangyaodi.com
254
257
  changelog_uri: https://github.com/yorzi/ruby_llm-browser/blob/main/CHANGELOG.md
255
258
  bug_tracker_uri: https://github.com/yorzi/ruby_llm-browser/issues
256
259
  rubygems_mfa_required: 'true'