@seanyao/roll 4.714.2 → 4.717.2
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.
- package/CHANGELOG.md +94 -0
- package/README.md +13 -2
- package/dist/postinstall.mjs +28 -1
- package/dist/roll.mjs +15323 -6812
- package/docs/architecture.md +2 -0
- package/guide/INDEX.md +2 -0
- package/guide/en/acceptance-evidence.md +66 -0
- package/guide/en/ai-agents.md +7 -7
- package/guide/en/browser-operations.md +711 -0
- package/guide/en/faq.md +64 -0
- package/guide/en/loop.md +96 -7
- package/guide/en/pairing.md +4 -5
- package/guide/en/tools.md +11 -0
- package/guide/zh/acceptance-evidence.md +59 -0
- package/guide/zh/ai-agents.md +5 -5
- package/guide/zh/browser-operations.md +632 -0
- package/guide/zh/faq.md +62 -0
- package/guide/zh/loop.md +90 -7
- package/guide/zh/pairing.md +3 -4
- package/guide/zh/tools.md +11 -0
- package/package.json +2 -1
- package/skills/roll-build/SKILL.md +2 -1
- package/skills/roll-build/references/full-contract.md +20 -16
|
@@ -0,0 +1,711 @@
|
|
|
1
|
+
# Roll — Browser Operations (managed + interactive lanes)
|
|
2
|
+
|
|
3
|
+
Roll can drive a **managed, isolated Chrome via the real `chrome-devtools-mcp` sidecar**
|
|
4
|
+
to collect browser diagnostics — navigation checks, DOM snapshots, console and
|
|
5
|
+
network capture, and diagnostic screenshots. Each managed operation spawns a
|
|
6
|
+
pinned-version `chrome-devtools-mcp` stdio session under a temporary Chrome
|
|
7
|
+
profile; the session performs MCP initialize + tools/list, validates a minimum
|
|
8
|
+
tool manifest, and only then executes the requested action. The profile is
|
|
9
|
+
removed afterwards.
|
|
10
|
+
|
|
11
|
+
A separate **interactive owner-Chrome lane** supports a single, low-risk
|
|
12
|
+
operation against an already-open localhost debug endpoint, with foreground
|
|
13
|
+
owner approval and strict lease controls.
|
|
14
|
+
|
|
15
|
+
Both lanes are opt-in, dependency-gated, and deliberately narrow.
|
|
16
|
+
|
|
17
|
+
Two things they are **not**:
|
|
18
|
+
|
|
19
|
+
- They are **not** installers. Roll never adds a dependency to your product
|
|
20
|
+
repo's `package.json`, and never enables remote debugging on your own
|
|
21
|
+
(owner) Chrome. Setup only writes a machine-level config after you confirm.
|
|
22
|
+
- Their output is **not** visual acceptance evidence. A managed diagnostic
|
|
23
|
+
screenshot or an interactive owner-run result proves a page action succeeded;
|
|
24
|
+
neither satisfies a story's visual AC. Only **Roll Capture** (a physical
|
|
25
|
+
screenshot of your real terminal/app) satisfies visual acceptance — see
|
|
26
|
+
[Acceptance evidence](acceptance-evidence.md).
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Privacy & Security Boundaries
|
|
31
|
+
|
|
32
|
+
These invariants hold across every operation, managed or interactive:
|
|
33
|
+
|
|
34
|
+
- **Temporary profile only.** Managed Chrome runs under a fresh temporary
|
|
35
|
+
profile that is deleted after the operation. Owner browser state (cookies,
|
|
36
|
+
logins, history, localStorage) is never entered, read, or exported.
|
|
37
|
+
- **No credential export.** Cookies, storage, and network bodies have no CLI
|
|
38
|
+
or adapter surface. Neither lane can export owner credentials.
|
|
39
|
+
- **Telemetry disabled.** `chrome-devtools-mcp` is started with
|
|
40
|
+
`--no-usage-statistics`. No data is sent to Chrome, CrUX, Lighthouse, or
|
|
41
|
+
any external telemetry service.
|
|
42
|
+
- **Bounded, redacted diagnostics.** Diagnostic artifacts (console summaries,
|
|
43
|
+
network metadata, performance counters) are bounded to a fixed allowlist of
|
|
44
|
+
numeric metrics and redacted of URLs, resource names, and traces. See
|
|
45
|
+
[Optional diagnostic profiles](#optional-diagnostic-profiles).
|
|
46
|
+
- **No generic MCP bypass.** Only the pinned `chrome-devtools-mcp` transport
|
|
47
|
+
is registered for browser operations. A generic `mcp.call` directed at
|
|
48
|
+
DevTools is rejected (fail-closed).
|
|
49
|
+
- **DevTools artifacts never satisfy visual AC.** Diagnostic screenshots and
|
|
50
|
+
DOM snapshots are classified as diagnostic-only; they cannot earn a
|
|
51
|
+
visual-acceptance verdict. See [Evidence boundary](#evidence-boundary).
|
|
52
|
+
- **No automatic Chrome startup.** Roll never launches or closes your owner
|
|
53
|
+
Chrome. The interactive lane connects only to a Chrome debug endpoint you
|
|
54
|
+
started yourself on a loopback address.
|
|
55
|
+
- **Machine-level config only.** Setup writes `~/.roll/browser-operations.yaml`
|
|
56
|
+
— never a product repo file — and only with `--confirm`.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Managed Lane
|
|
61
|
+
|
|
62
|
+
The managed lane is the **primary browser-operation path**. It launches Chrome
|
|
63
|
+
under a fresh temporary profile, spawns the pinned `chrome-devtools-mcp` sidecar,
|
|
64
|
+
runs one operation against an allowlisted target, and removes the profile
|
|
65
|
+
afterwards.
|
|
66
|
+
|
|
67
|
+
### Prerequisites & Doctor
|
|
68
|
+
|
|
69
|
+
The managed lane needs the pinned `chrome-devtools-mcp` transport and a Chrome
|
|
70
|
+
binary. Roll does not install these — it reports what is missing and how to fix
|
|
71
|
+
it. Start with the static doctor:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
roll browser doctor
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
Browser operations doctor
|
|
79
|
+
浏览器操作体检
|
|
80
|
+
|
|
81
|
+
~ managed: degraded — chrome-devtools-mcp not ready; existing Playwright and Roll Capture paths remain usable
|
|
82
|
+
→ roll browser setup --dry-run
|
|
83
|
+
→ install the missing dependency, then re-run roll browser doctor
|
|
84
|
+
✓ interactive: ready owner Chrome reachable on 127.0.0.1:9222
|
|
85
|
+
~ capture: degraded — Roll Capture readiness probe skipped (headless / CI / ROLL_NO_SCREENCAP).
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Each lane reports one of three honest states:
|
|
89
|
+
|
|
90
|
+
| State | Meaning |
|
|
91
|
+
|-------|---------|
|
|
92
|
+
| `ready` | The lane's prerequisites are satisfied. |
|
|
93
|
+
| `degraded` | The lane is unavailable or partially available. Existing Playwright and Roll Capture paths keep working — a missing prerequisite is never reported as a pass. |
|
|
94
|
+
| `blocked` | A hard precondition prevents the lane from running; the reason and repair command are printed. |
|
|
95
|
+
|
|
96
|
+
The static doctor inspects the machine environment and configuration. It does
|
|
97
|
+
**not** spawn `chrome-devtools-mcp` — a `ready` verdict from the static doctor
|
|
98
|
+
means the binary and config are present; it does not prove the MCP sidecar
|
|
99
|
+
initializes correctly.
|
|
100
|
+
|
|
101
|
+
### Live MCP Probe (`doctor --probe`)
|
|
102
|
+
|
|
103
|
+
`doctor --probe` runs a **real, temporary `chrome-devtools-mcp` session** to
|
|
104
|
+
validate the full transport lifecycle end-to-end. Only a successful probe
|
|
105
|
+
advances the managed lane to `ready` in the doctor output.
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
roll browser doctor --probe
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
Browser operations doctor --probe
|
|
113
|
+
浏览器操作体检 --probe
|
|
114
|
+
|
|
115
|
+
⏳ Running live MCP lane probe — this will:
|
|
116
|
+
1. Spawn the pinned chrome-devtools-mcp session (temporary process)
|
|
117
|
+
2. Run MCP initialize + tools/list + manifest validation
|
|
118
|
+
3. Close the session and clean up the temporary Chrome profile
|
|
119
|
+
The probe may take a few seconds. No owner state enters the temporary profile.
|
|
120
|
+
|
|
121
|
+
⏳ 正在运行实时 MCP 通道探测——将会:
|
|
122
|
+
1. 启动固定版本的 chrome-devtools-mcp 会话(临时进程)
|
|
123
|
+
2. 运行 MCP initialize + tools/list + 清单验证
|
|
124
|
+
3. 关闭会话并清理临时 Chrome 档案
|
|
125
|
+
探测可能需要几秒。绝不会进入 owner 状态。
|
|
126
|
+
|
|
127
|
+
✅ Live probe passed — managed lane is ready.
|
|
128
|
+
✅ 实时探测通过——受管通道就绪。
|
|
129
|
+
|
|
130
|
+
✓ managed: ready chrome-devtools-mcp 1.5.0 (8 tools) — live probe passed
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The probe lifecycle:
|
|
134
|
+
|
|
135
|
+
1. **Spawn** — a temporary `chrome-devtools-mcp` stdio process starts with the
|
|
136
|
+
pinned version and `--no-usage-statistics`.
|
|
137
|
+
2. **Initialize** — MCP `initialize` handshake completes.
|
|
138
|
+
3. **Validate** — `tools/list` runs; the response is checked against the minimum
|
|
139
|
+
tool manifest (navigate, snapshot, console, network, screenshot).
|
|
140
|
+
4. **Close & clean** — the MCP process and temporary Chrome profile are removed.
|
|
141
|
+
|
|
142
|
+
A failed probe categorizes each failure honestly:
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
❌ Live probe failed — see categorized failures below.
|
|
146
|
+
❌ 实时探测失败——见下方分类失败信息。
|
|
147
|
+
transport: chrome-devtools-mcp not installed or not on PATH
|
|
148
|
+
manifest: tool manifest missing required entries (expected: navigate, snapshot, console, network, screenshot; got: [])
|
|
149
|
+
chrome: chrome binary not found at expected path
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Re-run `doctor --probe` after fixing the reported issues. The static doctor
|
|
153
|
+
(without `--probe`) remains available for quick environment checks; it reports
|
|
154
|
+
the lane as `configured` when the binary and config are present but the probe
|
|
155
|
+
has not yet passed.
|
|
156
|
+
|
|
157
|
+
### Setup (dry-run first)
|
|
158
|
+
|
|
159
|
+
`setup --dry-run` shows the exact machine-level config Roll would write and runs
|
|
160
|
+
the dependency preflight. It writes **nothing**:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
roll browser setup --dry-run
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
Browser operations setup
|
|
168
|
+
浏览器操作安装
|
|
169
|
+
|
|
170
|
+
target (machine-level, never committed): ~/.roll/browser-operations.yaml
|
|
171
|
+
|
|
172
|
+
proposed ~/.roll/browser-operations.yaml:
|
|
173
|
+
devtools:
|
|
174
|
+
command: npx
|
|
175
|
+
args: ["-y", "chrome-devtools-mcp@1.5.0", "--no-usage-statistics"]
|
|
176
|
+
package: chrome-devtools-mcp
|
|
177
|
+
package_version: 1.5.0
|
|
178
|
+
chrome_channel: stable
|
|
179
|
+
remote_debugging: { host: "127.0.0.1", port: 9222 }
|
|
180
|
+
...
|
|
181
|
+
Roll never installs into a product package.json and never enables owner Chrome remote debugging.
|
|
182
|
+
Roll 绝不改动产品仓 package.json,也绝不自动开启 owner Chrome 的远程调试。
|
|
183
|
+
|
|
184
|
+
dry-run: no configuration was written.
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Only after you review it do you write the config, and only with explicit
|
|
188
|
+
confirmation:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
roll browser setup --confirm
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Without `--confirm` (and without `--dry-run`), `setup` refuses and writes
|
|
195
|
+
nothing.
|
|
196
|
+
|
|
197
|
+
### Running a Managed Operation (Real MCP Lane)
|
|
198
|
+
|
|
199
|
+
`roll browser run` with `--story` and `--url` executes through the **real,
|
|
200
|
+
policy-gated MCP lane**. This is the production path. The project must first
|
|
201
|
+
opt in via `.roll/policy.yaml` (everything is disabled by default):
|
|
202
|
+
|
|
203
|
+
```yaml
|
|
204
|
+
browser_operations:
|
|
205
|
+
enabled: true
|
|
206
|
+
managed:
|
|
207
|
+
enabled: true
|
|
208
|
+
allowed_origins: [https://example.com]
|
|
209
|
+
allowed_actions: [navigate, snapshot, console, network, screenshot]
|
|
210
|
+
max_runs_per_cycle: 20
|
|
211
|
+
timeout_ms: 30000
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
roll browser run \
|
|
216
|
+
--story US-BROW-021 \
|
|
217
|
+
--url https://example.com \
|
|
218
|
+
--action screenshot
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Verbatim output (captured from a real run, 2026-07-16):
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
Managed browser operation — real MCP
|
|
225
|
+
受管浏览器操作 — 真实 MCP
|
|
226
|
+
|
|
227
|
+
mcp package / MCP 包: 1.5.0
|
|
228
|
+
transport initialized / 传输初始化: yes
|
|
229
|
+
manifest verified / 清单验证: yes
|
|
230
|
+
lane / 通道: managed
|
|
231
|
+
action / 动作: screenshot
|
|
232
|
+
target / 目标: https://example.com
|
|
233
|
+
run state / 运行状态: passed
|
|
234
|
+
result / 结果: pass (action: ok)
|
|
235
|
+
temp profile / 临时档案: removed (owner state never entered / 绝不进入 owner 状态)
|
|
236
|
+
diagnostics / 诊断产物: 1 (diagnostic-only, NOT visual acceptance / 仅诊断,非视觉验收)
|
|
237
|
+
summary / 摘要: diagnostic screenshot recorded
|
|
238
|
+
|
|
239
|
+
Diagnostic success is not visual acceptance evidence.
|
|
240
|
+
诊断通过不等于视觉验收证据。
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Supported actions: `navigate` (default), `snapshot`, `console`, `network`,
|
|
244
|
+
`screenshot`.
|
|
245
|
+
|
|
246
|
+
The MCP session lifecycle is:
|
|
247
|
+
|
|
248
|
+
1. **Policy check** — the project's `.roll/policy.yaml` must enable the managed
|
|
249
|
+
lane (`browser_operations.enabled: true` plus `managed.enabled: true` with an
|
|
250
|
+
origin allowlist). With no explicit policy everything is disabled, and the
|
|
251
|
+
run is **denied** before any process starts.
|
|
252
|
+
2. **Session spawn** — the pinned `chrome-devtools-mcp` starts with a fresh
|
|
253
|
+
temporary Chrome profile.
|
|
254
|
+
3. **MCP handshake** — `initialize` → `tools/list` → manifest validation.
|
|
255
|
+
Any failure here aborts the run (`devtools-error`).
|
|
256
|
+
4. **Action execution** — the requested action runs against the allowlisted
|
|
257
|
+
target.
|
|
258
|
+
5. **Cleanup** — the MCP process group is terminated, including the `npx`
|
|
259
|
+
wrapper and its DevTools server child; the temporary profile is deleted
|
|
260
|
+
(even on timeout or crash). If cleanup cannot be confirmed, the run fails
|
|
261
|
+
loudly and reports `MCP process cleanup failed`; it never claims a clean
|
|
262
|
+
session.
|
|
263
|
+
|
|
264
|
+
A target outside the allowlist — including a redirect away from the requested
|
|
265
|
+
origin — is **denied**, not followed. A `--story` identifier is **required** for
|
|
266
|
+
the real lane; it is recorded in the operation ledger for auditability.
|
|
267
|
+
|
|
268
|
+
#### Blocked / Unavailable Transcript
|
|
269
|
+
|
|
270
|
+
When the managed lane is unavailable or policy-denied, the run fails loud.
|
|
271
|
+
Verbatim output with no `.roll/policy.yaml` present (captured 2026-07-16):
|
|
272
|
+
|
|
273
|
+
```
|
|
274
|
+
Managed browser operation — real MCP
|
|
275
|
+
受管浏览器操作 — 真实 MCP
|
|
276
|
+
|
|
277
|
+
denied / 已拒绝: Browser operations are disabled in project policy
|
|
278
|
+
|
|
279
|
+
Diagnostic success is not visual acceptance evidence.
|
|
280
|
+
诊断通过不等于视觉验收证据。
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Resolve: add the `browser_operations:` opt-in block shown above to
|
|
284
|
+
`.roll/policy.yaml`, run `roll browser doctor --probe` to verify, then retry.
|
|
285
|
+
|
|
286
|
+
Failure modes and their remediation:
|
|
287
|
+
|
|
288
|
+
| Failure | Doctor signal | Fix |
|
|
289
|
+
|---------|--------------|-----|
|
|
290
|
+
| `chrome-devtools-mcp` not installed | `managed: degraded — transport not found` | `npm i -g chrome-devtools-mcp@<version>` or `roll browser setup --confirm` |
|
|
291
|
+
| Chrome binary not found | `managed: degraded — chrome not found` | Install Chrome (stable channel) |
|
|
292
|
+
| Policy disables managed lane | run → `denied` | Add the `browser_operations:` opt-in block (`enabled: true` + `managed.enabled: true` + origin allowlist) to `.roll/policy.yaml` |
|
|
293
|
+
| MCP handshake fails | `doctor --probe` → `manifest` failure | Check `chrome-devtools-mcp` version; re-run `roll browser update --check` |
|
|
294
|
+
| MCP process crashes mid-run | run → `devtools-error` | Re-run; consistent crashes → `roll browser doctor --probe` |
|
|
295
|
+
| Run timeout | run → `timeout` | Target may be slow; profile cleaned up regardless |
|
|
296
|
+
|
|
297
|
+
### Fixture Path (Test-Only)
|
|
298
|
+
|
|
299
|
+
A `--fixture` flag runs a **fake-target path** for testing seams and exploring
|
|
300
|
+
the lane's reporting without a real MCP process. It is **not** a managed lane
|
|
301
|
+
fallback — the fixture uses hardcoded test data and never proves the real MCP
|
|
302
|
+
transport works.
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
roll browser run --fixture --action screenshot
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
```
|
|
309
|
+
Managed browser operation — fixture (fake target)
|
|
310
|
+
受管浏览器操作 — fixture(假目标)
|
|
311
|
+
|
|
312
|
+
lane / 通道: managed (fixture — TEST ONLY / 仅测试)
|
|
313
|
+
action / 动作: screenshot
|
|
314
|
+
target / 目标: https://fake.target.test
|
|
315
|
+
run state / 运行状态: passed
|
|
316
|
+
result / 结果: pass (action: ok)
|
|
317
|
+
temp profile / 临时档案: removed (owner state never entered / 绝不进入 owner 状态)
|
|
318
|
+
diagnostics / 诊断产物: 1 (diagnostic-only, NOT visual acceptance / 仅诊断,非视觉验收)
|
|
319
|
+
summary / 摘要: diagnostic screenshot captured at https://fake.target.test
|
|
320
|
+
|
|
321
|
+
Diagnostic success is not visual acceptance evidence.
|
|
322
|
+
诊断通过不等于视觉验收证据。
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
The fixture supports injection flags for exploring failure modes:
|
|
326
|
+
`--fail timeout|crash|devtools-error`, `--redirect <url>`, `--perf-fail`.
|
|
327
|
+
These are test-only — they have no effect on the real MCP lane.
|
|
328
|
+
|
|
329
|
+
**A fixture run can never earn a `verified` verdict.** Only the real MCP lane
|
|
330
|
+
(no `--fixture` flag) exercises the actual transport. The live regression gate
|
|
331
|
+
(see below) enforces this at the CI level: a `fixture`-sourced report can
|
|
332
|
+
exercise seams but can never produce a `verified` result.
|
|
333
|
+
|
|
334
|
+
### Transport Updates
|
|
335
|
+
|
|
336
|
+
The DevTools transport version is **pinned**. `update --check` compares the
|
|
337
|
+
pinned version against a candidate without downloading or changing anything:
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
roll browser update --check
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Applying an update is gated the same way as setup — it requires explicit
|
|
344
|
+
confirmation, runs a smoke check, then a **real MCP probe**, and keeps the
|
|
345
|
+
prior version intact on any failure:
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
roll browser update --apply --confirm
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
The update lifecycle:
|
|
352
|
+
|
|
353
|
+
1. **Check** — compare pinned version against the candidate.
|
|
354
|
+
2. **Smoke check** — validate the candidate binary starts.
|
|
355
|
+
3. **MCP probe** — `doctor --probe` runs against the candidate version.
|
|
356
|
+
If the probe fails, the update is **aborted** and the prior version is
|
|
357
|
+
kept intact.
|
|
358
|
+
4. **Apply** — only if smoke + probe both pass, the config is rewritten
|
|
359
|
+
and the new version becomes the pinned transport.
|
|
360
|
+
|
|
361
|
+
```
|
|
362
|
+
Update applied: 1.5.0 → 1.6.0
|
|
363
|
+
更新已应用:1.5.0 → 1.6.0
|
|
364
|
+
wrote: ~/.roll/browser-operations.yaml
|
|
365
|
+
|
|
366
|
+
smoke check: passed
|
|
367
|
+
冒烟检查:通过
|
|
368
|
+
|
|
369
|
+
MCP probe: passed (1.6.0)
|
|
370
|
+
MCP 探测:通过 (1.6.0)
|
|
371
|
+
|
|
372
|
+
✓ managed: ready chrome-devtools-mcp 1.6.0 (8 tools) — live probe passed
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
A failed update keeps the prior version:
|
|
376
|
+
|
|
377
|
+
```
|
|
378
|
+
Update aborted: live MCP probe failed for 1.6.0
|
|
379
|
+
更新中止:1.6.0 实时 MCP 探测失败
|
|
380
|
+
|
|
381
|
+
Prior version 1.5.0 is kept intact.
|
|
382
|
+
已保留原版本 1.5.0。
|
|
383
|
+
|
|
384
|
+
transport: process exited before initialize completed
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## Optional Diagnostic Profiles
|
|
390
|
+
|
|
391
|
+
The managed lane ships two **optional, opt-in** diagnostic profiles: a
|
|
392
|
+
performance profile and a small set of device-emulation profiles. Both run only
|
|
393
|
+
inside the managed isolated lane (real MCP path), and both produce
|
|
394
|
+
**diagnostic-only** material.
|
|
395
|
+
|
|
396
|
+
Read the boundary before adopting them:
|
|
397
|
+
|
|
398
|
+
- They are **opt-in**. Nothing collects a profile unless you explicitly select
|
|
399
|
+
one on the command line; the baseline managed operation is unchanged when no
|
|
400
|
+
profile is requested.
|
|
401
|
+
- Their output is **diagnostic-only**, never visual acceptance evidence and
|
|
402
|
+
never a multi-browser test matrix. A profile summary proves a local diagnostic
|
|
403
|
+
ran; it does not satisfy a story's visual AC. Use
|
|
404
|
+
[Roll Capture](acceptance-evidence.md) for visual acceptance.
|
|
405
|
+
- They **minimize data** and send nothing off the machine.
|
|
406
|
+
|
|
407
|
+
### Performance Profile (opt-in)
|
|
408
|
+
|
|
409
|
+
`--perf-profile web-vitals-lite` collects a bounded, redacted set of local
|
|
410
|
+
DevTools performance counters (documents, frames, layout/style counts and
|
|
411
|
+
durations, script/task durations, JS heap size — a fixed allowlist of numeric
|
|
412
|
+
metrics). It is disabled unless you select it, and selecting it is what flips the
|
|
413
|
+
lane's performance-diagnostics policy on.
|
|
414
|
+
|
|
415
|
+
```bash
|
|
416
|
+
roll browser run --story US-BROW-021 --url https://example.test --perf-profile web-vitals-lite
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
```
|
|
420
|
+
perf profile / 性能诊断: web-vitals-lite (opt-in, diagnostic-only / 需选启,仅诊断)
|
|
421
|
+
metrics / 指标 (12, bounded & redacted / 有界脱敏):
|
|
422
|
+
- LayoutCount: 3
|
|
423
|
+
- ScriptDuration: 0.021
|
|
424
|
+
...
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
Data-minimization and scope guarantees:
|
|
428
|
+
|
|
429
|
+
- **Only numeric metric names in the profile allowlist survive.** No URL,
|
|
430
|
+
resource name, or trace is ever retained, so the profile cannot become an
|
|
431
|
+
analytics or evidence channel.
|
|
432
|
+
- **No external telemetry.** Nothing is uploaded to CrUX, Lighthouse, or any
|
|
433
|
+
other service. Adding an external upload would require a separately designed,
|
|
434
|
+
consent-gated policy contract.
|
|
435
|
+
- **Graceful degradation.** If collection fails, the run reports
|
|
436
|
+
`degraded — no signal collected` and the underlying action verdict is
|
|
437
|
+
unchanged.
|
|
438
|
+
|
|
439
|
+
An unknown profile name is denied fail-fast, not silently ignored.
|
|
440
|
+
|
|
441
|
+
### Device-Emulation Profiles (opt-in)
|
|
442
|
+
|
|
443
|
+
`--profile <name>` runs the managed operation under a named Chrome
|
|
444
|
+
device/viewport profile. The allowlist is finite — callers cannot submit
|
|
445
|
+
arbitrary DevTools emulation parameters:
|
|
446
|
+
|
|
447
|
+
| Profile | Viewport | Scale | Mobile |
|
|
448
|
+
|---------|----------|-------|--------|
|
|
449
|
+
| `Pixel 7` | 412 × 915 | 2.625 | yes |
|
|
450
|
+
| `iPhone 14` | 390 × 844 | 3 | yes |
|
|
451
|
+
| `iPad Pro` | 1024 × 1366 | 2 | no |
|
|
452
|
+
|
|
453
|
+
```bash
|
|
454
|
+
roll browser run --story US-BROW-021 --url https://example.test --action screenshot --profile "iPhone 14"
|
|
455
|
+
# device profile / 设备仿真: iPhone 14
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
Scope guarantees:
|
|
459
|
+
|
|
460
|
+
- **Finite allowlist only.** An unknown profile name is denied fail-fast; there
|
|
461
|
+
is no way to pass raw emulation parameters through it.
|
|
462
|
+
- **This is Chrome DevTools emulation, not a multi-browser matrix.** Comparing
|
|
463
|
+
declared viewport behavior is in scope; a real cross-browser (Playwright-style)
|
|
464
|
+
farm is explicitly out of scope and would need a separately designed proposal.
|
|
465
|
+
- **Security invariants are unchanged.** A device profile does not alter origin
|
|
466
|
+
policy, temporary-profile cleanup, Capture verdicts, or interactive
|
|
467
|
+
owner-Chrome behavior.
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## Interactive Lane
|
|
472
|
+
|
|
473
|
+
The interactive lane lets you run **one low-risk owner-Chrome operation** at a
|
|
474
|
+
time against a page you already have open in your own Chrome. It is designed
|
|
475
|
+
for manual attest workflows, not background automation.
|
|
476
|
+
|
|
477
|
+
### What you must set up first
|
|
478
|
+
|
|
479
|
+
Roll **does not start Chrome for you** and **does not enable remote debugging**.
|
|
480
|
+
You must launch your own Chrome with a loopback debug endpoint before running
|
|
481
|
+
`roll browser interactive`:
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
|
|
485
|
+
--remote-debugging-port=9222 \
|
|
486
|
+
--user-data-dir=/tmp/owner-chrome-profile
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
Only `127.0.0.1:9222` (or another loopback address) is allowed. Non-loopback
|
|
490
|
+
endpoints are rejected.
|
|
491
|
+
|
|
492
|
+
### Run an interactive operation
|
|
493
|
+
|
|
494
|
+
```bash
|
|
495
|
+
roll browser interactive \
|
|
496
|
+
--story US-EXAMPLE-001 \
|
|
497
|
+
--origin https://example.test \
|
|
498
|
+
--action navigate --url https://example.test/login
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
Supported actions: `navigate`, `click`, `fill`, `press_key`.
|
|
502
|
+
|
|
503
|
+
The command requires an **attached TTY**. It prints exactly what it will do,
|
|
504
|
+
including the story, origin, action, and a 15-minute maximum lease, then asks
|
|
505
|
+
for **one owner approval**:
|
|
506
|
+
|
|
507
|
+
```
|
|
508
|
+
Owner Chrome approval required (one operation only)
|
|
509
|
+
story: US-EXAMPLE-001
|
|
510
|
+
origin: https://example.test
|
|
511
|
+
action: navigate to https://example.test
|
|
512
|
+
expiry: 2026-07-15T08:34:00.000Z (15 minutes maximum)
|
|
513
|
+
credential export: denied (cookies, storage, and network bodies are unavailable)
|
|
514
|
+
Approve this owner-run operation? [y/N]
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
If you decline, no connection is attempted. If you approve, Roll connects to
|
|
518
|
+
the local debug endpoint, executes the single operation, prints the result,
|
|
519
|
+
and releases the lease immediately:
|
|
520
|
+
|
|
521
|
+
```
|
|
522
|
+
manual owner-run result: ok (tab: 1234)
|
|
523
|
+
This interactive result does not make CI pass and is not background automation.
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
### Lease expiry and cancellation
|
|
527
|
+
|
|
528
|
+
Each interactive operation holds a lease for **at most 15 minutes**. The lease
|
|
529
|
+
is bound to the holder process and the loopback endpoint; it is released as
|
|
530
|
+
soon as the operation finishes. If the process dies or the lease expires, Roll
|
|
531
|
+
reclaims it automatically. You cannot approve a persistent background lease —
|
|
532
|
+
every operation needs its own foreground approval.
|
|
533
|
+
|
|
534
|
+
### What the interactive lane will never do
|
|
535
|
+
|
|
536
|
+
- Run without an attached TTY and explicit owner approval.
|
|
537
|
+
- Connect to a non-loopback or remote debug endpoint.
|
|
538
|
+
- Export cookies, storage, network bodies, or any other credentials.
|
|
539
|
+
- Start Chrome automatically or leave a background scheduler running.
|
|
540
|
+
- Make CI pass on its own — it is an **owner-run manual-attest** tool only.
|
|
541
|
+
|
|
542
|
+
---
|
|
543
|
+
|
|
544
|
+
## Evidence Boundary
|
|
545
|
+
|
|
546
|
+
Managed browser diagnostics and interactive owner-run results are
|
|
547
|
+
**diagnostic-only / manual-attest only**. Every run report repeats it:
|
|
548
|
+
*diagnostic success is not visual acceptance evidence*. A diagnostic screenshot
|
|
549
|
+
or interactive result is classified as a diagnostic artifact, not a visual-AC
|
|
550
|
+
artifact, so it can never fake a story's visual acceptance. When a story needs
|
|
551
|
+
visual acceptance, use **Roll Capture** — a physical screenshot of your real
|
|
552
|
+
terminal/app — which alone satisfies that requirement. See
|
|
553
|
+
[Acceptance evidence](acceptance-evidence.md).
|
|
554
|
+
|
|
555
|
+
When `roll attest` receives a physical capture response, it writes a validated
|
|
556
|
+
CaptureBridge link to `.roll/browser-operations/events.ndjson`. Doctor, truth,
|
|
557
|
+
and dossier surfaces read that durable fact: a verified `roll.capture.v1`
|
|
558
|
+
physical capture can satisfy a visual AC, while Playwright and DevTools
|
|
559
|
+
diagnostics remain ineligible. With no persisted link, capture truth stays
|
|
560
|
+
honestly unknown and the dossier does not invent a capture event.
|
|
561
|
+
|
|
562
|
+
---
|
|
563
|
+
|
|
564
|
+
## Dossier Timeline (optional)
|
|
565
|
+
|
|
566
|
+
When a story has declared browser-operation facts (ledger start/finish, lease
|
|
567
|
+
grant/expiry/release, or physical-capture results), the delivery dossier shows a
|
|
568
|
+
compact **Browser operations timeline** under Execution. Ordering comes only from
|
|
569
|
+
declared timestamps — missing categories render as honest absences with reasons,
|
|
570
|
+
never an invented stamp or verdict. Redacted diagnostic artifacts and physical
|
|
571
|
+
capture images are linked only when the viewer is authorized under existing
|
|
572
|
+
dossier rules (local href map); otherwise the label stays visible without a
|
|
573
|
+
link. Stories with no browser facts keep the previous dossier shape unchanged.
|
|
574
|
+
|
|
575
|
+
**Unknown and degraded states are shown honestly.** When a category has no
|
|
576
|
+
declared timestamp, the timeline renders it as an explicit absence with the
|
|
577
|
+
reason (for example, *lease: unknown — no grant recorded*) rather than inventing
|
|
578
|
+
a stamp or a verdict. A profile that degraded (see
|
|
579
|
+
[Performance profile](#optional-diagnostic-profiles) above) appears as a
|
|
580
|
+
degraded diagnostic, not a pass. If a timeline row looks unexpectedly empty or
|
|
581
|
+
degraded, follow [Troubleshooting](#troubleshooting) below — a degraded managed
|
|
582
|
+
lane is a missing prerequisite, not a broken delivery.
|
|
583
|
+
|
|
584
|
+
---
|
|
585
|
+
|
|
586
|
+
## Safe Recovery
|
|
587
|
+
|
|
588
|
+
- If `doctor` reports `managed: degraded`, existing Playwright and Roll Capture
|
|
589
|
+
paths remain usable — nothing you already rely on is broken. Install the
|
|
590
|
+
missing dependency and re-run `roll browser doctor --probe`.
|
|
591
|
+
- The temporary profile is always removed after a run; owner Chrome state is
|
|
592
|
+
never entered. If a run is interrupted, re-running is safe — each run starts
|
|
593
|
+
from a fresh profile.
|
|
594
|
+
- Nothing is written to your product repo. The only file Roll may write is the
|
|
595
|
+
machine-level `~/.roll/browser-operations.yaml`, and only with `--confirm`.
|
|
596
|
+
|
|
597
|
+
---
|
|
598
|
+
|
|
599
|
+
## Troubleshooting
|
|
600
|
+
|
|
601
|
+
### `roll browser doctor` reports `managed: degraded`
|
|
602
|
+
|
|
603
|
+
The static doctor found a missing prerequisite. Run `roll browser setup --dry-run`
|
|
604
|
+
to see what's needed, then install the missing dependency and re-run
|
|
605
|
+
`roll browser doctor --probe` to validate.
|
|
606
|
+
|
|
607
|
+
### `doctor --probe` fails with "transport" or "manifest" errors
|
|
608
|
+
|
|
609
|
+
The real MCP sidecar could not initialize. Common causes:
|
|
610
|
+
|
|
611
|
+
- `chrome-devtools-mcp` is not installed globally (`npm i -g chrome-devtools-mcp`).
|
|
612
|
+
- The version pinned in `~/.roll/browser-operations.yaml` does not match the
|
|
613
|
+
installed version. Run `roll browser update --check` to compare.
|
|
614
|
+
- Chrome is not installed or not on PATH.
|
|
615
|
+
|
|
616
|
+
### `roll browser run` says "Browser operations are disabled in project policy"
|
|
617
|
+
|
|
618
|
+
The project's `.roll/policy.yaml` does not enable the managed lane. Add the
|
|
619
|
+
`browser_operations` opt-in block (the same schema shown in
|
|
620
|
+
[Running a Managed Operation](#running-a-managed-operation-real-mcp-lane)):
|
|
621
|
+
|
|
622
|
+
```yaml
|
|
623
|
+
browser_operations:
|
|
624
|
+
enabled: true
|
|
625
|
+
managed:
|
|
626
|
+
enabled: true
|
|
627
|
+
allowed_origins: [https://example.com]
|
|
628
|
+
allowed_actions: [navigate, snapshot, console, network, screenshot]
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
Then re-run `roll browser doctor --probe` to verify the lane is ready.
|
|
632
|
+
|
|
633
|
+
### `roll browser run` without `--story` or `--url` fails
|
|
634
|
+
|
|
635
|
+
The real MCP lane **requires** `--story <US-ID>` and `--url <targetUrl>`. These
|
|
636
|
+
are recorded in the operation ledger for auditability. Omit them only with
|
|
637
|
+
`--fixture` (test-only path).
|
|
638
|
+
|
|
639
|
+
### `roll browser interactive` says "requires an attached TTY"
|
|
640
|
+
|
|
641
|
+
Interactive owner-Chrome operations require a foreground terminal. They cannot
|
|
642
|
+
run from a background scheduler, CI job, or non-interactive shell. This is by
|
|
643
|
+
design: every operation needs live owner approval.
|
|
644
|
+
|
|
645
|
+
### "Connects only to an already-open loopback Chrome debug endpoint"
|
|
646
|
+
|
|
647
|
+
Roll does not start Chrome and does not open a remote debug port. Launch Chrome
|
|
648
|
+
yourself with `--remote-debugging-port=9222` bound to `127.0.0.1`. Non-loopback
|
|
649
|
+
addresses are rejected.
|
|
650
|
+
|
|
651
|
+
### Can I use interactive mode to export cookies or keep a session open?
|
|
652
|
+
|
|
653
|
+
No. Credential export (cookies, storage, and network bodies) is always denied.
|
|
654
|
+
The lease is released immediately after the operation and expires within 15
|
|
655
|
+
minutes; there is no background scheduler or persistent session.
|
|
656
|
+
|
|
657
|
+
### Can I point interactive mode at a remote Chrome instance?
|
|
658
|
+
|
|
659
|
+
No. Only loopback endpoints are supported. There is no remote endpoint, tunnel,
|
|
660
|
+
or cloud browser integration.
|
|
661
|
+
|
|
662
|
+
---
|
|
663
|
+
|
|
664
|
+
## Live Regression Gate
|
|
665
|
+
|
|
666
|
+
The managed lane is protected by a real, hermetic end-to-end gate
|
|
667
|
+
(`pnpm test:browser-live`). It starts a local temporary HTTP target, a real
|
|
668
|
+
exact-version `chrome-devtools-mcp` process, and a managed temporary Chrome
|
|
669
|
+
profile, then drives navigation, DOM snapshot, real console/network summaries, a
|
|
670
|
+
diagnostic screenshot, and the opt-in performance/device profiles through the
|
|
671
|
+
public managed path (`roll browser run` without `--fixture`). It also proves
|
|
672
|
+
final-origin redirect denial and that timeout, Chrome crash, MCP protocol error,
|
|
673
|
+
and redaction failure each clean up the MCP process, Chrome, and the temporary
|
|
674
|
+
profile. It performs **no external network request**.
|
|
675
|
+
|
|
676
|
+
Two environments, deliberately separate:
|
|
677
|
+
|
|
678
|
+
- **Default `roll test` / `pnpm -r test`** — never runs the live gate (it needs
|
|
679
|
+
Chrome). These suites stay green everywhere. The gate's own logic (capability
|
|
680
|
+
detection, evidence scoring, the local target) is covered by hermetic unit
|
|
681
|
+
tests that always run.
|
|
682
|
+
- **Chrome-capable CI lane** (`.github/workflows/browser-live-gate.yml`) — sets
|
|
683
|
+
`ROLL_BROWSER_LIVE=1`, provisions a real Chrome, and runs the live gate for
|
|
684
|
+
real.
|
|
685
|
+
|
|
686
|
+
The gate is **fail-loud, never a silent skip**. Run it locally with:
|
|
687
|
+
|
|
688
|
+
```bash
|
|
689
|
+
ROLL_BROWSER_LIVE=1 pnpm test:browser-live
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
If Chrome or `npx` is missing, or `ROLL_BROWSER_LIVE` is unset, the gate exits
|
|
693
|
+
as an *explicitly unavailable environment gate* — it reports the missing
|
|
694
|
+
capability and states plainly that the managed lane is **not verified**. It
|
|
695
|
+
never reports the feature as verified from a skipped or fixture run: a
|
|
696
|
+
`fixture`-sourced report can exercise seams but can never earn a `verified`
|
|
697
|
+
verdict.
|
|
698
|
+
|
|
699
|
+
A `verified` result prints the real transport verification (`transport
|
|
700
|
+
initialized`, `manifest verified`), the per-scenario cleanup state, and the
|
|
701
|
+
diagnostic-only boundary — the same summary a physical-terminal screenshot
|
|
702
|
+
captures.
|
|
703
|
+
|
|
704
|
+
---
|
|
705
|
+
|
|
706
|
+
## See Also
|
|
707
|
+
|
|
708
|
+
- [Tools & policy](tools.md) — how `browser.*` tool access is governed.
|
|
709
|
+
- [Acceptance evidence](acceptance-evidence.md) — why diagnostics are not visual AC.
|
|
710
|
+
- [FAQ](faq.md) — common questions and answers.
|
|
711
|
+
- [中文版](../zh/browser-operations.md)
|