PostHog 前端 QA 实战:浏览器 MCP 模式与证据化验证指南
【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog
本篇技术指南以 PostHog 仓库内qa-frontend技能集的 浏览器 MCP 模式参考文档 为主体,系统讲解如何用浏览器 MCP(Browser MCP)工具链对 PostHog 前端执行可复现、证据驱动的 QA 循环。你将掌握:浏览器 MCP 的接入与作用域选型、七步浏览器流程骨架、锁定配置文件与会话清理的排障纪律、以截图与控制台/网络信号为准的"证据优先"验证法、暗/亮主题切换、测试数据播种、Feature Flag 覆盖,以及从标注截图、WebP 演示胶卷到录制视频的完整证据产出流水线。文章结合仓库中 qa-frontend 技能 及其脚本源码,给出可直接照搬的命令、代码片段与可验证的文件依据。
一、浏览器 MCP:把浏览器当作 QA 的"眼睛"
qa-frontend技能集把浏览器 MCP/工具化能力定义为前端 QA 的唯一浏览器透镜,核心原则是:优先做用户可见的断言(user-visible assertions),而不是实现层面的断言。也就是说,验证一个改动是否生效,应该看页面上用户能感知到的文字、Toast、表格行、模态框状态、URL 变化,而不是去检查内部 state 或 DOM 结构细节。
在 browser-mcp-patterns.md 中,Playwright MCP 被明确定为仓库内的"已知可用"参考实现(known-good concrete example);Chrome DevTools MCP 或其他浏览器 MCP 同样适用,前提是它暴露了同一组基础原语:
- navigate:导航到目标 URL
- interact:与页面交互
- evaluate:在页面上下文中执行 JavaScript
- screenshot:捕获截图
- console / network 信号检查:读取控制台与网络信号
这一要求的源码级佐证在 SKILL.md 的allowed-tools字段中:技能明确允许mcp__playwright__*、mcp__chrome-devtools__*、mcp__phrocs__*三个命名空间的 MCP 工具,其中mcp__phrocs__*用于本地开发进程状态检查(下文"控制台与网络信号分级"会用到)。
MCP 可用性检查与会话前置
技能要求在动手前先确认会话里是否真的有浏览器 MCP 工具:
- 如果当前会话没有任何浏览器 MCP 工具,先停下来询问用户,而不是擅自配置。标准话术是:"我没有在会话中看到浏览器 MCP 工具。你希望我为这个 Agent 环境配置一个,还是你自己配置?如果由我配置,范围是仅限本仓库/工作区、用户级,还是你的客户端支持的其他范围?"
- 作用域选型原则:优先选择"最窄的、不提交进仓库的"作用域(如客户端本地 scope 或用户级 scope)。绝不静默修改已入库的仓库级 MCP 配置(如
.mcp.json),也不要用项目/仓库级提交作用域、更不要为了跑一次 QA 就把 MCP 配置提交进版本库。 - 配置完成后,主动告知用户:重新运行
qa-frontend之前,可能需要重连或重启 Agent 会话。
各客户端的具体示例在文档中被明确标注为"参考性指导,而非通用指令":
| 客户端 | 本地作用域示例 | 说明 |
|---|---|---|
| Claude Code | claude mcp add --scope local playwright -- npx -y @playwright/mcp@0.0.75 | 本地 scope,不提交 |
| Chrome DevTools MCP | 服务通常命名为chrome-devtools,在保留服务名的客户端中映射为mcp__chrome-devtools__*工具命名空间 | 沿用客户端或仓库已有的浏览器 MCP 配置 |
| Cursor 及其他客户端 | 使用该客户端的本地或用户级 MCP 设置 | 不用仓库提交式配置 |
| Codex | 优先使用已暴露的浏览器工具;否则询问用户如何在 Codex 环境中配置浏览器自动化 | — |
二、浏览器流程骨架:七步标准 QA 循环
文档给出了一个可复用的浏览器执行骨架,以下工具名以 Playwright MCP 为例;使用 Chrome DevTools MCP 或其他实现时,换成该服务等价的 navigate、snapshot/DOM、evaluate、screenshot、console、network 工具即可:
- 导航:跳转到目标 URL,例如
mcp__playwright__browser_navigate。 - 读取响应:导航动作的返回通常自带一次自动快照(automatic snapshot),先读完它再决定下一步。
- 按需深查 DOM:当页面状态不清晰时,调用 snapshot/DOM 检查工具,例如
mcp__playwright__browser_snapshot。 - 交互:优先按 role、文本或无障碍快照引用(accessible snapshot reference)定位控件,优先可见控件而非 CSS 选择器——这呼应了"用户可见断言优先"的核心原则。
- 逐步断言:每次有意义的动作之后,立即对 UI 状态做断言:文本变化、Toast、表格行、模态框状态、URL 变化等任何可见结果。
- 截图留证:截图统一落入
.qa-frontend/runs/<run-id>/目录(run 目录的命名规则见 SKILL.md 的 Run identity 小节:本地模式为local-<时间戳>,PR 模式为pr<编号>-<时间戳>)。 - 收集信号:读取页面 error 级控制台消息与网络失败记录。
这套骨架与 SKILL.md 中定义的 Frontend QA Loop 一一对应:navigate → snapshot → exercise the changed behavior → capture screenshot evidence → collect console errors → inspect relevant network failures。
锁定浏览器配置文件:基础设施阻塞,不是 QA 结果
如果浏览器 MCP/工具报告"浏览器配置文件已被占用"(browser profile already in use),应将其视为基础设施阻塞而非 QA 结论。处理流程:
- 优先切换到能启动全新隔离配置文件的 MCP/浏览器选项。
- 若是一个陈旧的本地浏览器进程占用了配置文件,在杀死进程或清除配置文件锁之前先询问用户。
- 恢复后,重新打开目标路由,从头重做受影响的动作。
- 若锁无法解除,记录一条带有确切浏览器报错信息的 coverage gap(覆盖缺口),且不得声称该路由已被测试。
红线:未经明确批准,不得删除浏览器配置文件数据,也不得关闭用户可见的浏览器窗口。
浏览器会话清理
每次 QA 结束时,如果浏览器 MCP/工具暴露了 close-page、close-context、close-browser 或 end-session 类动作,就关闭浏览器自动化会话,防止陈旧的 Chromium 会话长期占住配置文件锁、干扰后续 QA。
同样地,不要关闭用户可见的浏览器窗口。如果上一个 Agent 遗留的无头 Chromium 进程阻塞了运行,而 MCP 又没有关闭动作,先询问再杀,并且只瞄准 Agent 启动的浏览器进程。文档给出了识别 Agent 启动会话的命令行标记(command-line markers),用于在检查进程时向用户精确说明要终止什么:
ms-playwrightmcp-chrome-remote-debugging-pipeplaywright-mcp
而用户可见的浏览器通常走正常浏览器配置文件,不属于这些标记。
三、Snapshot 与"证据优先"截图纪律
Snapshot 的克制使用
默认从一次默认快照开始,仅在以下情况才加深或滚动:
- 目标元素很可能在首屏折叠线(below the fold)以下;
- 折叠面板隐藏了被改动的功能;
- 默认快照只有 loading 或空壳(shell)内容。
纪律要点:在检查过合理的滚动或标签页状态之前,不得声明某元素不存在——元素"缺席"必须是在已穷尽合理视图状态之后才能下的结论。
Proof-First 截图:每张图都要"自证"
Proof-First(证据优先)是本文档最核心的截图原则:每一张截图都必须能可见地证明它所支撑的那条覆盖行(coverage row)。拍摄之前,先确定能让该用例通过或失败的具体元素——精确的文本、控件、表格行、图表、Toast、表单状态——然后:
- 等待这个证明元素出现;
- 必要时滚动到可视区;
- 截图时带上足够的上下文,让审查者能看懂路由与状态。
对长页面、落地页(landing pages)、定价页、文档页等"hero 引导式"布局,假设首屏只是设置上下文而不是证明:只截 hero 区域不能作为页面下方 gate、表单、警告或 CTA 状态的有效证据。应滚动到被改动的区域再截,或使用整页截图——前提是整页截图仍可读、证明区域容易找到。
每次截完候选图后,在标注或上传前先检查保存的文件。若证明被裁掉、被 banner 或字幕遮挡、太小无法辨认,或画面大部分是导航栏、调试边框、无关页面设置,就重截。如果截图需要一个图注来解释术语,就在报告里补一句简短说明,而不是只靠图本身。
四、Console 与网络信号:分级与甄别
建立基线再对比
页面初次加载后先收集一份基线控制台快照(baseline console snapshot),目标动作执行后再对比。只有满足以下条件的新错误才算相关:出现在目标交互之后,或明确属于被锻炼到的端点。
已知的、动作前就存在的第三方噪音,如果它不影响被改动的流程,可以忽略。
区分本地栈噪音与 PR 引入的错误
在对任何控制台输出打分之前,先通过 phrocs MCP 检查进程相关的开发状态(这是 SKILL.mdallowed-tools中mcp__phrocs__*的典型用途):
mcp__phrocs__get_process_status(process="backend")mcp__phrocs__get_process_status(process="frontend")- 错误所指的进程,例如
capture、feature-flags、temporal-worker或mcp
注意:不要依赖启动期间的"全进程状态"(all-process status)——进程级调用可能已经可用,而全进程状态仍不稳定。
只有当下游进程停止/崩溃能解释这些错误时,才按以下常见模式降权处理:
| 常见错误 | 可解释的本地进程状态 |
|---|---|
capture、capture-ai、capture-replay端点出现 502 | 这些进程为stopped或crashed |
| invocations / hog flow 路径出现 500 | posthog-node(CDP)或temporal-worker进程宕机 |
/decide、remote-config、feature-flag 端点出现Failed to load resource: 404 | feature-flags或flags-consumer已停止 |
| 开发环境第三方脚本导致的 CORS 或字体 CDN 失败 | — |
判定范围(in-scope vs out-of-scope)
- 范围内(值得标记):错误触碰了 PR 实际改动的代码路径,无论它何时触发——包括初始挂载时、任何用户交互之前。首渲染就抛异常的场景、加载时就请求了错误端点的场景,是真实 bug 而非既有噪音。受影响界面在加载时报错,与点击/提交后的报错享有同等审查权重。
- 范围外(值得降权):错误能被上表列出的本地进程停止状态解释,或来自与 diff 无关的第三方脚本。
关键纪律:降权时必须把分级结论显式写进 run notes 和 PR 评论(例如"所有控制台错误均追溯到此机器上 capture 进程已停止;本 PR 未引入新错误")。静默吞掉控制台输出会侵蚀报告的可信度。
页面上下文辅助(Page Context Helpers)
- 只有为了设置或检查可见流程所需的前端状态时,才在浏览器页面上下文里使用已认证的
fetch。Cookie 与 CSRF 状态来自浏览器会话。不要把它变成一套独立的后端测试计划。 - 仅在无认证健康检查(如
_health)时使用 shellcurl。
五、可复现性:一次强制重试
任何"发现"成立之前,必须重试一次:
- 只重置该步骤所需的本地页面状态;
- 重跑同一动作序列;
- 捕获全新证据;
- 确认同样的"期望 vs 实际"错配。
如果第一次失败、重试通过,且重试成本很低,再跑一次。此时不要把它报告为已确认发现,但也不要隐瞒:给它独立的 coverage 行,结果标注为INTERMITTENT,把第一次失败的证据保留在 run 目录里,并在 run notes 中描述观察到的现象。文档给出的理由很直接:"一个读起来像干净 PASS 的真实竞态(race),比一行诚实的 INTERMITTENT 更侵蚀信任。"
六、主题切换(Theme Toggle):暗/亮变体的可靠开关
要锻炼一个场景的暗/亮变体,正确做法是从页面上下文 PATCH 已认证用户的theme_mode并重新加载——这是应用内主题切换器走的同一条路径,也是唯一可靠的杠杆:
// via the browser MCP evaluate tool, in the authenticated page context ;async () => { const csrf = document.cookie.match(/csrftoken=([^;]+)/)?.[1] const r = await fetch('/api/users/@me/', { method: 'PATCH', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrf }, body: JSON.stringify({ theme_mode: 'dark' }), // or 'light' / 'system' }) return { status: r.status, theme_mode: (await r.json()).theme_mode } }然后导航到目标路由(导航会重载 kea state)。<html>上带有服务端渲染的data-boot-theme属性(检查document.documentElement.dataset.bootTheme可看启动状态),但运行时切换不会更新它——验证切换是否生效,应读取计算后的背景色:kea state 直接驱动 CSS 变量,且 PostHog不会在运行时设置darkclass 或data-theme/data-color-mode属性。
;() => getComputedStyle(document.body).backgroundColor // dark: ~rgb(19, 19, 22); light: ~rgb(243, 244, 240)明确不要尝试这些路径(文档逐一给出了理由):
document.documentElement.classList.add('dark')——themeLogic不读它;data-theme/data-color-mode属性 —— 不被查询;window.getKeaContext()—— 生产构建不暴露;- 单独使用
emulateMedia({colorScheme:'dark'})—— 仅当用户theme_mode === 'system'时才生效,而种子用户默认是null/'light'。
运行结束时恢复原始theme_mode(通常是'light'),让开发环境保持原样。
七、播种测试数据(Seeding Test Data)
如果一个 PR 添加的是"显示 X 的计数 / 按 Y 过滤 / 当 Z 时高亮行"之类的行为,它往往依赖全新本地栈中不存在的数据形态。空态(empty states)渲染没问题,但 diff 内的行为永远不会被触发。在声明覆盖之前,先播种锻炼该改动所需的最小数据,否则这次运行是 coverage gap,而不是 PASS。
两个后端存储
Postgres:应用模型(surveys、dashboards、cohorts、data warehouse sources、feature flags、organizations 等)。通过 shell 驱动 Django ORM,保持模型不变量(model invariants)完好:
flox activate -- bash -c "uv run python manage.py shell <<'PY' from posthog.models import Team team = Team.objects.first() # create the minimum rows needed to exercise the diff PY"ClickHouse:事件、人员属性、会话录制、LLM spans 等。优先使用 posthog/test/ 与 posthog/clickhouse/ 下现有的工厂工具;只有当没有工厂覆盖所需形态时,才退回到裸
INSERT INTO ... VALUES (...)。
播种纪律
- 播种最小集合,不要批量灌入类生产规模的数据;
- 给播种行打上可识别的标记(名称前缀、固定描述等),便于日后识别与恢复;
- 播种后重新加载受影响的场景,断言 UI 现在反映了你设置的数据形态;
- 在
run-notes.md和 PR 评论的"What was tested"行里注明播种步骤,让审查者知道创建了哪些前置条件; - 默认不删除播种行(留给调试),只有用户明确要求时才清理。
八、Feature Flag 覆盖:不碰后端,页面上下文直接 override
如果 PR 行为被某个种子用户项目尚未启用的 Feature Flag 门控,新 UI 会一直隐藏,QA 循环永远锻炼不到它。此时可以从已认证的浏览器页面上下文直接覆盖该 flag,无需后端改动:
// Enable a boolean flag posthog.featureFlags.overrideFeatureFlags({ flags: { 'my-flag-key': true } }) // Set a multivariate flag to a specific variant posthog.featureFlags.overrideFeatureFlags({ flags: { 'my-flag-key': 'variant-name' } }) // Clear all overrides posthog.featureFlags.overrideFeatureFlags(false)操作流程:通过浏览器 MCP 的 evaluate 工具在已认证页面上下文发出上述调用 → 导航到目标路由(导航会重载 flag 驱动的渲染)→ 用 snapshot 确认门控 UI 已出现。QA 循环结束时调用overrideFeatureFlags(false)清除覆盖,保持开发环境原样,并在run-notes.md与 PR 评论中注明 override 步骤,让审查者知道测试是在非默认 flag 状态下运行的。
九、证据命名、标注与演示胶卷
证据命名:稳定可读
所有证据统一放在.qa-frontend/runs/<run-id>/下,保持未提交(uncommitted)状态,命名要稳定、可读:
.qa-frontend/runs/<run-id>/001-login.png .qa-frontend/runs/<run-id>/011-save-click-failure.png .qa-frontend/runs/<run-id>/011-save-click-failure.annotated.png .qa-frontend/runs/<run-id>/frontend-qa.webp .qa-frontend/runs/<run-id>/console-errors.json截图优先使用 PostHog 工作区现有的浏览器工具:活动浏览器 MCP/工具,或仓库已有的@playwright/test依赖。不要往package.json里添加截图、图片或视频类依赖包。
标注证据:让每帧自解释
原始截图要求审查者脑补发生了什么,所以关键帧必须标注:截图下方加图注条(说明这一步做了什么)、PASS/FAIL/INFO 芯片,发现(finding)还要在关键元素周围加高亮框。仓库自带的 annotate-evidence.py 用仓库已有的 Pillow 依赖同时完成标注与动画两种工作,用uv run python从可信检出(例如技能目录所在仓库)运行,绝不在 PR 检出里运行——uv run会解析那个工作树的依赖。不要用ffmpeg或为证据处理安装任何东西。
该脚本源码确认了三个子命令:annotate(图注条 + PASS/FAIL/INFO 芯片 + 高亮框)、animate(拼装动画 WebP,可带 GIF 兜底)、video(把录制 WebM 转码为 H.264 MP4,需要本机 ffmpeg)。标注样式直接采用 PostHog 产品色板(frontend/src/styles/base.scss 中的品牌红#f54e00高亮、--success/--danger芯片、品牌黑条 + 奶油色文字),与 cursor-overlay.js 中的颜色保持同步(两处源码都有"keep in sync"注释)。
要标注关键区域,先通过浏览器 MCP evaluate 工具抓取元素的 CSS 像素 rect,连同视口宽度(供 HiDPI 缩放):
;() => { const el = document.querySelector('<selector for the element that matters>') const r = el.getBoundingClientRect() return { x: r.x, y: r.y, w: r.width, h: r.height, viewportWidth: window.innerWidth } }然后标注该帧。保留原始 PNG,标注副本写在其旁边:
uv run python "<skill_dir>/scripts/annotate-evidence.py" annotate \ --input "$RUN_DIR/011-save-click-failure.png" \ --caption "Clicked Save - no toast, no network call" \ --step 3 --status fail \ --highlight 840,220,320,88 --viewport-width 1280要点:--highlight可重复且可选,整帧都是故事时可省略。由于浏览器是通过元素引用驱动的,截图里永远不会出现光标——当一帧展示交互时,加--click X,Y(被点击元素的中心点)绘制带点击环的光标,读者才能看到动作发生在哪里。--click用于交互,--highlight用于结果区域,同一元素同时加两者是冗余的。图注陈述"发生了什么、意味着什么",而不是内部代号。
Demo Reel:2~5 帧慢速动画 WebP
浏览器或视觉目标捕获两张以上截图后,把 2~5 个已标注关键帧拼成慢速动画 WebP。WebP 在远小于 GIF 的体积下保留完整 24 位色彩,且 GitHub 在 PR 评论中内联渲染动画 WebP:
uv run python "<skill_dir>/scripts/annotate-evidence.py" animate \ --frame "$RUN_DIR/003-state-a.annotated.png:1500" \ --frame "$RUN_DIR/011-save-click-failure.annotated.png:2500" \ --frame "$RUN_DIR/014-state-c.annotated.png:1500" \ --output "$RUN_DIR/frontend-qa.webp"只收录审查者跟读流程所必需的帧——在有意义时刻之间跳过死时间正是拼接胶卷的意义。每个状态变化都需要成因在画面里:在出现/变化了某物的帧之前,前一帧必须在引起该变化的控件上带--click标记。凭空出现、看不到点击的副本读起来是困惑而非证据——重试帧也适用此规则,重试本身也是独立的因果对。发现(finding)帧给更多放映时间。
脚本实现细节(源自 annotate-evidence.py):宽度上限 1200px,混合高度帧用底部锚定补齐而非拉伸(保证每帧图注条位置一致),默认每帧 1800ms,输出时打印文件大小。3~5 帧 1200px UI 截图的胶卷可稳稳落在 200 KB 以下。只有当确实需要 GIF 兜底时才加--gif <path>,同样帧数的 GIF 体积会大数倍。
上传或嵌入胶卷之前,用 Read 工具或直接打开检查它。如果文字不可读、序列不如静帧清晰,就把标注 PNG 作为证据。
十、录制演示通道(Recorded Demo Pass):默认视频输出
WebP 胶卷像 GIF 一样自动播放,无法暂停或拖动进度。真正的视频只有在展示"人眼所见"时才值得:平滑的页面过渡 + 可见光标移动到每个控件。元素驱动的自动化不渲染任何光标——截图和会话录制里都没有——所以 QA 循环的原始录制又跳又难跟。不要用拼接静帧的方式做视频,那只是一个可暂停的胶卷。
默认做法:QA 循环稳定后,跑一遍演示通道(demo pass)——重新执行关键流程一次,开启录制并注入可见光标。仅当设置了NO_VIDEO、浏览器工具无法录视频、或缺少ffmpeg时才跳过——绝不静默跳过:在 run notes 和报告 Setup 节中说明跳过原因。
六步演示通道
开始录制:优先用浏览器工具的原生录制(agent-browser 可用时用
agent-browser record start "$RUN_DIR/demo.webm";或用 Playwright MCP 视频捕获PLAYWRIGHT_MCP_SAVE_VIDEO=1280x720,它暴露带 chapter markers 的browser_start_video/browser_stop_video)。两者都不可用时,先询问再重新配置,然后跳过视频模式而不是即兴发挥。等待页面恢复可用:开始录制通常会重建浏览器上下文、重载页面;冷开发服务器上这次重载可能很慢。轮询标记元素而不是固定 sleep。首次动作之前录到的都是要修剪的片头。
注入光标叠加层:用浏览器工具的 evaluate/eval 把仓库脚本 cursor-overlay.js 注入页面。它绘制跟随真实鼠标事件的光标、点击时产生涟漪、显示图注条,并暴露
window.__qaCursor。叠加层纯视觉(pointer-events: none),且每次导航后都必须重新注入。整段流程写成一次连续批处理:步骤之间的停顿全都会上镜。每步:设图注 → 滑行(glide)→ 涟漪(ripple)→ 点击 → 短暂定格。图注讲述与标注静帧相同的故事(步骤号、发生了什么、pass/fail):
window.__qaCursor.caption('Step 2 · Clicking Duplicate on Question 1', 'info') const r = el.getBoundingClientRect() await window.__qaCursor.glide(r.x + r.width / 2, r.y + r.height / 2, 650) window.__qaCursor.ripple(r.x + r.width / 2, r.y + r.height / 2) el.click()如果会话中真实输入事件不可靠(agent-browser daemon 的已知怪癖),程序化
el.click()加显式ripple()在影片上看起来一模一样。注意:图注条覆盖页面底边,而 PostHog 的 Toast 和部分操作按钮锚定在底部——当某步的证明是底部锚定元素时,用window.__qaCursor.caption(null)在该节拍清掉图注,之后再恢复,确保录制从不遮挡它要展示的结果。这些能力在 cursor-overlay.js 源码中均有对应实现(caption/glide/ripple/moveTo,mousemove/mousedown监听器)。停止录制、修剪片头并转码:
uv run python "<skill_dir>/scripts/annotate-evidence.py" video \ --input "$RUN_DIR/demo.webm" \ --output "$RUN_DIR/frontend-qa.mp4" \ --trim-start <lead-in seconds>--trim-start使用 ffmpeg 输出定位(output seeking),从头解码、帧级精确裁剪。绝不要自己用输入定位(-ss/-sseof放在-i之前)修剪 WebM:录屏 WebM 关键帧非常稀疏,输入定位会大幅偏离请求点,静默平移整个时间窗。脚本源码中video子命令正是把-ss放在-i之后的输出定位实现,并附加scale + yuv420p、libx264 veryfast crf 26、-movflags +faststart等参数。发布前验证视频:Agent 看不了视频,所以渲染一张帧联系表(contact sheet)来检查:
ffmpeg -y -i "$RUN_DIR/frontend-qa.mp4" \ -vf "fps=1,scale=420:-1,tile=5x2" -frames:v 1 /tmp/qa-video-sheet.png # fps=1 with tile=5x2 covers 10 seconds; for longer clips raise the tile # (tile=5x4 for 20 s) or lower fps - the sheet must reach the final frame联系表必须显示:前几秒就有图注条、每一步的图注按顺序出现、帧间有运动(没有大段相同空闲帧)、最后持有最终 finding 状态。不满足就修正裁剪再查;不要分享未验证的视频。
视频输出与分享约束
- 转码需要本机
ffmpeg;缺失则保留 WebM 并在 run notes 中说明。15 秒 1280px 演示视频大约 300 KB;MP4 控制在 ~10 MB 以内,保证能直接拖进 GitHub 评论。 - 不要尝试在 Agent 发布的评论里自动内嵌视频:GitHub 只为通过网页编辑器手工上传的文件渲染播放器,raw 托管的 MP4 链接按下载处理、不可播放。MP4 从本地报告链接出去;PR 模式下可经
hogli pr:upload-video进入已批准的上传集(评论里是下载链接),开发者仍可把文件拖进评论编辑器获得内联播放器。 - 叠加层只用不透明品牌色,明暗主题下可读性一致。
十一、证据上传与输出纪律(配套参考)
证据产出的最终归属与上传纪律由配套参考 evidence-and-output.md 定义,与本文档的浏览器模式紧密咬合:
- 上传仅限 PR 模式且必须显式批准:用仓库自带上传器
hogli pr:upload-image(png/jpg/gif/webp,10 MB 上限),上传到公开的PostHog/pr-assets仓库并打印alt行。上传是公开且永久的(URL 经 SHA 固定,删除后仍持续服务,不可撤回),所以上传前必须向用户展示确切文件清单并取得批准。第一个不带--yes的运行只打印警告、故意不传;--yes即"用户已批准这组文件"的确认,未经批准绝不传入。 - 只挑人眼可见的证据:
frontend-qa.webp(若生成且检查可读)+ 1~3 张与 findings 或 PASS 叙事匹配的标注关键截图;不上传.md快照、console.log或每一张编号截图。MP4 走hogli pr:upload-video --yes --label "demo video"。 - 运行产物:每次运行必须写
findings.json(结构化 findings 数组,PR 评论与本地报告都是它的渲染结果)并在 stdout 首行输出QA-VERDICT: <verdict>(取值PASS/FIXED/FAIL/NEEDS-INTENT/REPORT-ONLY),供外层编排器 grep。coverage_gap条目必须作为测试计划表中的可见行呈现,而不是页脚备注。 - run-notes 贯穿始终:栈选择、工作区与登录、org/plan 状态、创建/播种的数据、flag/主题覆盖、降级的进程等所有设置,都随发生追加到
.qa-frontend/runs/<run-id>/run-notes.md,报告必需的 Setup 节正是从这些笔记渲染而来。 - 安全边界:safety-rules.md 强调
.qa-frontend/下的证据绝不 stage 或 commit(老 PR 分支上该目录未被 gitignore,git add -A会把本地栈截图卷进 fix 提交);控制台摘录发布前必须擦除Bearer <token>、?token=、sk-*、长 base64 值、cookie/会话 ID/CSRF token;不上传包含邮件、工作区名、仪表盘内容或渲染 token 的截图。
十二、总结:从"跑一遍"到"可审查的证据链"
浏览器 MCP 模式把 PostHog 前端 QA 从随意的"点一点、截个图"升级为一条可复现、可审计的证据链:
- 流程标准化:七步浏览器骨架(navigate → snapshot → interact → assert → screenshot → console/network)让每次 QA 覆盖同样的关键动作;
- 证据可自证:Proof-First 截图 + 图注条/PASS-FAIL 芯片/高亮框标注 + WebP 胶卷,让审查者无需重放会话即可读懂运行;
- 噪音可甄别:通过 phrocs 进程状态把"本地栈崩溃导致的错误"与"PR 真正引入的错误"区分开,降权结论必须显式写入报告;
- 状态可控:theme_mode PATCH、最小数据播种、Feature Flag override 三个"前置条件"杠杆,确保 diff 内行为在种子环境下真正被触发;
- 安全有边界:浏览器 MCP 作用域最窄化、不提交 MCP 配置、配置文件锁需询问、上传需批准——QA 全程不触碰用户可见浏览器与已入库配置。
这些模式的完整实现与配套脚本(标注/动画/转码工具 annotate-evidence.py、光标叠加层 cursor-overlay.js、技能总纲 SKILL.md)都保留在当前仓库中,可作为其他项目搭建"证据驱动前端 QA"体系的直接参考。
【免费下载链接】posthog:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.项目地址: https://gitcode.com/GitHub_Trending/po/posthog
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考