@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.
@@ -0,0 +1,632 @@
1
+ # Roll — 浏览器操作(受管通道 + 交互通道)
2
+
3
+ Roll 可以驱动一个**受管、隔离的 Chrome(经真实的 `chrome-devtools-mcp` 侧车)**
4
+ 来采集浏览器诊断——导航检查、DOM 快照、控制台与网络捕获、诊断截图。每次受管操作
5
+ 会启动一个固定版本的 `chrome-devtools-mcp` stdio 会话(临时 Chrome 档案),会话
6
+ 完成 MCP initialize + tools/list、校验最小工具清单后,才执行所请求的操作。档案在
7
+ 操作后删除。
8
+
9
+ 另一条**交互式 owner-Chrome 通道**支持对已打开的本地 Chrome 调试端点执行单次、
10
+ 低风险操作,需前台 owner 批准并受严格租约控制。
11
+
12
+ 两条通道都需显式开启、依赖受控、范围刻意收窄。
13
+
14
+ 它们**不是**两件事:
15
+
16
+ - 它们**不是安装器**。Roll 绝不往你的产品仓 `package.json` 加依赖,也绝不擅自
17
+ 开启你自己(owner)Chrome 的远程调试。`setup` 只在你确认后写入一份机器级配置。
18
+ - 它们的产物**不是视觉验收证据**。受管诊断截图或交互式 owner 运行结果只能证明
19
+ 页面动作成功,不能满足故事的视觉验收(visual AC)。只有 **Roll Capture**
20
+ (对你真实终端/应用的物理截图)才满足视觉验收——见[验收证据](acceptance-evidence.md)。
21
+
22
+ ---
23
+
24
+ ## 隐私与安全边界
25
+
26
+ 以下不变量对每次操作(受管或交互)都成立:
27
+
28
+ - **仅临时档案。** 受管 Chrome 在全新临时档案下运行,操作后删除。owner 浏览器
29
+ 状态(cookie、登录态、历史、localStorage)绝不进入、不读取、不导出。
30
+ - **禁止凭证导出。** cookie、storage 与 network bodies 没有任何 CLI 或适配器
31
+ 暴露面。两条通道都无法导出 owner 凭证。
32
+ - **遥测已禁用。** `chrome-devtools-mcp` 以 `--no-usage-statistics` 启动。
33
+ 不向 Chrome、CrUX、Lighthouse 或任何外部遥测服务发送数据。
34
+ - **有界脱敏诊断。** 诊断产物(控制台摘要、网络元数据、性能计数器)限定在固定
35
+ 白名单数值指标内,URL、资源名、trace 均脱敏。见[可选诊断 profile](#可选诊断-profile)。
36
+ - **无通用 MCP 绕过。** 只注册了固定版本的 `chrome-devtools-mcp` 传输用于浏览器
37
+ 操作。指向 DevTools 的通用 `mcp.call` 会被拒绝(fail-closed)。
38
+ - **DevTools 产物绝不满足视觉 AC。** 诊断截图与 DOM 快照被归类为仅诊断产物,
39
+ 无法获得视觉验收结论。见[证据边界](#证据边界)。
40
+ - **不自动启动 Chrome。** Roll 绝不启动或关闭你的 owner Chrome。交互通道仅连接
41
+ 你自行以 loopback 地址启动的 Chrome 调试端点。
42
+ - **仅机器级配置。** `setup` 写入 `~/.roll/browser-operations.yaml`——绝不写产品
43
+ 仓文件——且仅在 `--confirm` 时写入。
44
+
45
+ ---
46
+
47
+ ## 受管通道
48
+
49
+ 受管通道是**浏览器操作的主路径**。它用全新临时档案启动 Chrome、拉起固定版本的
50
+ `chrome-devtools-mcp` 侧车、对白名单目标执行一次操作,结束后删除档案。
51
+
52
+ ### 前置条件与体检
53
+
54
+ 受管通道需要固定版本的 `chrome-devtools-mcp` 传输和一个 Chrome 可执行文件。
55
+ Roll 不会替你安装——它只报告缺什么、怎么修。先跑静态体检:
56
+
57
+ ```bash
58
+ roll browser doctor
59
+ ```
60
+
61
+ ```
62
+ Browser operations doctor
63
+ 浏览器操作体检
64
+
65
+ ~ managed: degraded — chrome-devtools-mcp not ready; existing Playwright and Roll Capture paths remain usable
66
+ → roll browser setup --dry-run
67
+ → install the missing dependency, then re-run roll browser doctor
68
+ ✓ interactive: ready owner Chrome reachable on 127.0.0.1:9222
69
+ ~ capture: degraded — Roll Capture readiness probe skipped (headless / CI / ROLL_NO_SCREENCAP).
70
+ ```
71
+
72
+ 每条通道只报告三种诚实状态之一:
73
+
74
+ | 状态 | 含义 |
75
+ |------|------|
76
+ | `ready` | 该通道的前置条件已满足。 |
77
+ | `degraded` | 通道不可用或仅部分可用。已有的 Playwright 与 Roll Capture 路径照常工作——缺前置绝不会被报成通过。 |
78
+ | `blocked` | 存在硬性前置阻断通道运行;会打印原因与修复命令。 |
79
+
80
+ 静态体检只检查机器环境与配置,**不会**启动 `chrome-devtools-mcp`——静态体检的
81
+ `ready` 仅表示二进制与配置存在,不能证明 MCP 侧车能正确初始化。
82
+
83
+ ### 实时 MCP 探测(`doctor --probe`)
84
+
85
+ `doctor --probe` 会运行**一次真实的临时 `chrome-devtools-mcp` 会话**,端到端验证
86
+ 整个传输生命周期。只有通过探测,受管通道才会在 doctor 输出中显示为 `ready`。
87
+
88
+ ```bash
89
+ roll browser doctor --probe
90
+ ```
91
+
92
+ ```
93
+ Browser operations doctor --probe
94
+ 浏览器操作体检 --probe
95
+
96
+ ⏳ Running live MCP lane probe — this will:
97
+ 1. Spawn the pinned chrome-devtools-mcp session (temporary process)
98
+ 2. Run MCP initialize + tools/list + manifest validation
99
+ 3. Close the session and clean up the temporary Chrome profile
100
+ The probe may take a few seconds. No owner state enters the temporary profile.
101
+
102
+ ⏳ 正在运行实时 MCP 通道探测——将会:
103
+ 1. 启动固定版本的 chrome-devtools-mcp 会话(临时进程)
104
+ 2. 运行 MCP initialize + tools/list + 清单验证
105
+ 3. 关闭会话并清理临时 Chrome 档案
106
+ 探测可能需要几秒。绝不会进入 owner 状态。
107
+
108
+ ✅ Live probe passed — managed lane is ready.
109
+ ✅ 实时探测通过——受管通道就绪。
110
+
111
+ ✓ managed: ready chrome-devtools-mcp 1.5.0 (8 tools) — live probe passed
112
+ ```
113
+
114
+ 探测生命周期:
115
+
116
+ 1. **启动** —— 临时 `chrome-devtools-mcp` stdio 进程以固定版本 +
117
+ `--no-usage-statistics` 启动。
118
+ 2. **初始化** —— MCP `initialize` 握手完成。
119
+ 3. **验证** —— 运行 `tools/list`,校验响应是否符合最小工具清单
120
+ (navigate、snapshot、console、network、screenshot)。
121
+ 4. **关闭与清理** —— MCP 进程与临时 Chrome 档案被移除。
122
+
123
+ 探测失败时如实分类报告:
124
+
125
+ ```
126
+ ❌ Live probe failed — see categorized failures below.
127
+ ❌ 实时探测失败——见下方分类失败信息。
128
+ transport: chrome-devtools-mcp not installed or not on PATH
129
+ manifest: tool manifest missing required entries (expected: navigate, snapshot, console, network, screenshot; got: [])
130
+ chrome: chrome binary not found at expected path
131
+ ```
132
+
133
+ 修复后重跑 `doctor --probe`。不带 `--probe` 的静态体检仍可用于快速环境检查;
134
+ 当二进制与配置存在但尚未通过探测时,报告通道为 `configured`。
135
+
136
+ ### 安装(先 dry-run)
137
+
138
+ `setup --dry-run` 展示 Roll 将要写入的机器级配置全文,并跑依赖预检。它**什么都不写**:
139
+
140
+ ```bash
141
+ roll browser setup --dry-run
142
+ ```
143
+
144
+ ```
145
+ Browser operations setup
146
+ 浏览器操作安装
147
+
148
+ target (machine-level, never committed): ~/.roll/browser-operations.yaml
149
+
150
+ proposed ~/.roll/browser-operations.yaml:
151
+ devtools:
152
+ command: npx
153
+ args: ["-y", "chrome-devtools-mcp@1.5.0", "--no-usage-statistics"]
154
+ package: chrome-devtools-mcp
155
+ package_version: 1.5.0
156
+ chrome_channel: stable
157
+ remote_debugging: { host: "127.0.0.1", port: 9222 }
158
+ ...
159
+ Roll never installs into a product package.json and never enables owner Chrome remote debugging.
160
+ Roll 绝不改动产品仓 package.json,也绝不自动开启 owner Chrome 的远程调试。
161
+
162
+ dry-run: no configuration was written.
163
+ ```
164
+
165
+ 你审阅之后才写入配置,且必须显式确认:
166
+
167
+ ```bash
168
+ roll browser setup --confirm
169
+ ```
170
+
171
+ 没有 `--confirm`(也没有 `--dry-run`)时,`setup` 会拒绝并且什么都不写。
172
+
173
+ ### 运行受管操作(真实 MCP 通道)
174
+
175
+ `roll browser run` 带 `--story` 和 `--url` 会经**真实、策略控制的 MCP 通道**
176
+ 执行。这是生产路径。项目须先在 `.roll/policy.yaml` 显式开闸(默认全部关闭):
177
+
178
+ ```yaml
179
+ browser_operations:
180
+ enabled: true
181
+ managed:
182
+ enabled: true
183
+ allowed_origins: [https://example.com]
184
+ allowed_actions: [navigate, snapshot, console, network, screenshot]
185
+ max_runs_per_cycle: 20
186
+ timeout_ms: 30000
187
+ ```
188
+
189
+ ```bash
190
+ roll browser run \
191
+ --story US-BROW-021 \
192
+ --url https://example.com \
193
+ --action screenshot
194
+ ```
195
+
196
+ 真实运行逐字输出(2026-07-16 实录):
197
+
198
+ ```
199
+ Managed browser operation — real MCP
200
+ 受管浏览器操作 — 真实 MCP
201
+
202
+ mcp package / MCP 包: 1.5.0
203
+ transport initialized / 传输初始化: yes
204
+ manifest verified / 清单验证: yes
205
+ lane / 通道: managed
206
+ action / 动作: screenshot
207
+ target / 目标: https://example.com
208
+ run state / 运行状态: passed
209
+ result / 结果: pass (action: ok)
210
+ temp profile / 临时档案: removed (owner state never entered / 绝不进入 owner 状态)
211
+ diagnostics / 诊断产物: 1 (diagnostic-only, NOT visual acceptance / 仅诊断,非视觉验收)
212
+ summary / 摘要: diagnostic screenshot recorded
213
+
214
+ Diagnostic success is not visual acceptance evidence.
215
+ 诊断通过不等于视觉验收证据。
216
+ ```
217
+
218
+ 支持的动作:`navigate`(默认)、`snapshot`、`console`、`network`、`screenshot`。
219
+
220
+ MCP 会话生命周期:
221
+
222
+ 1. **策略检查** —— 项目 `.roll/policy.yaml` 必须启用受管通道
223
+ (`browser_operations.enabled: true` 加 `managed.enabled: true` 与 origin
224
+ 白名单)。无显式策略时默认全部关闭,运行在启动任何进程前即被**拒绝**。
225
+ 2. **会话启动** —— 固定版本的 `chrome-devtools-mcp` 以全新临时 Chrome 档案
226
+ 启动。
227
+ 3. **MCP 握手** —— `initialize` → `tools/list` → 清单验证。任何一步失败即中止
228
+ 运行(`devtools-error`)。
229
+ 4. **动作执行** —— 所请求的动作对白名单目标执行。
230
+ 5. **清理** —— MCP 进程组终止,包含 `npx` 包装器和它的 DevTools server 子进程;
231
+ 临时档案删除(超时或崩溃时也不例外)。无法确认清理时,运行会大声失败并报告
232
+ `MCP process cleanup failed`,绝不会声称会话已清理。
233
+
234
+ 白名单之外的目标——包括从请求 origin 跳走的重定向——会被**拒绝**,不会跟随。
235
+ 真实通道**必须**提供 `--story` 标识符;它会记入操作账本(ledger)以备审计。
236
+
237
+ #### 阻塞/不可用实录
238
+
239
+ 受管通道不可用或被策略拒绝时,运行会大声失败。无 `.roll/policy.yaml` 时的
240
+ 逐字输出(2026-07-16 实录):
241
+
242
+ ```
243
+ Managed browser operation — real MCP
244
+ 受管浏览器操作 — 真实 MCP
245
+
246
+ denied / 已拒绝: Browser operations are disabled in project policy
247
+
248
+ Diagnostic success is not visual acceptance evidence.
249
+ 诊断通过不等于视觉验收证据。
250
+ ```
251
+
252
+ 修复:把上文的 `browser_operations:` 开闸块加进 `.roll/policy.yaml`,跑
253
+ `roll browser doctor --probe` 验证后重试。
254
+
255
+ 失败模式与修复:
256
+
257
+ | 失败 | Doctor 信号 | 修复 |
258
+ |------|------------|------|
259
+ | `chrome-devtools-mcp` 未安装 | `managed: degraded — transport not found` | `npm i -g chrome-devtools-mcp@<version>` 或 `roll browser setup --confirm` |
260
+ | Chrome 二进制未找到 | `managed: degraded — chrome not found` | 安装 Chrome(stable 渠道) |
261
+ | 策略禁用受管通道 | run → `denied` | 在 `.roll/policy.yaml` 加 `browser_operations:` 开闸块(`enabled: true` + `managed.enabled: true` + origin 白名单) |
262
+ | MCP 握手失败 | `doctor --probe` → `manifest` 失败 | 检查 `chrome-devtools-mcp` 版本;重跑 `roll browser update --check` |
263
+ | MCP 进程运行中崩溃 | run → `devtools-error` | 重跑;持续崩溃 → `roll browser doctor --probe` |
264
+ | 运行超时 | run → `timeout` | 目标可能较慢;档案无论如何都会清理 |
265
+
266
+ ### Fixture 路径(仅测试)
267
+
268
+ `--fixture` 标志走一条**假目标路径**,用于在不启动真实 MCP 进程的情况下测试接缝、
269
+ 查看通道报告格式。它**不是**受管通道的回落——fixture 使用硬编码测试数据,永远
270
+ 无法证明真实 MCP 传输正常工作。
271
+
272
+ ```bash
273
+ roll browser run --fixture --action screenshot
274
+ ```
275
+
276
+ ```
277
+ Managed browser operation — fixture (fake target)
278
+ 受管浏览器操作 — fixture(假目标)
279
+
280
+ lane / 通道: managed (fixture — TEST ONLY / 仅测试)
281
+ action / 动作: screenshot
282
+ target / 目标: https://fake.target.test
283
+ run state / 运行状态: passed
284
+ result / 结果: pass (action: ok)
285
+ temp profile / 临时档案: removed (owner state never entered / 绝不进入 owner 状态)
286
+ diagnostics / 诊断产物: 1 (diagnostic-only, NOT visual acceptance / 仅诊断,非视觉验收)
287
+ summary / 摘要: diagnostic screenshot captured at https://fake.target.test
288
+
289
+ Diagnostic success is not visual acceptance evidence.
290
+ 诊断通过不等于视觉验收证据。
291
+ ```
292
+
293
+ Fixture 支持注入标志以探究失败模式:`--fail timeout|crash|devtools-error`、
294
+ `--redirect <url>`、`--perf-fail`。这些都是仅测试用途——对真实 MCP 通道无效。
295
+
296
+ **Fixture 运行永远无法获得 `verified` 结论。** 只有真实 MCP 通道(不带
297
+ `--fixture`)才真正驱动传输。实况回归闸(见下文)在 CI 层面强制执行这一点:
298
+ `fixture` 来源的报告可以测试接缝,但永远无法产生 `verified` 结果。
299
+
300
+ ### 传输更新
301
+
302
+ DevTools 传输版本是**固定的**。`update --check` 比较固定版本与候选版本,不下载、
303
+ 不改任何东西:
304
+
305
+ ```bash
306
+ roll browser update --check
307
+ ```
308
+
309
+ 应用更新与 setup 同样受控——需显式确认,先跑冒烟检查,再跑**真实 MCP 探测**,
310
+ 任何失败都保留原版本不动:
311
+
312
+ ```bash
313
+ roll browser update --apply --confirm
314
+ ```
315
+
316
+ 更新生命周期:
317
+
318
+ 1. **检查** —— 比较固定版本与候选版本。
319
+ 2. **冒烟检查** —— 验证候选版本二进制可启动。
320
+ 3. **MCP 探测** —— 以候选版本运行 `doctor --probe`。若探测失败,更新**中止**,
321
+ 保留原版本不动。
322
+ 4. **应用** —— 仅当冒烟 + 探测均通过,才重写配置,新版本成为固定传输。
323
+
324
+ ```
325
+ Update applied: 1.5.0 → 1.6.0
326
+ 更新已应用:1.5.0 → 1.6.0
327
+ wrote: ~/.roll/browser-operations.yaml
328
+
329
+ smoke check: passed
330
+ 冒烟检查:通过
331
+
332
+ MCP probe: passed (1.6.0)
333
+ MCP 探测:通过 (1.6.0)
334
+
335
+ ✓ managed: ready chrome-devtools-mcp 1.6.0 (8 tools) — live probe passed
336
+ ```
337
+
338
+ 更新失败时保留原版本:
339
+
340
+ ```
341
+ Update aborted: live MCP probe failed for 1.6.0
342
+ 更新中止:1.6.0 实时 MCP 探测失败
343
+
344
+ Prior version 1.5.0 is kept intact.
345
+ 已保留原版本 1.5.0。
346
+
347
+ transport: process exited before initialize completed
348
+ ```
349
+
350
+ ---
351
+
352
+ ## 可选诊断 profile
353
+
354
+ 受管通道提供两个**可选、需显式选启**的诊断 profile:一个性能 profile 和一小组
355
+ 设备仿真 profile。两者都只在受管隔离通道(真实 MCP 路径)内运行,产物都是**仅诊断**
356
+ 材料。
357
+
358
+ 采用前先看清边界:
359
+
360
+ - **需显式选启**。不在命令行显式选择就不会采集任何 profile;不带 profile 时基础
361
+ 受管操作行为不变。
362
+ - 产物**仅诊断**,既不是视觉验收证据,也不是多浏览器测试矩阵。profile 摘要只能
363
+ 证明本地诊断跑过,不满足故事的视觉 AC。视觉验收请用
364
+ [Roll Capture](acceptance-evidence.md)。
365
+ - **数据最小化**,不向机器外发送任何内容。
366
+
367
+ ### 性能 profile(需选启)
368
+
369
+ `--perf-profile web-vitals-lite` 采集一组有界、脱敏的本地 DevTools 性能计数器
370
+ (documents、frames、layout/style 的计数与耗时、script/task 耗时、JS 堆大小——
371
+ 一份固定的数值指标白名单)。不选就不启用,而"选择"这一动作正是打开本通道
372
+ 性能诊断策略的开关。
373
+
374
+ ```bash
375
+ roll browser run --story US-BROW-021 --url https://example.test --perf-profile web-vitals-lite
376
+ ```
377
+
378
+ ```
379
+ perf profile / 性能诊断: web-vitals-lite (opt-in, diagnostic-only / 需选启,仅诊断)
380
+ metrics / 指标 (12, bounded & redacted / 有界脱敏):
381
+ - LayoutCount: 3
382
+ - ScriptDuration: 0.021
383
+ ...
384
+ ```
385
+
386
+ 数据最小化与范围保证:
387
+
388
+ - **只有白名单内的数值指标名会被保留。** 绝不保留任何 URL、资源名或 trace,因此
389
+ 该 profile 无法变成分析或证据通道。
390
+ - **无外部遥测。** 不向 CrUX、Lighthouse 或任何服务上传。要加外部上传,须另立
391
+ 一份单独设计、经同意授权的策略契约。
392
+ - **优雅降级。** 采集失败时运行报告 `degraded — no signal collected`,底层动作
393
+ 结论不变。
394
+
395
+ 未知 profile 名会 fail-fast 拒绝,而非静默忽略。
396
+
397
+ ### 设备仿真 profile(需选启)
398
+
399
+ `--profile <name>` 用一个命名的 Chrome 设备/视口 profile 运行受管操作。白名单是
400
+ 有限的——调用方不能提交任意 DevTools 仿真参数:
401
+
402
+ | Profile | 视口 | 缩放 | 移动端 |
403
+ |---------|------|------|--------|
404
+ | `Pixel 7` | 412 × 915 | 2.625 | 是 |
405
+ | `iPhone 14` | 390 × 844 | 3 | 是 |
406
+ | `iPad Pro` | 1024 × 1366 | 2 | 否 |
407
+
408
+ ```bash
409
+ roll browser run --story US-BROW-021 --url https://example.test --action screenshot --profile "iPhone 14"
410
+ # device profile / 设备仿真: iPhone 14
411
+ ```
412
+
413
+ 范围保证:
414
+
415
+ - **仅限有限白名单。** 未知 profile 名 fail-fast 拒绝;无法借它传入原始仿真参数。
416
+ - **这是 Chrome DevTools 仿真,不是多浏览器矩阵。** 对比声明的视口行为在范围内;
417
+ 真正的跨浏览器(Playwright 式)farm 明确不在范围,需另立单独设计的提案。
418
+ - **安全不变量不变。** 设备 profile 不改变源策略、临时 profile 清理、Capture
419
+ 结论或交互式 owner-Chrome 行为。
420
+
421
+ ---
422
+
423
+ ## 交互通道
424
+
425
+ 交互通道让你对自己 Chrome 中**已经打开的页面**执行单次低风险操作。它用于
426
+ 手动举证(manual-attest)工作流,而非后台自动化。
427
+
428
+ ### 先决条件
429
+
430
+ Roll **不会替你启动 Chrome**,也**不会开启远程调试**。你必须先自行启动带有
431
+ 本地调试端点的 Chrome,再运行 `roll browser interactive`:
432
+
433
+ ```bash
434
+ /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
435
+ --remote-debugging-port=9222 \
436
+ --user-data-dir=/tmp/owner-chrome-profile
437
+ ```
438
+
439
+ 仅允许 `127.0.0.1:9222`(或其他 loopback 地址)。非 loopback 端点会被拒绝。
440
+
441
+ ### 运行一次交互操作
442
+
443
+ ```bash
444
+ roll browser interactive \
445
+ --story US-EXAMPLE-001 \
446
+ --origin https://example.test \
447
+ --action navigate --url https://example.test/login
448
+ ```
449
+
450
+ 支持动作:`navigate`、`click`、`fill`、`press_key`。
451
+
452
+ 该命令要求**已连接的 TTY**。它会打印待执行内容(story、origin、动作、最长
453
+ 15 分钟的租约),然后请求**一次 owner 批准**:
454
+
455
+ ```
456
+ Owner Chrome approval required (one operation only)
457
+ story: US-EXAMPLE-001
458
+ origin: https://example.test
459
+ action: navigate to https://example.test
460
+ expiry: 2026-07-15T08:34:00.000Z (15 minutes maximum)
461
+ credential export: denied (cookies, storage, and network bodies are unavailable)
462
+ Approve this owner-run operation? [y/N]
463
+ ```
464
+
465
+ 如果你拒绝,不会尝试任何连接。如果批准,Roll 会连接本地调试端点、执行单次
466
+ 操作、打印结果,并立即释放租约:
467
+
468
+ ```
469
+ manual owner-run result: ok (tab: 1234)
470
+ This interactive result does not make CI pass and is not background automation.
471
+ ```
472
+
473
+ ### 租约到期与取消
474
+
475
+ 每次交互操作最多持有 **15 分钟** 租约。租约绑定到持有进程与 loopback 端点;
476
+ 操作结束后立即释放。若进程死亡或租约到期,Roll 会自动回收。你无法批准持久
477
+ 后台租约——每次操作都需要独立的前台批准。
478
+
479
+ ### 交互通道永远不会做的事
480
+
481
+ - 在没有 TTY 和显式 owner 批准的情况下运行。
482
+ - 连接非 loopback 或远程调试端点。
483
+ - 导出 cookie、storage、network bodies 或任何其他凭证。
484
+ - 自动启动 Chrome 或留下后台调度器。
485
+ - 独自让 CI 通过——它只是一个 **owner-run manual-attest** 工具。
486
+
487
+ ---
488
+
489
+ ## 证据边界
490
+
491
+ 受管浏览器诊断与交互式 owner 运行结果**仅为诊断 / 仅为 manual-attest**。每次
492
+ run 报告都重复这句:*诊断通过不等于视觉验收证据*。诊断截图或交互结果会被归类
493
+ 为诊断产物,而非视觉验收产物,因此绝不可能伪造故事的视觉验收。故事需要视觉
494
+ 验收时,请用 **Roll Capture**——对真实终端/应用的物理截图——只有它满足该要求。
495
+ 见[验收证据](acceptance-evidence.md)。
496
+
497
+ 当 `roll attest` 收到物理捕获响应时,会把已验证的 CaptureBridge link 写入
498
+ `.roll/browser-operations/events.ndjson`。doctor、truth 与 dossier 都读取这条持久化
499
+ 事实:通过验证的 `roll.capture.v1` 物理捕获可以满足视觉 AC,而 Playwright 与 DevTools
500
+ 诊断仍不具资格。没有已落盘的 link 时,capture truth 诚实保持 unknown,dossier 也不会
501
+ 凭空生成捕获事件。
502
+
503
+ ---
504
+
505
+ ## Dossier 时间线(可选)
506
+
507
+ 当故事已有声明的浏览器操作事实(ledger 的 start/finish、lease 的
508
+ grant/expiry/release,或物理截图结果)时,交付 dossier 的 Execution 区会显示紧凑的
509
+ **浏览器操作时间线**。排序只来自已声明时间戳——缺失类别以诚实的 absent + 原因
510
+ 呈现,绝不虚构时间点或结论。脱敏诊断产物与物理截图只有在既有 dossier 授权规则
511
+ (本地 href 映射)允许时才会变为链接;否则只显示标签。没有浏览器事实的故事保持
512
+ 原先 dossier 形态不变。
513
+
514
+ **unknown 与 degraded 状态如实呈现。** 某类别没有已声明时间戳时,时间线把它渲染
515
+ 成明确的 absent + 原因(例如 *lease: unknown — no grant recorded*),而不虚构
516
+ 时间点或结论。降级的 profile(见上文[性能 profile](#可选诊断-profile))显示为
517
+ degraded 诊断,而非 pass。若某行时间线意外为空或降级,请按下文[排障](#排障)
518
+ 排查——受管通道 degraded 是缺少前置依赖,不是交付坏了。
519
+
520
+ ---
521
+
522
+ ## 安全恢复
523
+
524
+ - 若 `doctor` 报告 `managed: degraded`,已有的 Playwright 与 Roll Capture 路径
525
+ 照常可用——你原本依赖的东西没有被破坏。装上缺失依赖后重跑
526
+ `roll browser doctor --probe`。
527
+ - 临时 profile 每次运行后都会删除;owner Chrome 状态绝不进入。运行被中断后重跑
528
+ 是安全的——每次都从全新 profile 开始。
529
+ - 不会向你的产品仓写任何东西。Roll 唯一可能写入的是机器级
530
+ `~/.roll/browser-operations.yaml`,且仅在 `--confirm` 时。
531
+
532
+ ---
533
+
534
+ ## 排障
535
+
536
+ ### `roll browser doctor` 报告 `managed: degraded`
537
+
538
+ 静态体检发现缺少前置依赖。跑 `roll browser setup --dry-run` 查看需要什么,
539
+ 装上缺失依赖后重跑 `roll browser doctor --probe` 验证。
540
+
541
+ ### `doctor --probe` 报 "transport" 或 "manifest" 错误
542
+
543
+ 真实 MCP 侧车无法初始化。常见原因:
544
+
545
+ - `chrome-devtools-mcp` 未全局安装(`npm i -g chrome-devtools-mcp`)。
546
+ - `~/.roll/browser-operations.yaml` 中固定的版本与已安装版本不匹配。跑
547
+ `roll browser update --check` 对比。
548
+ - Chrome 未安装或不在 PATH 中。
549
+
550
+ ### `roll browser run` 提示 "Browser operations are disabled in project policy"
551
+
552
+ 项目 `.roll/policy.yaml` 未启用受管通道。添加 `browser_operations` 开闸块
553
+ (与上文「运行受管操作」一节相同的 schema):
554
+
555
+ ```yaml
556
+ browser_operations:
557
+ enabled: true
558
+ managed:
559
+ enabled: true
560
+ allowed_origins: [https://example.com]
561
+ allowed_actions: [navigate, snapshot, console, network, screenshot]
562
+ ```
563
+
564
+ 然后重跑 `roll browser doctor --probe` 验证通道就绪。
565
+
566
+ ### `roll browser run` 不带 `--story` 或 `--url` 失败
567
+
568
+ 真实 MCP 通道**必须**提供 `--story <US-ID>` 和 `--url <targetUrl>`。这些参数
569
+ 会记入操作账本以备审计。仅在 `--fixture`(仅测试路径)下可省略。
570
+
571
+ ### `roll browser interactive` 提示 "requires an attached TTY"
572
+
573
+ 交互式 owner-Chrome 操作需要前台终端。它们不能从后台调度器、CI 作业或非交互式
574
+ shell 中运行。这是设计如此:每次操作都需要实时的 owner 批准。
575
+
576
+ ### "Connects only to an already-open loopback Chrome debug endpoint"
577
+
578
+ Roll 不会启动 Chrome,也不会打开远程调试端口。你需要自行用
579
+ `--remote-debugging-port=9222` 绑定到 `127.0.0.1` 来启动 Chrome。非 loopback
580
+ 地址会被拒绝。
581
+
582
+ ### 交互模式能导出 cookie 或保持会话吗?
583
+
584
+ 不能。凭证导出(cookie、storage、network bodies)始终被拒绝。租约在操作结束后
585
+ 立即释放,并在 15 分钟内过期;没有后台调度器,也没有持久会话。
586
+
587
+ ### 我能把交互模式指向远程 Chrome 实例吗?
588
+
589
+ 不能。仅支持 loopback 端点。没有远程端点、隧道或云浏览器集成。
590
+
591
+ ---
592
+
593
+ ## 实况回归闸
594
+
595
+ 受管通道由一个真实、封闭的端到端回归闸守护(`pnpm test:browser-live`)。它会启动
596
+ 一个本地临时 HTTP 目标、一个真实的精确版本 `chrome-devtools-mcp` 进程,以及一个
597
+ 受管的临时 Chrome 档案,然后通过公开的受管路径(`roll browser run`,不带
598
+ `--fixture`)执行导航、DOM 快照、真实的 console/network 摘要、诊断截图,以及需选启
599
+ 的性能/设备档案。它同时验证最终 origin 的跳转拒绝,并验证超时、Chrome 崩溃、MCP
600
+ 协议错误、redaction 失败各自都会清理 MCP 进程、Chrome 与临时档案。它**不发起任何
601
+ 外部网络请求**。
602
+
603
+ 两个环境,刻意分离:
604
+
605
+ - **默认 `roll test` / `pnpm -r test`** —— 永不运行实况闸(它需要 Chrome)。这些
606
+ 套件在任何机器上都保持绿。闸本身的逻辑(能力探测、证据判分、本地目标)由始终运行
607
+ 的封闭单元测试覆盖。
608
+ - **Chrome-capable CI 通道**(`.github/workflows/browser-live-gate.yml`)——
609
+ 设置 `ROLL_BROWSER_LIVE=1`,装配真实 Chrome,真跑实况闸。
610
+
611
+ 该闸**失败即大声报错,绝不静默 skip**。本地运行:
612
+
613
+ ```bash
614
+ ROLL_BROWSER_LIVE=1 pnpm test:browser-live
615
+ ```
616
+
617
+ 若缺少 Chrome 或 `npx`,或未设置 `ROLL_BROWSER_LIVE`,闸会作为*显式的不可用环境闸*
618
+ 退出——报告缺失的能力,并明确声明受管通道**未验证**。它绝不会把 skip 或 fixture
619
+ 运行报告为已验证:`fixture` 来源的报告可以测试接缝,但永远无法获得 `verified` 结论。
620
+
621
+ `verified` 结果会打印真实的传输验证(`transport initialized`、`manifest
622
+ verified`)、每个场景的清理状态,以及 diagnostic-only 边界——正是物理终端截图所
623
+ 捕获的同一份摘要。
624
+
625
+ ---
626
+
627
+ ## 相关
628
+
629
+ - [工具与策略](tools.md) —— `browser.*` 工具访问如何被治理。
630
+ - [验收证据](acceptance-evidence.md) —— 为什么诊断不是视觉验收。
631
+ - [FAQ](faq.md) —— 常见问题与解答。
632
+ - [English](../en/browser-operations.md)