For AI agents: the complete documentation index is available at https://a3s-lab.github.io/Test/llms.txt, the full documentation bundle is available at https://a3s-lab.github.io/Test/llms-full.txt, and this page is available as Markdown at https://a3s-lab.github.io/Test/guide/testkit.md.

接入 Web Test Kit

如果要在开发页面中点选元素、框选区域、画出期望的 UI 或附上页面截图,只需安装 Test Kit,并在应用根节点挂载两个组件。完成下面三步后,页面会出现 A3S 页面评审 入口。默认反馈流程只需要两个决定,选择元素或区域,然后描述期望结果。

Test Kit 增加了什么

Test Kit 把渲染后的页面连接到负责它的实现,但不会把业务页面变成编辑器。

需求技术实现
让 Agent 读取截图之外的页面事实无界面的 Context Runtime 在 DOM、可访问语义、样式与布局计算完成后生成有界事实
让人准确指出问题一个右侧 Review Overlay 常驻元素与区域入口,按需展开高级标记、画板和截图工具
从点选节点定位到代码显式组件边界、DOM 归属注册和可选 Source Map v3 生成排序后的源码跨度
阻止旧目标继续作用于新页面精确修订差异只保留未受影响的上下文目标,其余绑定全部关闭失败
把评审与源码修改分开保存只留在本地,只有明确发送才进入 A3S Test Repair Ledger
浏览器完成渲染
  -> Context Runtime 发布有界修订
  -> 评审者选择一个目标并描述修改
  -> Test Kit 附带当前页面、组件、几何与源码证据
  -> 明确发送后才进入 Repair Ledger
  -> 拥有工作区的 Agent 修改源码
  -> A3S Test 在更新后的页面修订中验证

三步完成 React 接入

1. 安装开发依赖

在前端工程目录执行固定版本的安装命令:

npm install --save-dev @a3s-lab/testkit@0.6.2

该包已通过 GitHub OIDC provenance 发布到官方 npm Registry。固定安装的 0.6.2 版本已包含简化评审侧栏、有界 SVG 画板、页面内框选截图、CLI 实时兼容握手、渲染节点源码映射和修订级 Page Context 差异,不需要浏览器扩展、绘图库、截图插件或屏幕共享权限。

确认依赖已经进入当前工程:

npm ls @a3s-lab/testkit

2. 在应用根节点挂载

下面是可工作的最小 React 接入。Test Kit 仅在开发环境启用,业务应用继续作为普通子节点渲染。

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { A3SReviewOverlay, A3STestKit } from '@a3s-lab/testkit/react';
import { App } from './App';

const testKitEnabled = import.meta.env.DEV;

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <A3STestKit enabled={testKitEnabled} page={{ id: 'app' }}>
      <App />
      <A3SReviewOverlay enabled={testKitEnabled} locale="zh-CN" />
    </A3STestKit>
  </StrictMode>,
);

enabled 必须明确为 true 才会安装浏览器 bridge。不要依赖 tree shaking 判断环境,也不要在正常生产页面中启用可见的 Review Overlay。

3. 打开页面并验证

启动原有开发服务器并打开页面。右下角出现 A3S 页面评审 按钮即表示接入成功;也可以按 Ctrl/Command+Shift+F 打开侧栏。按钮没有出现时,先确认以下三点。

  • A3STestKitA3SReviewOverlay 位于同一棵 React 树中。
  • 两个组件的 enabled 在浏览器中都为 true
  • 代码从客户端入口挂载,而不是只在服务端渲染。

Test Kit 是前端 SDK,不会增加一个名为 a3s-testkit 的终端命令。需要从终端运行测试或让 Agent 接收修复任务时,再安装 A3S Test CLI 与 Agent Skill

已经安装 CLI 时,用真实渲染页面验证接入,不要只根据 node_modules 推断兼容性:

a3s-test init
a3s-test doctor
a3s-test dev --json

doctor 只检查静态包版本范围。dev 会在发出 ready 前短暂等待客户端 hydration,再验证 a3s.test.testkit-handshake/1、包身份、SDK 范围、Page Context 协议、必需能力和实际 Review Overlay。ready 事件会带上准入后的 握手结果。必需边界缺失或不兼容时,A3S Test 只中止自己打开的浏览器 session,并给出精确的安装或挂载修复命令。

准入成功后,dev --json 还会在 ready.repair_bridge 中报告 a3s.test.local-repair-bridge/1。用户从普通页面评审侧栏发送 finding 后, A3S Test 会先写入现有 repair ledger 并保存自有的修改前证据,再从同一条 stdout JSONL 流发出 repair_batch。事件已经包含生成的 session ID,coding agent 可以直接领取,不需要另行协调一个 repair-watch 进程。Test Kit 设为可选且页面中完全不存在时,repair_bridgenull,不会启动轮询。

大多数项目到这里就够了

继续配置前,先按实际目标选择所需能力。

  • 页面点选、框选、画板和截图: 使用 A3STestKitA3SReviewOverlay
  • CI 只读取 Page Context: 保留 A3STestKit,省略可见的 A3SReviewOverlay
  • 标注组件归属和源码提示: 再增加 A3STestBoundary
  • 精确定位点选节点的源码: 由框架适配器调用 registerSource,需要时再调用 registerSourceMap
  • 把 finding 发送到自建服务: 再配置同源 repairEndpointonSubmitted
Test Kit 是增强项,不是运行前提

不接入 Test Kit,A3S Test 仍可通过浏览器可访问语义执行类型化动作、断言和证据采集。需要组件归属、源码提示、多坐标空间几何、渲染态 UI 证据或人工点选时,再接入 Test Kit。

按需增加组件边界

A3STestBoundary 不是启动 Review Overlay 的前提。只有需要让 A3S Test 识别组件归属或源码提示时,才包住对应区域。

import { A3STestBoundary } from '@a3s-lab/testkit/react';

<A3STestBoundary
  id="checkout-form"
  name="Checkout form"
  source={{ file: 'src/Checkout.tsx' }}
>
  <Checkout />
</A3STestBoundary>;

让点选节点直接定位源码

大多数应用只需要在 A3STestBoundary 上声明 source,它会为所有后代提供一个粗粒度的归属文件候选。框架适配器还可以声明某个 DOM 节点的精确归属,并按需用显式提供的编码 Source Map v3 把生成代码位置还原到原始源码。

import { registerSource, registerSourceMap } from '@a3s-lab/testkit';

const unregisterMap = registerSourceMap({
  id: 'vite-app',
  generatedFile: 'http://127.0.0.1:3000/assets/app.js',
  mapUrl: 'http://127.0.0.1:3000/assets/app.js.map',
  map: encodedMap,
});

const unregisterOwner = registerSource({
  id: 'react:pay-button',
  framework: 'react',
  elements: () => [document.querySelector('[data-testid=pay]')!],
  includeDescendants: false,
  generated: {
    file: 'http://127.0.0.1:3000/assets/app.js',
    line: 1,
    column: 1,
  },
});

export function disposeSourceMapping() {
  unregisterOwner();
  unregisterMap();
}

点选后的节点会得到按置信度排序的 sourceMapping.candidates。每个候选都带有 exactancestor 关系,以及 framework_adaptersource_mapboundary_hintgenerated 来源。用户明确发送 finding 后,同一份记录会进入 repair context,coding agent 不需要再增加一次浏览器探索就能先打开最可能的文件。

注册必须显式完成。Test Kit 不会读取 React Fiber、Vue 实例或其它框架私有状态,不会自行发现或下载 Source Map,并会在保存注册数据前丢弃 sourcesContent。源码候选只是定位证据,不授予文件读取或修改权限。

框架无关接入

非 React 页面可以直接安装 runtime,并显式注册一个或多个组件边界。

import { getPageContextBridge, installTestKit } from '@a3s-lab/testkit';

const checkout = document.querySelector('#checkout');
if (!checkout) throw new Error('Checkout root is missing');

const runtime = installTestKit({
  enabled: import.meta.env.DEV,
  page: { id: 'checkout' },
  ready: () => document.readyState !== 'loading',
  facts: () => ({ currency: 'CNY' }),
  redact: ['[data-payment-field]'],
});

const unregister = runtime.registerBoundary({
  id: 'checkout-form',
  name: 'Checkout form',
  elements: () => [checkout],
  source: { file: 'src/checkout.ts' },
});

export function disposeTestContext() {
  unregister();
  runtime.dispose();
}

console.log(getPageContextBridge()?.probe());

同一页面只保留一个 active runtime。再次调用 installTestKit 会先释放旧 runtime。SPA 切换应用根、微前端卸载或测试夹具结束时,应调用 dispose(),避免观察器和 bridge 残留。

Next.js 客户端边界

A3STestKit 使用浏览器 effect,因此要从 Client Component 挂载。服务端渲染可以继续输出业务页面,Test Kit 只在 hydration 后安装 bridge。

'use client';

import { A3SReviewOverlay, A3STestKit } from '@a3s-lab/testkit/react';

export function TestContext({ children }: { children: React.ReactNode }) {
  const enabled = process.env.NODE_ENV !== 'production';

  return (
    <A3STestKit enabled={enabled} page={{ id: 'app' }}>
      {children}
      <A3SReviewOverlay enabled={enabled} locale="zh-CN" />
    </A3STestKit>
  );
}

如果 CI 的浏览器测试需要 Page Context,可以让 A3STestKit 保持启用并省略 A3SReviewOverlay。不要依赖 tree shaking 猜测生产状态,enabled 应由明确环境条件决定。

验证接入结果

先检查 probe,再读取最小快照。

import { getPageContextBridge } from '@a3s-lab/testkit';

const bridge = getPageContextBridge();
if (!bridge) throw new Error('Test Kit bridge is unavailable');

const probe = bridge.probe();
const snapshot = bridge.snapshot({
  detail: 'summary',
  scope: { kind: 'page' },
  limits: { nodes: 100, uiNodes: 50 },
});

console.log({
  protocol: probe.protocol,
  revision: snapshot.revision,
  ready: snapshot.page.ready,
  components: snapshot.components.map((component) => component.id),
  truncated: snapshot.truncated,
});

一次健康接入至少满足以下条件。

  • probe.protocol 等于 a3s.test.page-context/1
  • Test Kit 0.6.0 会在 probe.capabilities 中报告 revision_diff
  • snapshot.page.id 与接入配置一致。
  • 页面完成当前渲染后 snapshot.page.readytrue
  • 声明过的组件边界出现在 components
  • 目标节点有语义定位器或几何,敏感区域没有暴露原文。
  • truncatedtrue 时,调用方会缩小 scope 或使用 nextCursor

bridge 缺失、ready 长期为 false 或 UI 记录被省略时,查看故障排查,不要在业务页面里加入任意轮询。

选择上下文或评审模式

目标需要挂载的组件
本地或 CI 自动测试A3STestKit,按需增加 A3STestBoundary;可以不挂载可见界面
人工点选与批量修复在 Context Runtime 之外增加 A3SReviewOverlay,并配置明确的提交处理或修复端点

Review Overlay 不会因为打开、查看建议或保存本地草稿而获得源码修改权限。只有评审者明确发送的问题才进入拥有会话的修复流程。

画出或附上期望的 UI

点选元素或框选区域后,可以从问题编辑器打开 设计参考。画板会暂时替换 评审侧栏,再通过一段轻量过渡从页面右侧展开;它不显示全屏遮罩,也不会叠加 第二个弹窗。绘图、图片、历史和样式操作集中在一条中文图标工具栏中。

内置 SVG 画板提供自由绘制、矩形、文字、选中、移动、缩放、样式、撤销和 重做,画布固定在有界的 960 × 600 尺寸。评审者可以点击 框选页面截图, 在当前可见页面拖出一个区域,松开后直接把裁剪结果加入画板;按 Esc 会取消 框选并返回画板。这个 DOM 截图不会包含 Test Kit 自己的界面,也不需要屏幕 录制或屏幕共享权限。上传、粘贴和拖入 PNG/JPEG 截图仍然可用。

画板完全运行在 Test Kit 的 Shadow DOM 内,不加载绘图库、许可证密钥、 水印、远程字体或 CDN 资源,最多接收 250 个对象。源图片上限为 8 MiB, 内联引用上限为 384 KiB、1,600 × 1,200 和 1,920,000 像素。Web session 收到 finding 后会重新校验图片头和尺寸,把文件写入 session artifact 根下的 repairs/<finding-id>/design-reference.png|jpg,计算 SHA-256,并用类型化 artifact 元数据替换内联字节。

评审侧栏复用 A3S UI 的视觉约定,同时不会给业务应用增加运行时 UI 依赖。 构建 Test Kit 时,脚本读取固定版本 A3S UI 导出的 foundation、task-pane、 toolbar 和 status-badge CSS,把根选择器与深色主题选择器限制在 overlay 内, 再生成写入 Shadow DOM 样式表的 TypeScript 常量。宿主页面样式无法串入评审 界面,使用方也不需要额外导入样式表。

设计引用只属于评审证据,不是指令边界,也不是验证结论。它不会授予工作区 权限,也不会替代 A3S Test 自己保存的修改前后证据。

Provider 配置速查

属性默认值或要求作用
enabled必须显式传入只有严格等于 true 才安装浏览器 bridge
page.id必填标识当前页面上下文
readydocument.readyState说明页面是否完成当前可观察渲染
facts{}返回经过 JSON 和字节限制的项目事实
redact[]隐藏匹配选择器下的文本和表单内容
maxNodes500Page Context 节点上限,硬上限 5,000
maxStringBytes4 KiB单字符串上限,硬上限 16 KiB
maxEncodedBytes1 MiBPage Context 编码上限,硬上限 8 MiB
uiUnderstandingtrue是否生成可选 UI 理解记录
maxUiNodes200UI 采样节点上限,硬上限 1,000
maxUiStateSamples200状态候选上限,硬上限 1,000
maxUiDurationMs32单次 UI 采集时间,硬上限 100 ms
maxUiEncodedBytes256 KiBUI 编码上限,硬上限 1 MiB
repairStoragesession选择 memory、当前标签页 sessionlocal
repairEndpoint未配置可选同源 repair adapter
maxQualityReports5确定性质量报告保留数,范围 1 到 20
maxDesignAuditReports5建议性设计报告保留数,范围 1 到 20

安装级选项只设上限。单次 snapshot() 可以降低节点、字符串、编码、UI 节点、状态、时间和 UI 编码预算,不能提高。

公开 Bridge API

大多数 React 工程只需挂载组件。框架集成、测试夹具或自定义评审界面可以通过 getPageContextBridge() 取得同一份公开 bridge。采集与修改方法受 active runtime、当前页面修订和安装预算约束,读取方法返回存储状态的副本。

方法用途与返回值状态与权限边界
probe()返回协议、SDK 版本和能力名称只做同步能力发现,不采集页面快照
snapshot(request?)读取 summary、scoped、diff 或 forensic 快照,并支持 page、node、component、region scope结果可能截断;cursor、scope 和 revision 必须保持一致
resolve(nodeId)把当前私有 node ID 解析为仍然连接的 DOM Element仅用于页面内集成;未知、已移除或过期节点返回 null
waitForChange(revision, timeoutMs)等待更高修订号,立即变化时直接返回,超时返回 nulltimeout 必须是 0 到 300,000 的整数
waitForDiff({ sinceRevision, timeoutMs, ...request })等待一次更高修订并返回精确有界差异,超时返回 null非法 baseline 和 timeout 会拒绝,不会取整或 clamp
subscribe(listener)订阅 context、quality、design audit 和 repair 事件,返回取消订阅函数listener 只观察事件,不获得动作或工作区权限
submitRepair({ findings, batchId? })校验 finding、捕获当前上下文并返回进入 queued 的记录重复 finding ID 幂等返回旧记录;只有这一步代表明确发送
peekRepairBatch(limit?)takeRepairBatch(limit?)查看或在页面侧保留最多 100 条 queued findingtake 防止同一 bridge 重复提取,不替代 Agent 的 lease claim
listRepairs()listRepairBatches()读取按提交时间排序的记录和聚合批次状态返回结构化副本,调用方不能借修改返回对象改变状态
exportRepairs(findings)exportRepairsMarkdown(findings)导出最多 100 条 finding 的 JSON 协议或 Markdown导出不发送、不领取,也不授权修复
applyRepairEvent(event)应用 Agent 或服务器返回的严格状态事件要求递增 sequence、合法迁移和幂等 request ID
submitRepairAction(action)takeRepairActions(limit?)排队并提取人工 reply、accept、dismiss 或 reopen人工动作仍要由 session 端确认,不能绕过 Repair Ledger
addRepairReply(reply)listRepairReplies(findingId)追加并读取有界讨论线程finding 必须存在,每项回复受 request ID 与长度限制
reportQuality(report)listQualityReports()dismissQualityFinding(reportId, findingId)dismissQualityReport(reportId)接收、读取或关闭确定性 Surface Contract 质量报告严格校验协议、大小、finding ID 和 scope;报告 verdict 保持不变
reportDesignAudit(report)listDesignAuditReports()dismissDesignAuditFinding(reportId, findingId)dismissDesignAuditReport(reportId)接收、读取或关闭建议性设计审计报告要求当前 revision、合法来源与仍存在的 node;关闭建议没有修复副作用
setAnimationsPaused(paused)animationsPaused()暂停或恢复当前 Web Animations 和正在播放的媒体,读取当前暂停状态只用于评审稳定画面;dispose 会恢复由 Test Kit 暂停的内容
dispose()断开 observer、waiter、listener、边界、报告和全局 bridge幂等;随后 active-runtime 操作会拒绝,修复历史副本仍可读取

TestKitRuntime 还提供 registerBoundary()。顶层导出的同名函数会先查找已安装 bridge,未安装时直接报错。installTestKit({ enabled: false }) 返回禁用 runtime,其中 probe()snapshot() 明确拒绝调用,修复和报告方法返回空结果,不会偷偷启用页面采集。

只观察真正变化的部分

先取得一次普通 baseline,再等待下一次有意义的差异。

let baseline = bridge.snapshot({ detail: 'summary', ui: false });
const diff = await bridge.waitForDiff({
  sinceRevision: baseline.revision,
  timeoutMs: 5_000,
  ui: false,
});

if (diff?.delta?.status === 'reset_required') {
  baseline = bridge.snapshot({ detail: 'summary', ui: false });
}

complete 会列出每个变化或消失的节点、变化组件,以及 page、facts、UI 是否失效。reset_required 表示精确 baseline 已不在有界历史中,或完整失效集合无法装入字节上限;此时应丢弃旧证据,不能把它理解为“没有变化”。Cursor 绑定完整请求和修订,所以 diff 分页不会悄悄漂移到另一个 baseline。

Review Overlay 属性与回调

A3SReviewOverlay 可以只使用内置 UI,也可以把草稿和发送事件交给宿主工程。回调只观察已经发生的界面事件。同步异常和 rejected Promise 会被隔离,不能破坏评审状态。

属性或回调默认值或触发时机用途
enabledfalse只有严格为 true 且存在兼容 bridge 时才挂载 Shadow DOM overlay
defaultOpenfalse设定首次挂载时面板是否展开,不把后续状态变成受控属性
autoSendfalse设定首次保存是否直接提交;评审者仍可在工具栏切换
localeauto选择英文或简体中文,并可跟随 <html lang>
messages覆盖已知显示文案,空值和超过 2,048 字符的值被忽略
copyToClipboard使用 navigator.clipboard.writeText为受限 iframe、Electron 或自定义权限环境注入复制实现
onCopiedJSON 或 Markdown 成功复制后接收格式、最终文本和被复制草稿
onDraftAddedonDraftUpdatedonDraftDeleted对应本地草稿操作完成后同步宿主界面的草稿统计或遥测,不代表 finding 已发送
onDraftsCleared清空草稿或按偏好复制后清空时接收实际移除的草稿副本
onSubmittedsubmitRepair() 返回后接收真正进入 Repair Ledger 的 SubmittedRepair[]

中文界面与项目文案

A3SReviewOverlay 支持 locale="auto" | "en" | "zh-CN"。默认值 auto 会在组件挂载期间观察页面的 <html lang>;任何 zh-* 语言标签都会使用简体中文,其余语言使用英文。中文站点建议像上面的示例一样显式传入 locale="zh-CN",避免宿主页面语言配置错误时退回英文。

项目可以受限覆盖少量界面文案。

<A3SReviewOverlay
  enabled={import.meta.env.DEV}
  locale="zh-CN"
  messages={{
    reviewTitle: '页面评审',
  }}
/>

messages 只接受已知文案键。空字符串和超过 2,048 个字符的值会被忽略;这些内容只影响显示,不会进入页面上下文、修复指令或 Agent 的隐藏输入。

A3S Test 能看到什么

每个快照带有单调递增修订号,并把以下事实绑定在一起。

  • 角色、可访问名称、状态和 DOM 层级。
  • Test Kit 边界、组件标识和有界源码提示。
  • 优先语义定位器与明确退化顺序。
  • 视口、文档和标准化坐标中的元素几何。
  • 布局视口、设备像素比,以及可选 visual viewport 的偏移与缩放。
  • 有界 computed style、页面事实和脱敏后的表单状态。
  • 观察到的设计令牌、包含 overflow/裁剪状态的布局关系、重复结构、真实交互状态差分和时间轴感知的动效事实。

MutationObserver、ResizeObserver、滚动、视口和导航信号会推进修订号。没有变化的页面不会被轮询。浏览器 ref、坐标、截图和 UI 证据会随修订漂移失效。只有完整 delta 经过 Rust 校验并证明私有节点身份未变时,Page Context @cN 才能保留背后的稳定定位器;delta 缺失或要求 reset 时会清空全部旧上下文绑定。

区分可操作引用与只读证据

引用含义权限
@eN当前浏览器观察中的可访问语义节点可操作,只在生成它的观察中有效
@cN当前 Page Context 中可唯一操作的节点在该观察内可操作;只有未受影响的稳定定位器可以跨过修订漂移
@uNUI 理解中的证据节点只读,只能关联样式、布局、状态与动效事实

公开观察不会暴露 Test Kit 的私有节点 ID,持久 session 元数据只保存带域隔离的 SHA-256 节点指纹。可唯一操作的 UI 节点复用 @cN,其他证据节点投影为 @uN。任何 @uN 动作都会在 ACL 准入或驱动执行前被拒绝;如果投影后无法同时保留图完整性和字节预算,可选 UI 证据会被省略。

渲染态 UI 理解

每个快照默认包含一个可选的 a3s.test.ui-understanding/1 嵌套记录。它补充浏览器可访问树缺少的视觉事实,不创建一棵竞争性的语义树,也不猜测产品意图。

证据来自浏览器的事实
样式画像颜色、字体、间距、圆角、阴影、z-index、安全的根级设计属性和响应式条件。
布局图Flex、Grid、普通流、精确的 client/scroll 尺寸、有符号滚动偏移、逐轴 overflow 与当前裁剪状态、物理 margin/border/padding 边值、box sizing、书写模式、文本方向、包含、offset parent、滚动容器和层叠上下文关系。
重复结构根据标签、角色、语义状态、有界子树形状和 computed style 生成确定性指纹。类名本身不会被当作组件事实。
状态差分从已观察的默认状态到真实 hover、focus、focus-visible、checked、expanded、selected 或 disabled 状态的变化。Test Kit 不会为了采集而主动触发交互。
动效画像transition、CSS 与 Web Animations、document/scroll/view/具名时间轴、animation range、关键帧名称、sticky 与滚动节点、canvas、媒体界面和 reduced-motion 偏好。

记录使用独立的 observationId,因为焦点、悬停或运行中的动画可能改变 computed state,却不改变页面语义修订号。它的 pageRevision、viewport 与 scope 仍必须和外层 Page Context 一致。物理盒模型边值与书写模式、文本方向分别记录,Test Kit 不会据此虚构逻辑布局意图。浏览器没有暴露已解析的 Web Animations 时间轴时,具名 CSS 时间轴只记录为 named,Test Kit 不会猜测它由滚动还是视图驱动。Web 驱动会拒绝过期绑定、未知字段、非法几何、格式错误的盒模型证据、互相矛盾的 overflow/裁剪或时间轴证据、不一致的截断信息和预算越界。它还会拒绝重复布局节点或边、缺失的父节点或任一边端点、与 parentNodeId 冲突、不完整或循环的包含关系、重复证据引用、不属于成员集合的组件代表节点,以及超出声明采样节点数的布局数据。

默认预算为 200 个采样节点、200 个状态候选、32 毫秒和 256 KiB。maxUiNodesmaxUiStateSamplesmaxUiDurationMsmaxUiEncodedBytes 可以降低安装上限,每次 snapshot() 请求还可以继续收紧。单次请求使用 snapshot({ ui: false }) 关闭;整个安装不需要该投影时使用 uiUnderstanding={false}

用于验证修改结果的截图仍由 A3S Test 证据层负责;评审者主动添加的设计参考截图则属于 finding。评审者明确发送问题后,同一份有界 UI 记录会随 untrusted: true 修复上下文提交,让拥有工作区的 Agent 把选中节点与页面视觉系统准确关联起来。

人工标记与批量修复

Test Kit 0.6.2 把评审收敛到一个固定侧栏。默认流程只需要两个决定,选择元素或区域,然后描述期望结果。文本、多选、手绘和 Layout 收在 更多工具 中,需要时才展开。选中目标后,编辑器会在原位置替换工具,保存或发送就是最后一步。顶层只保留 新反馈问题,偏好设置移到标题栏。整个过程不会打开贴着目标的编辑器、第二层浮动工具栏或嵌套弹窗。

画板打开时会暂时替换评审侧栏,关闭后回到同一个编辑器。短桌面视口中的问题和偏好内容会在侧栏内部滚动;移动端使用单一全宽界面,主要操作提供至少 44 CSS 像素的触控目标,表单文字保持 16 像素,避免浏览器自动缩放。开始标记后,桌面和移动端侧栏都会暂时让出页面,只保留轻量的“完成选择 / 取消”提示条,因此被侧栏覆盖的内容也能直接选择;侧栏回来后,页面标记始终位于它的下方。

元素与文本标记会在页面或内部滚动容器滚动后,根据目标节点的实时 DOM 坐标重新计算,当前候选也使用同一套定位。完成点选时,临时 hover 框会立刻清除,不会停在旧的视口坐标。区域标记会结合框选时记录的滚动原点重新定位。关闭 Test Kit 后,页面上的所有标记都会停止渲染,重新打开后才恢复。

Overlay 支持元素、文本、点击或拖动多选、矩形和自由手绘标记。评审者可以完成以下操作。

  1. 选择一个目标或按顺序组织一批目标。
  2. 添加修复说明、回复、冲突关系与验收决定。
  3. 先保存本地草稿,或明确发送到拥有该会话的 A3S Test。
  4. 等待编码 Agent 修改源码并执行新浏览器验证。
  5. 接受、拒绝或重新打开修复结果。

Overlay 打开后,可以按 EMTAD 分别开始元素、多选、文本、区域和手绘标记;LPH 分别切换 Layout Mode、页面动画和标记显示。焦点位于输入框或编辑器时,字母快捷键不会接管输入。

Overlay 位于开放的 Shadow DOM 中,中文按钮名称、状态、提示、实时播报和 ARIA 名称使用同一套文案目录。键盘焦点会在关闭编辑器、取消标记和隐藏组件时返回到稳定控件;这些本地化不会改变页面上下文协议或修复数据。

Layout Mode 只生成类型化 placementrearrange 意图和视口 CSS 像素目标。它不会直接移动、重排或修改宿主 DOM。

内置的 90 种组件类型都支持中英文显示与搜索。切换页面语言时,已选择的内置组件名称会同步切换;项目自行输入的组件类型会保持原样。

安全边界

Test Kit 不接收工作区、Shell、MCP 或源码编辑凭据。DOM 上下文被明确标记为不可信证据。Quality Store、Design Audit Store 和 Repair Ledger 分开保存,查看建议或打开编辑器不会自动授予修复权限。

确定性 Surface Contract 差异可以阻断套件,但投影到 overlay 只作为评审候选。设计审计结果始终是建议。只有人工保存或发送后,候选才进入现有单项或批量修复流程。

生产构建通常关闭 Test Kit。CI 如需页面上下文,可以保留 A3STestKit 并省略 A3SReviewOverlay。Next.js 中应从客户端组件挂载,并以 process.env.NODE_ENV !== "production" 明确控制。

继续深入