108 KiB
测试与验收要求
本文件用于测试 Skill 的行为、失败处理和边界提醒。
测试 1:用户信息不完整
输入:
我要补环境,目标是 example.com。
期望:
- 不开始逆向分析。
- 列出缺失的必填字段。
- 提供信息收集模板。
缺失项应包含 API URL、请求方法、加密参数名、参数位置、成功请求样本、取证模式、最终请求 TLS 指纹兼容客户端。
测试 2:只提供 URL 和参数名
输入:
目标网站:https://example.com
加密参数:sign
期望:
- 不进入正式流程。
- 要求补充 API URL、请求方法、参数位置、成功请求样本、取证模式和最终请求 TLS 指纹兼容客户端。
测试 3:提供完整必填信息
输入包含目标网站、API、请求方法、加密参数、参数位置和 Copy as cURL。
期望:
- 输出任务确认。
- 不立即写补环境代码。
- 如果缺少取证模式或最终请求 TLS 指纹兼容客户端,先要求用户补充;如果都已提供,先要求用户确认流程。
测试 4:请求样本中找不到目标参数
期望:
- 在后续分析前停止。
- 要求用户确认参数名、参数位置,或补充 HAR / Network 截图。
建议提示:
在当前请求样本中未找到目标加密参数 `sign`。
请确认参数名是否正确、参数是否位于 Header / Query / Body / Cookie 中,以及提供的是否为加密后的成功请求。
测试 5:JS 文件无法获取
期望:
- 明确说明 JS 文件无法获取。
- 给出可能原因:需要登录、缺少 Cookie、缺少 Referer、资源过期、动态 chunk 需交互后加载、CSP 或鉴权限制。
- 要求用户补充本地 JS 文件或浏览器导出的材料。
测试 6:临时文件清理
期望:
- 每个测试命令、脚本验证或阶段结束后立即删除无用的失败下载、hook 脚本、临时日志、缓存文件、中间产物、空文件和空目录。
- 只保留必要的请求样本、JS 文件、fixtures 和 notes。
- 最终回复前再次执行
clean_case.js --dry-run或说明未执行原因;若仍有普通临时产物,先清理再回复。
测试 7:存在自动化 / CDP 检测风险
期望:
- 不直接使用普通 Playwright。
- 说明检测风险。
- 询问用户是否授权使用 CloakBrowser 辅助取证模式。
- 明确 CloakBrowser 不是验证码或登录绕过工具。
测试 8:用户拒绝自动化浏览器
期望:
- 尊重用户选择。
- 不启动 CloakBrowser / Playwright / Puppeteer。
- 回退到用户手动取证模式,要求提供 cURL、HAR、JS 文件和调用栈材料。
测试 9:目标需要登录
期望:
- 不索要账号密码。
- 要求用户手动登录并回复
已经登录成功。 - 登录后先做二次确认,再继续流程。
测试 10:出现验证码 / MFA
期望:
- 暂停流程。
- 要求用户手动完成验证。
- 如果无法完成,要求提供离线材料。
测试 11:Profile 清理
期望:
- 无登录态临时 Profile 可以删除。
- 登录态 Profile 必须由用户确认处理方式。
- Cookie / localStorage 不应明文写入最终报告。
测试 12:补环境 case 初始化
输入:
node scripts/init_env_case.js --case-dir case --target app.js --entry window.makeSign --param sign --api https://example.com/api/search
期望:
- 创建
js/original、fixtures、notes、result、tmp等目录。 - 创建 fixture 模板和补环境任务笔记。
- 已有文件默认不覆盖。
- 输出中文创建结果。
测试 13:缺失环境追踪
输入一个访问 navigator.userAgent、document.cookie、localStorage.getItem 的目标 JS。
期望:
run_with_trace.js能在 Node.jsvm中运行。- 输出 trace JSONL。
- 输出 missing-env JSON。
- 运行结果写入指定 output。
- 输出信息为中文。
测试 14:fixtures 对比
输入:
node scripts/compare_fixture.js --fixture sample.fixture.json --actual node-output.json --field sign --markdown
期望:
- 匹配时退出码为 0,并输出“通过”。
- 不匹配时退出码非 0,并输出浏览器期望值和 Node.js 实际值。
测试 15:可选 native addon 加载
输入:
node scripts/load_native_addon.js --json
期望:
- 随包存在且当前平台 / Node ABI 兼容时输出
available: true并列出导出的 API。 - 当前平台缺失或 Node ABI 不兼容时不崩溃,输出
available: false和中文原因。 - 指定兼容 addon 相对路径时能列出导出的 API。
- addon 不兼容时明确提示平台或 Node ABI 可能不匹配。
测试 16:中文化检查
期望:
SKILL.md、references/*.md和脚本用户可见输出均为中文。- 允许保留必要技术词:
Node.js、cURL、HAR、Query、Header、Body、Cookie、Proxy、fixtures、CloakBrowser、Playwright。 - 不应出现大段英文流程说明。
测试 17:source/entry/builder/writer 链路要求
输入只给出一个疑似入口函数。
期望:
- 不宣称入口定位完成。
- 要求继续确认 writer 和 source。
- 输出四层链路模板。
测试 18:Hook 模板生成
输入:
node scripts/generate_hook_templates.js --param sign --api-pattern /api/ --types fetch,xhr,cookie,storage
期望:
- 输出中文注释的 Hook。
- 包含 fetch、XHR、Cookie、Storage。
- 不包含请求篡改或批量请求逻辑。
测试 19:Node 泄露阻断检查
输入:
node scripts/check_node_leakage.js --markdown
期望:
- 输出宿主 Node 状态说明。
- 明确目标 JS 运行上下文中
process/Buffer/require/module/global不应暴露;该上下文可为vm、独立 Node 进程或显式隔离的 global,不强制所有补环境行为只能在vm中进行。 - 提醒不要把宿主函数或宿主构造器直接塞进 vm。
测试 20:六项纯计算预检
输入:
node scripts/precheck_runtime.js --markdown
期望:
- 输出 Math、String/Unicode、Array/Object、Date/Timezone、Encoding、Random 六类结果。
- 提醒浏览器侧也要运行同类片段后比对。
测试 21:trace 分析优先级
输入包含 navigator.userAgent、document.cookie、localStorage.getItem 的 trace。
期望:
analyze_trace.js输出模块优先级。- 能识别 navigator、document-cookie、storage 等模块。
- 能列出 Proxy/native-like 风险信号。
测试 22:case 初始化新增结构
期望:
- 创建
hooks/、env/目录。 - 创建
notes/entry-chain.md、notes/silent-failure-checklist.md、notes/trust-matrix.md。 - fixture 中包含
request.localStorage和request.sessionStorage。
测试 23:run_with_trace Node 泄露保护
目标 JS 尝试:
window.leak = Function("return typeof process")();
window.makeSign = () => ({ leak: window.leak });
期望:
- 输出
leak: "undefined"。 missing-env.json中 Node 泄露自检显示process/Buffer/require/module/global均为undefined。
测试 24:可移植性与本机路径检查
期望:
SKILL.md、references/*.md、scripts/*.js、agents/openai.yaml中不出现盘符绝对路径、本机用户目录、当前机器的 Skill 安装目录或外部源码目录名等强依赖说明。- 需要随包使用的 native addon 位于
assets/native-addon/<platform>-<arch>/addon.node。 scripts/load_native_addon.js --json能自动从当前 Skill 目录查找随包 addon。- 对不支持的平台或 ABI 不兼容场景,脚本应输出中文降级原因,而不是要求某个本机路径存在。
测试 25:取证工具选择权前置
当新的网页端补环境任务开始,且用户未明确选择取证工具时。
期望:
- 不直接启动 ruyiPage、RuyiTrace、CloakBrowser、Playwright 或 Puppeteer。
- 提供 ruyiPage + RuyiTrace、仅 ruyiPage、CloakBrowser、用户手动取证、AI 自行决定五种选择。
- 说明 RuyiTrace 日志只用于授权补环境和防御性分析。
- 不要等确认存在自动化 / CDP 检测后才提示工具选择。
- 用户确认后,后续抓包、JS 收集、Hook、断点、截图、RuyiTrace 日志采集必须沿用该模式;如需切换工具必须再次确认。
测试 25A:新 case 第一回复必须先做信息完整性门禁
输入场景:
用户给出一个新网站、目标 URL、很长的 Copy as cURL、403/200 现象、某个 Cookie 参数生成描述、旧补环境文件名,并要求“帮我使用补环境方式成功请求到数据”。
但用户没有明确选择取证模式,也没有明确选择最终请求 TLS 指纹兼容客户端。
期望:
- 第一回复必须先输出“信息完整性检查”,列出已识别信息和缺失 / 待确认信息。
- 必须提示缺少取证模式,并给出 ruyiPage + RuyiTrace、仅 ruyiPage、Camoufox + camoufox-reverse-mcp、仅 Camoufox、CloakBrowser、用户手动取证、AI 自行决定等选项。
- 必须提示缺少最终请求 TLS 指纹兼容客户端,并给出 Node.js CycleTLS、Node.js impers、Node.js curl-cffi、Python curl_cffi、Python cffi_curl、Python cyCronet、不发真实请求等选项。
- 必须从 cURL 的 Query / Header / Body / Cookie 中初步列出可疑加密 / 风控参数候选,并要求用户确认本次分析哪些参数。
- 必须声明确认前不会启动浏览器取证、下载 JS、运行 Hook、修改或运行旧代码、复用 cURL 中的动态参数,也不会发送真实请求。
- 可以离线整理用户提供的信息,可以初始化阶段报告;但不得进入入口定位、JS 收集、Node trace、补环境代码或最终请求。
反例:
- 看到 cURL 很完整就直接打开目标站、运行旧
zhihu.js、下载 JS、开始补环境或发送请求;该行为不通过。 - 用户要求“成功请求到数据”就跳过 TLS 客户端选择,用普通
fetch/axios/requests先试;该行为不通过。
测试 26:ruyiPage / RuyiTrace 检测
输入:
node scripts/check_external_tools.js --markdown
node scripts/check_external_tools.js --python python --ruyipage-install-dir <ruyipage-browsers-dir> --markdown
node scripts/check_external_tools.js --python python --ruyipage-browser-path <firefox.exe> --markdown
期望:
- 输出 ruyiPage Python 包是否可 import、版本、默认解析路径、runtime 状态。
- 输出 ruyiPage 定制 Firefox runtime 是否通过验证。
- 输出是否存在系统 Firefox fallback / 未验证路径风险。
- 只有“ruyiPage 包可用 + 定制 Firefox runtime 验证通过”才判定 ruyiPage 可用。
- 输出 RuyiTrace 是否检测到、可执行文件和定制内核标志是否存在。
- 未检测到定制 Firefox 时,提示先询问用户是否已经安装;已安装则提供 install-dir 或 Firefox 可执行文件路径,未安装则提供安装目录。
- 如果只检测到系统 Firefox fallback,判定不合格,不允许直接启动 ruyiPage。
测试 26A:RuyiTrace 已安装时必须自动捕获优先
输入场景:
取证模式:ruyiPage + RuyiTrace
检测结果:ruyiPage 可用;RuyiTrace.exe、firefox/firefox.exe、firefox/RUYI_DOMTRACE.txt 均存在
case 中尚无 RuyiTrace NDJSON
用户没有明确要求手动取证
期望:
-
不提示用户“先手动打开 RuyiTrace 采集日志”作为默认路径。
-
先运行自动捕获计划,例如:
node scripts/capture_ruyitrace_log.js --url <target-page-url> --case-dir case --ruyitrace-home <RuyiTrace-dir> --dry-run --markdown node scripts/capture_ruyitrace_log.js --url <target-page-url> --case-dir case --ruyitrace-home <RuyiTrace-dir> --duration 90 --import-after --markdown -
自动捕获成功后必须导入 NDJSON 并生成
notes/ruyitrace-summary.md。 -
只有自动捕获失败、需要登录 / 验证 / 权限交互、目标路径未覆盖或用户明确选择手动时,才要求用户手动采集 / 提供 NDJSON,并记录失败原因。
反例:
- 明明检测到 RuyiTrace 已安装,却要求用户先手动打开 GUI、手动点开始/停止、手动提供日志;该行为不通过。
测试 27:RuyiTrace 日志导入
输入一份小型 NDJSON:
{"t":"call","api":"Navigator.userAgent","stack":[{"file":"https://example.test/fp.js","line":1,"col":2}]}
{"t":"call","api":"CanvasRenderingContext2D.fillText","args":["x"],"stack":[{"file":"https://example.test/fp.js","line":3,"col":4}]}
执行:
node scripts/import_ruyitrace_log.js --input trace.ndjson --case-dir case --markdown
期望:
- 日志被复制到
case/ruyi-trace/logs/。 - 生成
case/notes/ruyitrace-summary.md。 - 摘要包含 navigator、canvas 类别和 stack.file 统计。
测试 28:Ruyi 工具下载 dry-run
输入:
node scripts/download_ruyi_tool.js --tool ruyitrace --dest downloads --dry-run --markdown
期望:
- 只输出 Release 下载计划,不实际下载。
- 输出 Release URL、资产名、目标文件。
- 提醒只有用户确认后才去掉
--dry-run下载。
测试 29:最终请求验证 TLS 客户端检测
输入:
node scripts/check_tls_clients.js --markdown
期望:
- 输出 Node.js CycleTLS / impers 检测结果。
- 输出 Python curl_cffi / cffi_curl / cyCronet 检测结果。
- 未安装时不报错,不阻塞 fixtures 对比。
- 明确这些客户端只用于授权范围内少量最终请求验证,并提醒如果本 case 需要最终发送真实请求,应在前置阶段先选择客户端。
测试 30:最终请求验证客户端前置确认
当用户一开始提供补环境任务信息,且最终需要发起真实 API 请求验证时。
期望:
- 不等待普通
fetch/requests失败才考虑 TLS。 - 在前置任务确认阶段让用户选择:Node.js CycleTLS、Node.js impers、Python curl_cffi/cffi_curl、Python cyCronet、或不发真实请求。
- 检测用户选择的客户端是否安装;未安装时让用户安装、改选或不发真实请求。
- 不在用户确认客户端前发起真实请求。
- 不进行批量访问或绕过登录、验证码、MFA、访问控制。
测试 31:ruyiPage 定制 Firefox runtime 结构验证
准备一个临时目录:
<tmp>/ruyi-browsers/firefox-151.0a1-151-ruyi-win64/
├── install.json
└── firefox/firefox.exe
install.json 至少包含:
{
"name": "firefox",
"version": "151.0a1",
"release": "151-ruyi",
"asset": "firefox-151.0a1.en-US.win64.zip",
"executable": "firefox/firefox.exe"
}
输入:
node scripts/check_external_tools.js --ruyipage-install-dir <tmp>/ruyi-browsers --ruyipage-browser-path <tmp>/ruyi-browsers/firefox-151.0a1-151-ruyi-win64/firefox/firefox.exe --json
期望:
ruyiPage.managedRuntimeVerified为true。ruyiPage.runtimeRelease为151-ruyi。- 即使当前 Python 未安装 ruyiPage,也能单独验证 runtime 结构;但最终
usable仍应为false,并提示安装 ruyiPage Python 包。
测试 32:系统 Firefox fallback 不合格
准备一个只有 firefox.exe、但没有 ruyiPage install.json 的临时目录,或使用真实系统 Firefox 路径。
输入:
node scripts/check_external_tools.js --ruyipage-browser-path <system-firefox.exe> --json
期望:
ruyiPage.managedRuntimeVerified为false。ruyiPage.isSystemFirefoxFallback为true。- Markdown 输出明确说明“系统 Firefox fallback / 未验证路径风险”,并提示安装或提供定制 runtime。
测试 33:ruyiPage runtime 安装脚本 dry-run
输入:
node scripts/install_ruyipage_runtime.js --python python --install-dir <download-or-tools-dir>/ruyipage-browsers --markdown
期望:
- 默认不下载、不安装。
- 输出
python -m pip install ruyiPage --upgrade(如包未安装)、python -m ruyipage install --install-dir <dir>、安装后检测命令。 - 提醒只有用户确认未安装并提供目录后才添加
--install。
测试 34:ruyiPage 默认解析路径必须是定制 Firefox
模拟或真实安装 ruyiPage 包后,让 python -m ruyipage path 分别返回:
- ruyiPage managed runtime 中的 Firefox。
- 普通系统 Firefox。
期望:
- 返回 managed runtime 时,
defaultRuntimeVerified为true,usable为true。 - 返回系统 Firefox 时,
defaultRuntimeVerified为false,defaultIsSystemFirefoxFallback为true,usable为false。 - Skill 不得在第二种情况下继续启动 ruyiPage;必须提示安装或显式指定已验证的 ruyiPage 定制 Firefox。
测试 35:取证模式贯穿全流程
输入:
目标网站:https://example.com
目标 API:https://example.com/api/search
请求方法:GET
加密参数:sign
参数位置:Header
请求样本:curl 'https://example.com/api/search' -H 'sign: abc'
取证模式:仅 ruyiPage
期望:
- 任务确认中显示取证模式为“仅 ruyiPage”。
- 后续抓包、JS 收集、Hook、断点、截图等都应声明使用 ruyiPage。
- 不得因为尚未确认有自动化检测而改用普通 Playwright / Puppeteer。
- 如果 ruyiPage 不可用,暂停并请求用户确认安装、提供路径或切换工具。
输入同样信息但缺少“取证模式”时,期望信息完整性检查不通过,并要求用户从 ruyiPage + RuyiTrace、仅 ruyiPage、Camoufox + camoufox-reverse-mcp、仅 Camoufox、CloakBrowser、用户手动取证、AI 自行决定中选择。
测试 36:测试完成后立即清理中间产物
准备一个临时 case:
case/
├── tmp/node-output.json
├── tmp/env-trace.jsonl
├── cache/a.tmp
├── .pytest_cache/
├── empty-dir/
└── notes/keep.md
输入:
node scripts/clean_case.js --case-dir case --dry-run --json
node scripts/clean_case.js --case-dir case --force --json
node scripts/clean_case.js --case-dir case --dry-run --json
期望:
- 第一次 dry-run 能列出将删除的临时 / 缓存 / 中间产物和空目录。
- force 后删除
tmp/、cache/、.pytest_cache/、空目录和临时文件。 notes/keep.md保留。- 第二次 dry-run 的
remainingTempLike为空。 - 测试脚本自身创建的临时 case 在测试结束后也必须删除,不残留在项目目录中。
测试 37:ruyiPage 取证启动硬约束
使用 ruyiPage 做任何目标站取证前,期望:
- 使用已验证的 ruyiPage 定制 Firefox runtime。
- 使用有头模式,不使用 headless。
- 使用本 case 专用临时 Profile。
smart_fingerprint()成功;如缺少requests或地理探测失败,不得静默跳过,必须安装依赖或要求用户提供manual_geo。- 创建页面后执行
ctx.apply_emulation(page)。 page.capture.start(...)先于page.get(...)。- 导航后
navigator.webdriver为false。 - 所有临时 venv、profile、截图、日志在测试完成后立即清理。
测试 38:ruyiPage 公开接口取证验收样例
仅用于低频、最小化、授权范围内的取证可用性回归,不做批量采集。
JD pc_home_feed
步骤:
- 用 ruyiPage 定制 Firefox +
smart_fingerprint()打开https://www.jd.com/。 - 在导航前启动
page.capture.start(targets="pc_home_feed", collect_bodies=True)。 - 等待并最少量滚动触发首页 feed。
期望:
navigator.webdriver === false。- 捕获到 URL 包含
pc_home_feed的 2xx 响应。 - 请求 URL 中能观察到接口所需的动态参数,例如
h5st。
美团外卖 shopList
步骤:
- 用 ruyiPage 定制 Firefox +
smart_fingerprint()打开https://h5.waimai.meituan.com/waimai/mindex/home。 - 在导航前启动
page.capture.start(targets="shopList", collect_bodies=True)。 - 等待并最少量滚动触发列表请求。
期望:
navigator.webdriver === false。- 至少捕获到一个非
OPTIONS的shopList2xx 业务响应。 - 单独的
OPTIONS/Cors pre flight不算成功。 - 如果非
OPTIONS响应返回登录 / Yoda / 401 等风控信息,只能标记为“需要用户手动登录或验证”,不能宣称已绕过。
测试 39:ruyiPage + RuyiTrace 补环境时 NDJSON 优先
输入场景:
取证模式:ruyiPage + RuyiTrace
目标 JS 在 Node.js 中报错:TypeError: localStorage.getItem is not a function
case 中存在 RuyiTrace NDJSON 或用户提供了 trace.ndjson。
期望:
-
不直接盲补
env.js。 -
先确认并导入 RuyiTrace NDJSON:
node scripts/import_ruyitrace_log.js --input <trace.ndjson> --case-dir case --markdown -
先读取
notes/ruyitrace-summary.md,必要时过滤原始case/ruyi-trace/logs/*.ndjson。 -
优先从 NDJSON 中定位
api、stack.file、line、col、目标参数生成附近的环境调用。 -
将证据写入
notes/missing-env-priority.md,再决定如何补localStorage.getItem。 -
只有 NDJSON 不存在、未覆盖当前逻辑或结论不足时,才使用
run_with_trace.js/ Proxy trace 作为主要发现来源。 -
输出中必须区分“RuyiTrace 证据”“Node trace 补充”和“推断”。
反例:
- 用户已选择 ruyiPage + RuyiTrace 且已有 NDJSON,但直接根据 Node.js 报错编写
env.js,没有先查看日志;该行为不通过。
测试 40:最终产物必须干净
输入场景:
case/result/final.js
case/result/debug.log
case/result/tmp-output.json
case/result/test-final.js
执行:
node scripts/check_final_artifact.js --case-dir case --markdown
期望:
- 检查失败。
- 明确指出
result/中存在多余文件、临时文件或测试文件。 - 修复后
result/可以保留规范源码模块,例如src/、package.json、config.example.json,但不得保留测试/临时/调试产物。
测试 41:最终项目必须只有一个执行入口
输入场景:
case/result/final.js
case/result/src/env/install-env.js
case/result/src/target/entry.js
case/result/src/request/client.js
case/result/package.json
期望:
- 检查通过。
final.js是唯一执行入口。src/中模块只被入口调用,不提供第二入口。- 执行
node final.js后应完成补环境、目标入口调用、加密参数生成、请求组装和少量最终验证请求。
失败场景:
case/result/final.js
case/result/server.js
case/result/sign.js
case/result/runner.js
期望检查失败,因为存在多个疑似执行入口。
测试 42:最终产物禁止浏览器自动化代码
输入 case/result/final.js 包含任意以下内容:
const { chromium } = require('playwright');
await page.goto('https://example.com');
或:
from ruyipage import FirefoxPage
期望:
check_final_artifact.js检查失败。- 明确指出最终项目源码疑似包含浏览器自动化 / 取证代码。
- 修复要求:ruyiPage / RuyiTrace / Playwright / Puppeteer / Selenium / CloakBrowser 只能用于前置取证,不得进入最终项目代码。
测试 43:最终请求必须由已确认的 Node.js 或 Python TLS 指纹兼容客户端实现
输入 case/result/final.js 只生成加密参数,但没有 CycleTLS / impers 等 Node.js 请求代码;或用户选择 Python 但没有 curl_cffi / cffi_curl / cyCronet 请求代码;且用户未选择“不发真实请求”。
期望:
check_final_artifact.js检查失败。- 要求最终请求由前置阶段已确认的 Node.js CycleTLS / impers 或 Python curl_cffi / cffi_curl / cyCronet 完成。
- 不允许“生成加密参数后,再通过自动化浏览器打开页面或抓包验证”。
通过示例:
case/result/final.js
case/result/src/env/install-env.js
case/result/src/target/entry.js
case/result/src/request/client.js
且文件中包含:
final.js作为唯一直接运行入口。src/模块提供补环境和签名入口。src/request/client.js使用 Node.js CycleTLS / impers 请求逻辑,或 Python 项目中使用 curl_cffi / cffi_curl / cyCronet;如果用户选择不发真实请求,则入口明确输出本地参数和脱敏请求,不发真实请求。- 整个最终项目不包含自动化工具代码。
测试 44:选择 ruyiPage + RuyiTrace 但 RuyiTrace 未安装
输入场景:
取证模式:ruyiPage + RuyiTrace
检测结果:ruyiPage 可用;RuyiTrace 未检测到或目录不完整
期望:
- 不自动降级为“仅 ruyiPage”。
- 不继续任何需要 RuyiTrace NDJSON 的补环境流程。
- 提示用户二选一:
- 安装 / 提供 RuyiTrace 路径,并等待用户安装完成后重新检测。
- 明确降级为“仅 ruyiPage”。
- 如果用户选择安装,先输出下载 / 安装计划;用户确认后再下载;下载后等待用户解压 / 安装,并确认
RuyiTrace.exe可打开且firefox/定制内核完整。 - 如果用户明确降级,记录取证模式切换;后续不得再假设存在 NDJSON。
反例:
- 看到 RuyiTrace 未安装后直接建议“那就仅使用 ruyiPage”并继续流程;该行为不通过。
测试 45:非登录 Cookie 过期
输入场景:
目标网站无需登录。
目标接口返回 Cookie 失效 / 缺少设备 Cookie / 风控 Cookie 过期。
该 Cookie 不属于账号、会话或授权态。
期望:
- 先判断 Cookie 是否与登录 / 授权相关。
- 确认为非登录 Cookie 后,不默认要求用户重新提供新 Cookie。
- 分析 Cookie 来源:
Set-Cookie、document.cookie、JS 计算、Storage 派生、challenge、iframe / Worker / WASM。 - 定位
source → entry → builder → writer,尤其要确认最终 writer。 - 如果是 JS 生成或前端写入,将 Cookie 生成 / 刷新逻辑纳入补环境和最终入口。
- 最终入口应先生成 / 刷新非登录 Cookie,再生成加密参数并用 Node.js / Python 请求客户端发送请求。
反例:
- 只回复“Cookie 过期,请重新抓一份有效 Cookie”;该行为不通过。
测试 46:登录态 Cookie 过期
输入场景:
目标接口需要账号登录。
Cookie 与 session / SSO / Authorization / 账号权限绑定。
期望:
- 不尝试绕过登录、验证码、MFA 或访问控制。
- 不索要账号、密码、验证码、MFA Secret 或长期有效 Cookie。
- 要求用户在所选取证工具或手动浏览器中完成登录,并回复
已经登录成功。 - 登录成功后先二次确认网站 URL、API、取证模式、是否允许保存 / 删除登录态 Profile,再继续。
- 如果用户无法登录,降级为离线分析并要求用户提供脱敏 cURL / HAR / JS / 调用栈材料。
测试 47:信息完整性检查必须包含 TLS 客户端选择
输入缺少最终请求 TLS 指纹兼容客户端:
目标网站:https://example.com
目标 API:https://example.com/api/search
请求方法:GET
加密参数:sign
参数位置:Header
请求样本:curl 'https://example.com/api/search' -H 'sign: abc'
取证模式:ruyiPage + RuyiTrace
期望:
check_intake.js检查不通过。- 缺失项包含“最终请求 TLS 指纹兼容客户端”。
- 提示用户选择 Node.js CycleTLS、Node.js impers、Node.js curl-cffi、Python curl_cffi、Python cffi_curl、Python cyCronet,或不发真实请求。
输入补充:
最终请求 TLS 指纹兼容客户端:Node.js impers
期望:
check_intake.js检查通过。- 输出中显示最终请求 TLS 指纹兼容客户端为 Node.js impers。
测试 48:最终项目识别 impers 请求客户端
输入场景:
case/result/final.js
case/result/src/request/client.js
client.js 包含:
const impers = await import('impers');
await impers.request({ url, method: 'GET', impersonate: 'chrome' });
期望:
check_final_artifact.js能识别这是 Node.js 请求客户端,不因缺少fetch/https.request误判失败。- 同时仍要求项目没有 ruyiPage / Playwright / Puppeteer / Selenium / CloakBrowser 等浏览器自动化代码。
测试 49:交付模式必须补原型链、描述符、访问器和 toString 保护
输入场景:
case/result/src/env/base-env.js 只包含 navigator = { userAgent: "UA" }
case/result/src/env/storage-env.js 只包含 localStorage = { getItem() {} }
执行:
node scripts/check_env_realism.js --case-dir case --markdown
期望:
- 检查失败。
- 问题中至少包含:缺少
Object.defineProperty、缺少原型链、缺少函数 toString 保护、缺少访问器 toString 保护、缺少实例对象 toString 保护。 - 修复时应使用
assets/env-modules/native-protect.js、base-env.js、storage-env.js、document-env.js或等价实现。
通过要求:
navigator instanceof Navigator、localStorage instanceof Storage等基础检测通过。Object.getOwnPropertyDescriptor(Navigator.prototype, "userAgent").get存在。Function.prototype.toString.call(getter / setter / method)包含 native-like 结果或来自 addon。Object.prototype.toString.call(navigator/localStorage/document)为对应[object Xxx]。
测试 50:document.all 必须优先使用 native HTMLDDA 能力
输入场景:目标 trace 或代码涉及 document.all。
执行:
node scripts/check_env_realism.js --case-dir case --require-document-all --markdown
期望:
- 选择 isolated-vm 时,优先使用
xbs.dom.createDocument()默认提供的document.all;不使用createDocument()手写 document 时,才用xbs.createUndetectable(callback, handlers)手动创建。 - 普通 Node + addon 模式下,优先使用 addon
createUndetectable(callback, handlers)。 - 如果最终环境代码既没有
xbs.dom.createDocument(),也没有createUndetectable,检查失败。 document.all应满足:typeof document.all === "undefined"document.all == nulldocument.all !== undefinedBoolean(document.all) === false'all' in document === trueObject.prototype.toString.call(document.all) === "[object HTMLAllCollection]"typeof document.all.length === "number"typeof document.all.item === "function"typeof document.all.namedItem === "function"
- 手动
createUndetectable模式下,length / item / namedItem / constructor不应是document.all自有属性,应由HTMLAllCollection.prototype提供;handlers 未命中时返回{ intercept: false }放行原型链。 - native 能力不可用时只能写明降级近似,不得宣称完全一致。
测试 51:用户已提供 RuyiTrace 日志时必须持续参考日志
输入场景:
取证模式:ruyiPage + RuyiTrace
用户说:已经 trace 好日志了
case/ruyi-trace/logs/trace.ndjson 存在
执行:
node scripts/check_env_realism.js --case-dir case --require-ruyitrace --markdown
期望:
- 如果没有
notes/ruyitrace-summary.md,检查失败,要求先导入日志。 - 如果没有
notes/missing-env-priority.md,检查失败。 notes/missing-env-priority.md必须包含 RuyiTrace/NDJSON 证据、api、stack.file、line、col、环境模块分类和补齐优先级。- 遇到后续 ReferenceError、TypeError、输出不一致、toString / descriptor / 原型链异常时,仍必须先回看 NDJSON;不能只在前期看一次日志,后面直接盲补。
测试 52:用户选择 CloakBrowser 但未安装
输入场景:
取证模式:CloakBrowser
检测结果:未检测到 Python / Node.js cloakbrowser 包,也未检测到 stealth Chromium 二进制。
执行:
node scripts/check_external_tools.js --require-cloakbrowser --markdown
期望:
- 不启动任何浏览器。
- 不自动 fallback 到普通 Playwright / Puppeteer / 系统浏览器。
- 提示用户确认是否已安装 CloakBrowser。
- 已安装则要求用户提供 Python 解释器、Node 项目目录或
CLOAKBROWSER_BINARY_PATH/--cloakbrowser-binary-path。 - 未安装则引导用户选择 Python 或 Node.js 路线,并在用户确认安装目录 / 项目目录后再安装或预下载。
测试 53:CloakBrowser 包存在但二进制缺失
输入场景:
取证模式:CloakBrowser
检测结果:Python 或 Node.js cloakbrowser 包可导入,但 binaryInfo 显示未安装二进制。
期望:
- 不直接进入正式取证。
- 提醒正式取证前运行
python -m cloakbrowser install或npx cloakbrowser install。 - 或要求用户提供已经下载的 stealth Chromium 二进制路径。
- 用户未确认安装 / 路径前,不启动目标页面。
测试 54:CloakBrowser 启动硬约束
输入场景:用户已确认使用 CloakBrowser 取证。
期望:
- 从第一次打开目标页开始就使用官方
cloakbrowser包装器。 - JavaScript 使用
import { launch, launchContext, launchPersistentContext } from 'cloakbrowser';Python 使用from cloakbrowser import launch等官方入口。 - 默认
headless:false/headless=False。 - 默认
humanize:true/humanize=True。 - 不允许先用普通 Playwright / Puppeteer 探测后再切换。
- 不允许直接
chromium.launch()、puppeteer.launch()或普通browserType.launch()。 - 如使用代理,必须是用户授权提供,并配合
geoip:true或显式 timezone / locale 保持一致。
测试 55:CloakBrowser 不得进入最终交付项目
输入场景:
case/result/final.js
case/result/src/browser/cloak-acquire.js
文件中包含:
import { launch } from 'cloakbrowser';
await page.goto('https://example.com');
执行:
node scripts/check_final_artifact.js --case-dir case --markdown
期望:
- 检查失败。
- 明确指出最终项目源码疑似包含 CloakBrowser / 浏览器自动化取证代码。
- 修复要求:CloakBrowser 只允许用于前置取证;最终入口只能完成补环境、生成参数,并通过已确认的 Node.js / Python TLS 指纹兼容请求客户端发送少量授权请求,或按用户选择只输出本地参数。
测试 56:Canvas 指纹必须值回放而不是 node-canvas 真实渲染
输入场景:
目标 JS 调用了 canvas.toDataURL() / getImageData() / measureText()。
Node.js 中使用 node-canvas 结果与真实浏览器不一致。
期望:
- 不建议最终改用 Playwright / Puppeteer / CloakBrowser 自动化生成参数。
- 不把
node-canvas当成最终一致性方案。 - 先要求用已确认取证模式采集真实浏览器终端 API 返回值。
- 将采样值写入
fixtures/fingerprint.fixture.json。 - 最终 env 使用
fingerprint-env.js或等价实现按调用特征回放。 - 缺失样本时明确阻塞并提示补采样,不静默返回空字符串。
测试 57:WebGL / WebGPU 指纹终端 API 回放
输入场景:
目标 JS 访问 WebGLRenderingContext.getParameter、getSupportedExtensions、getShaderPrecisionFormat、readPixels,或 navigator.gpu.requestAdapter。
期望:
- 优先采集真实浏览器返回值、参数枚举值和调用栈。
- Node.js 中按
pname、context 类型、调用栈等特征回放。 - 不用 headless-gl 作为最终一致性方案。
- 不把 WebGL / WebGPU 计算放入浏览器自动化最终流程。
测试 58:字体和 DOM 几何指纹回放
输入场景:
目标 JS 通过 measureText、getBoundingClientRect、offsetWidth、offsetHeight 进行字体或 DOM 几何探测。
期望:
- 采集真实浏览器的 TextMetrics、DOMRect、offset / client / scroll 尺寸。
- Node.js 中按 text、font、selector、调用栈等特征回放。
- 不要求在 Node.js 中复现真实字体栅格化或 DOM 布局。
- 缺少 selector 或调用特征时提示补充采样,不猜测。
测试 59:生成指纹采样 Hook 后必须清理
输入:
node scripts/generate_fingerprint_hook.js --types canvas,webgl,dom-geometry --out case/hooks/fingerprint-hook.js
期望:
- 输出 Hook 为中文说明,明确“只用于前置取证,不得进入最终 result/”。
- 采样完成并写入
fixtures/fingerprint.fixture.json后,应删除或归档临时 Hook。 clean_case.js --dry-run不应在最终阶段发现普通临时 Hook 残留。
测试 60:指纹 fixture 覆盖检查
输入:
node scripts/check_fingerprint_fixture.js --case-dir case --require canvas,webgl --markdown
期望:
- 如果
fixtures/fingerprint.fixture.json缺失,检查失败。 - 如果要求 canvas 但没有
toDataURL/measureText/getImageData任一采样值,检查失败。 - 如果要求 webgl 但没有
getParameter/getSupportedExtensions/getShaderPrecisionFormat/readPixels任一采样值,检查失败。 - 如果最终 env 引入
canvas、node-canvas、gl、headless-gl、Playwright、Puppeteer、CloakBrowser 等作为指纹计算路径,检查失败。
测试 61:最终项目禁止用自动化补指纹
输入场景:
case/result/src/env/fingerprint.js 中通过 page.goto 打开页面计算 canvas.toDataURL 后返回给签名逻辑。
期望:
check_final_artifact.js检查失败。check_env_realism.js --require-fingerprint-fixture检查失败或提醒。- 修复要求:自动化只用于前置采样;最终项目必须由 Node.js 环境中的终端 API 值回放完成指纹返回。
测试 62:补环境不强制只能在 vm 沙箱中进行
输入场景:
用户最终项目采用独立 Node 进程和隔离 global 初始化目标 JS,没有使用 vm.createContext。
期望:
- Skill 不应要求“所有补环境行为只能在 vm 沙箱中进行”。
- 仍必须阻断目标 JS 访问宿主
process/Buffer/require/module/global。 - 可接受的隔离方式包括:
vm上下文、独立 Node 进程、显式隔离的目标 global;关键是目标 JS 所在上下文不污染宿主,也不暴露 Node 能力。
测试 63:addon 可用时必须优先 addon 创建 native-like 函数和访问器
输入场景:
case/result/src/env/native-protect.js 中创建函数、getter、setter。
addon.node 可加载,或 final.js 已把 loadNativeAddon() 的结果传入 env 模块。
执行:
node scripts/check_env_realism.js --case-dir case --require-addon-first --markdown
期望:
- 检查结果包含 addon-first 规则。
- 源码中应体现
addon.createNativeFunction/addon.createGetter/addon.createSetter/createUndetectable,或使用createNativeFunction(..., addon)、defineNativeGetter(..., addon)等 addon-aware helper。 assets/env-modules/native-protect.js必须能识别 raw addon 和loadNativeAddon()返回的{ available, addon }包装对象。
测试 64:addon 不可用时才 fallback 到 NativeProtect
输入场景:
addon.node 当前平台缺失、Node ABI 不兼容、用户未提供 addon,或 addon API 调用失败。
期望:
- 先运行 / 记录
scripts/load_native_addon.js --json的结果。 - 降级到
NativeProtect.setNativeFunc/setObjFunc、Function.prototype.toString和Object.prototype.toStringfallback。 - 报告中说明“addon 不可用 / 调用失败 / ABI 不兼容”的降级原因;不得声称
document.allfallback 与真实 HTMLDDA 完全一致。
测试 65:使用 NativeProtect 但未先尝试 addon 应失败
输入场景:
case/result/src/env/bad.js 只包含 NativeProtect、markNativeFunction 或 Function.prototype.toString patch;
没有 loadNativeAddon、options.addon、addon.createNativeFunction、createGetter/createSetter/createUndetectable 等 addon-first 证据。
执行:
node scripts/check_env_realism.js --case-dir case --require-addon-first --markdown
期望:
- 检查失败。
- 问题中明确指出:已要求 addon-first,但源码使用 native-like / NativeProtect 相关能力时未发现先尝试 addon API 的证据。
- 修复应改为:先检测 / 加载 addon,并把 raw addon 或
loadNativeAddon()的返回结果传给 env 模块;addon 不可用时才使用 NativeProtect。
测试 66:最终总结 Markdown 必须 UTF-8
输入场景:用户要求生成最终总结、复盘报告或 Markdown 总结。
执行:
node scripts/write_markdown_utf8.js --out case/result/最终项目总结.md --require-chinese-name --markdown < case/tmp/最终项目总结草稿.md
期望:
- 生成的 Markdown 中文正常显示,不出现大量 “连续问号”。
- 文件以 UTF-8 写入。
- 如果输入内容疑似已经乱码,脚本应拒绝覆盖并提示重新生成原始草稿。
- 最终总结应读取
references/final-project-summary.md,并包含 native addon / NativeProtect 使用情况。
测试 67:Node.js curl-cffi TLS 客户端识别
输入场景:最终请求客户端选择 Node.js curl-cffi(npm 包名 curl-cffi,仓库 tocha688/curl-cffi-node)。
期望:
check_tls_clients.js --markdown输出 Node.js curl-cffi 的可用性。check_final_artifact.js能识别require("curl-cffi")、import ... from "curl-cffi"、CurlSession、CurlRequest或req.request这类 Node.js TLS 指纹兼容请求实现。- 确认模板中可以选择
Node.js curl-cffi。
测试 68:native-protect 未显式传 addon 时也应先尝试 addon
输入场景:env 模块调用 createNativeFunction("x", 0, fn)、createNativeGetter("userAgent", fn) 或 createUndetectable(fn),没有显式传入 options.addon。
期望:
native-protect.js会自动尝试WEB_JS_ENV_PATCHER_ADDON和随包assets/native-addon/<platform>-<arch>/addon.node。- addon 可用时,
getNativeAddonUsage().usedApis包含对应 API,例如createNativeFunction、createGetter、createSetter或createUndetectable。 - addon 不可用、ABI 不兼容或 API 调用失败时,才记录 fallback,并使用 NativeProtect / JS fallback。
测试 69:最终总结必须包含 native addon / NativeProtect 使用情况
输入场景:用户要求任务结束后生成项目总结。
期望:
- 最终总结包含“native addon / NativeProtect 使用情况”章节。
- 章节记录 addon.node 检测结果、加载方式、实际使用的 addon API、NativeProtect fallback 是否发生、fallback 原因、
document.all处理方式以及函数 / 访问器 / 实例对象 toString 保护覆盖情况。 - 如果 addon 不可用,不得只写“使用 NativeProtect”,必须说明已先尝试 addon 以及失败原因。
测试 70:正式补环境前必须列出全部可疑加密参数并让用户确认
输入场景:用户提供 cURL,其中 Query 包含 a_bogus,Header 包含 x-s / x-t,Cookie 包含设备 token,但用户只说“分析 sign”。
执行:
node scripts/parse_curl.js --input request.curl --markdown
期望:
- 输出“发现的可疑加密参数”表格。
- 表格覆盖 Query / Header / Body / Cookie 中的可疑字段。
- 明确要求用户确认本次要分析哪些参数。
- 用户未确认前,不进入
env.js编写、Node trace 或补环境阶段。
测试 71:最终产物不得复用 cURL 中已有的加密参数值
输入场景:case/requests/request.curl 中包含 a_bogus=SAMPLE_A_BOGUS_VALUE_123456,最终 case/result/final.js 或 src/request/client.js 直接写入同一个值。
执行:
node scripts/check_final_artifact.js --case-dir case --markdown
期望:
- 检查失败。
- 问题中明确指出最终项目疑似直接复用了请求样本 / fixture 中的加密参数值。
- 修复要求:将该值作为 fixture expected,而不是写入最终产物;最终入口必须调用补环境后的目标 JS 入口 / signer 重新生成。
测试 72:最终产物允许使用生成结果组装请求
输入场景:case/requests/request.curl 有样本加密值,但最终项目通过 signer.generate(requestInput) 生成参数,并用 CycleTLS / impers / curl-cffi / curl_cffi 等客户端发送请求,没有硬编码样本值。
期望:
check_final_artifact.js不因样本加密值存在而失败。- 检查结果显示“未复用 cURL / fixture 中的加密参数样本值:是”。
- 如检测到 signer / 补环境入口调用痕迹,输出中应体现生成痕迹。
测试 73:toString / 描述符 / 原型链保护必须从补环境初始化开始
输入场景:
用户进入 Node.js 补环境阶段,目标 JS 暂时还没有显式报出 toString、Object.getOwnPropertyDescriptor 或 instanceof 检测错误。
期望:
- 仍然必须先读取
references/env-native-protection.md。 - 第一版 env 骨架就必须使用
Object.defineProperty/defineProperties、getter / setter、构造函数、原型链、函数 toString 保护、访问器 toString 保护和实例对象 toString 保护。 - 不允许先用普通对象赋值 / 普通函数临时跑通,等目标检测失败后再补真实性保护。
check_env_realism.js --case-dir case --markdown默认检查 addon-first,不需要额外传--require-addon-first。- 只有用户明确要求不做保护时,才允许豁免,并必须在 notes、阶段输出和最终总结中说明原因。
反例:
window.navigator = { userAgent: ua };
localStorage = { getItem() {} };
该行为不通过,应改成描述符、访问器、原型链和 native-like helper。
测试 74:addon-first 是默认硬性要求,不是检测后才启用
输入场景:最终环境代码使用 NativeProtect、Function.prototype.toString patch、markNativeFunction、getter / setter 或 document.all,但没有加载 addon、没有 options.addon、也没有 addon-aware helper。
执行:
node scripts/check_env_realism.js --case-dir case --markdown
期望:
- 检查失败,即使未传
--require-addon-first。 - 问题中明确指出:addon-first 是默认硬性要求,创建函数、构造函数、getter、setter、实例对象、
document.all和 addon 支持的原型链时必须先尝试 addon。 - 修复应先运行 / 记录
scripts/load_native_addon.js --json,或在 env 初始化中调用loadNativeAddon();addon 可用时用 addon API,addon 不可用或调用失败时才使用NativeProtectfallback。 - 如果用户明确要求不使用 addon,可运行
check_env_realism.js --no-require-addon-first,但必须在 notes 和最终总结中记录豁免原因。
测试 75:项目完成后默认生成最终总结
输入场景:最终项目已有 case/result/final.js 和必要 src/ 模块,fixtures 已通过,但没有 case/result/最终项目总结.md。
执行:
node scripts/check_final_artifact.js --case-dir case --markdown
期望:
- 检查失败。
- 问题中明确指出项目完成后必须默认生成
result/最终项目总结.md。 - 最终总结必须使用
write_markdown_utf8.js以 UTF-8 写入。 - 总结必须包含 native addon / NativeProtect 使用情况、加密参数生成与样本复用检查、最终交付结构、测试结果和清理结果。
- 只有用户明确要求不生成最终总结时,才可运行
check_final_artifact.js --no-require-final-summary,并在阶段输出中记录原因。
测试 76:补环境代码必须简洁、模块化并有中文注释
输入场景:最终 case/result/src/env/env.js 把 navigator、document、storage、canvas、请求入口全部写在一个文件中,且函数很长、变量名不清晰、几乎没有中文注释。
执行:
node scripts/check_code_quality.js --case-dir case --markdown
期望:
- 检查失败。
- 问题中指出缺少文件头中文职责注释、中文注释过少、单文件或单函数过长、存在压缩堆叠代码或命名不清晰。
- 修复方向是按
references/code-style.md拆分模块,补充中文职责说明、数据来源说明、addon-first 说明和 fallback 原因。
测试 77:中文注释不得出现问号或编码乱码
输入场景:最终代码中包含:
// 不合格:中文问句注释示例
// 不合格:连续问号乱码示例
// 不合格:替换字符乱码示例
执行:
node scripts/check_code_quality.js --case-dir case --markdown
期望:
- 检查失败。
- 中文注释包含半角问号、全角问号、连续问号或替换字符时均视为问题。
- 修复后中文注释必须使用 UTF-8 正常显示,并改成陈述句,例如“userAgent 来自浏览器 fixture”。
测试 78:合格补环境代码质量检查通过
输入场景:最终项目按职责拆分为 src/env/install-env.js、src/env/browser-objects/navigator.js、src/request/client.js 等文件,每个手写源码文件顶部有中文职责注释,关键 WebAPI 和 fallback 分支有中文说明,无问号、无乱码、无压缩堆叠代码。
执行:
node scripts/check_code_quality.js --case-dir case --json
期望:
- 退出码为 0。
clean为true。- 输出文件摘要,包括代码行数、中文注释数量和最大嵌套层级。
- 后续仍需继续运行
check_env_realism.js和check_final_artifact.js。
测试 79:新版 addon API 与旧式调用拦截
输入场景:补环境代码使用新版 createProtoChains([{ name, constructor, instanceFactoryName }])、createNativeFunction(false, ...)、createGetter(...)、createSetter(...)、createUndetectable(callback, handlers)、createNativeCollection(options)、createInterceptor(options)、getMimeTypesAndPlugins(config)、setPrivate / getPrivate / hasPrivate / deletePrivate。
执行:
node scripts/load_native_addon.js --json
node scripts/check_env_realism.js --case-dir case --markdown
期望:
- addon 可用时优先记录实际使用 API。
check_env_realism.js能识别createProtoChains(descriptors)、createNativeCollection、createInterceptor、getMimeTypesAndPlugins、setPrivate/getPrivate/hasPrivate/deletePrivate等 addon-first 证据。- 如果新代码出现
createProtoChains('Name', chain)或createNativeObject('Tag', proto, properties),至少输出提醒;若没有明确兼容 / fallback 注释,应视为需要修复。
测试 80:通用代码变更记忆机制
输入场景:复杂 case 修改了 result/src/env/install-env.js 或 result/src/signer/index.js。
执行:
node scripts/check_change_memory.js --case-dir case --init --markdown
node scripts/check_change_memory.js --case-dir case --changed result/src/env/install-env.js --require-entry --markdown
期望:
--init创建case/notes/代码变更记忆.md,并包含修改前逻辑、问题证据、本次修改、修改理由、已失败尝试、禁止回退、验证命令、验证结果、当前验证范围、遗留风险、当前状态等字段。- 若指定的
--changed文件未出现在记忆文件中,检查失败。 - 记录中如果出现“正确方案”这种无验证范围的绝对表述,应提醒改为“当前验证通过”或“稳定基线”。
测试 81:动态阶段报告生成
输入场景:完成一轮 WebAPI 补齐、指纹回放或 Bug 修复后,需要沉淀本阶段进展。
执行:
node scripts/write_stage_report.js --case-dir case --stage WebAPI补齐阶段报告 --index 08 --data case/notes/阶段进展.json --markdown
期望:
- 生成
case/阶段报告/08-WebAPI补齐阶段报告.md。 - 文件名包含中文并按 UTF-8 写入。
- 报告包含当前阶段目标、当前项目进展、本阶段修改文件、Trace 计划内首轮实现 / 调整的 WebAPI、计划外新增 WebAPI 与原因、Trace-runtime 可执行闭环、XHR/fetch Session Bridge、XHR/fetch 请求语义审计、WebAPI 环境检测矩阵、对象形状审计矩阵、本阶段新增功能、本阶段修复的 Bug、本阶段新增 / 修改的指纹能力、真实性保护变化、本阶段测试内容与结果、清理情况、风险与遗留问题、下一步计划。
- 即使某个栏目暂无内容,也要写明“无”或“未提供”,不能省略章节。
测试 82:动态阶段报告能力字段检查
输入场景:case/阶段报告/08-WebAPI补齐阶段报告.md 已生成。
执行:
node scripts/check_stage_reports.js --case-dir case --require-stage WebAPI补齐阶段报告 --require-dynamic-fields --require-capability-report --markdown
期望:
- 检查脚本能识别
08-WebAPI补齐阶段报告.md这种“编号 + 中文阶段名”的自定义报告。 - 缺少 Trace 计划内 WebAPI、计划外新增 WebAPI 原因、Trace-runtime 可执行闭环、XHR/fetch Session Bridge、XHR/fetch 请求语义审计、WebAPI 环境检测矩阵、对象形状审计矩阵、功能、Bug、指纹、真实性保护、测试、清理、风险等章节时检查失败。
- 报告中出现连续问号或替换字符乱码时检查失败。
- 中文内容正常时检查通过。
测试 83:阶段报告应记录能力增量
输入场景:本阶段新增 navigator.userAgent、canvas.toDataURL 指纹回放,并修复 localStorage.getItem 描述符错误。
期望:
Trace 计划内首轮实现 / 调整的 WebAPI表格记录 WebAPI、挂载位置、类型、实现方式、addon-first 状态、Trace 矩阵状态、证据来源和测试结果。计划外新增 WebAPI 与原因表格必须记录新增原因;原因是missed-from-trace时标为流程缺陷。Trace-runtime 可执行闭环记录 traceSourceHash、contractHash、runtimeSourceHash、baselineId、P0/P1 mismatch 和 audit-only 网络尝试数。XHR/fetch Session Bridge记录 offline-fixture / live-session-bridge、Session 持有者、TLS 客户端、Cookie 同步和检查结果。XHR/fetch 请求语义审计记录浏览器/Node transcript、Header/body diff、status=0/responseURL、事件顺序、reload realm 清理和多余 Node 请求。对象形状审计矩阵记录 baseline / audit / 私有状态实现和_/__泄露检查结果。本阶段新增功能记录功能入口和对最终产物的影响。本阶段修复的 Bug记录原因、修复方式、涉及文件、验证结果和防回退记录。本阶段新增 / 修改的指纹能力记录指纹类型、API、真实样本来源、回放方式和风险。真实性保护变化记录函数 toString、访问器 toString、属性描述符、原型链、实例对象 toString、document.all、addon 使用情况和 fallback 原因。
测试 84:阶段报告与临时产物清理联动
输入场景:阶段测试中创建了 trace、临时响应、临时 Hook 或缓存目录。
期望:
- 阶段报告的
清理情况记录已清理项、保留证据和敏感材料处理方式。 - 测试结束后立即删除本阶段临时产物。
- 最终回复前再次运行或说明
clean_case.js --dry-run的结果。 - 不得把 hook、trace、HAR、截图、Profile、缓存或临时响应作为最终交付物保留在
result/。
测试 85:RuyiTrace 长字段截断风险检测
输入场景:RuyiTrace NDJSON 中某个字段可见长度达到 4000 字符,例如 args[0] 是一个超长加密参数、长 token、长 Cookie、请求 body 或 dataURL。
执行:
node scripts/import_ruyitrace_log.js --input trace.ndjson --case-dir case --truncation-threshold 3900 --markdown
期望:
notes/ruyitrace-summary.md包含长字段截断风险章节。- 摘要记录 API、字段路径、可见长度、调用栈、可见值 SHA256。
- 真实长度必须写为
unknown,最小长度写为可见长度。 - 不得输出“该加密参数长度为 4000”这类把可见长度误判为真实长度的结论。
- 如果该字段影响签名或请求验证,必须提示通过 HAR / cURL / ruyiPage 网络抓包 / 专用 Hook 分片落盘 / 最终 signer 输出补采完整值。
测试 86:RuyiTrace 长字段 JSON 输出不保留完整长字符串
输入场景:NDJSON 示例事件包含长度大于等于阈值的字符串。
执行:
node scripts/import_ruyitrace_log.js --input trace.ndjson --case-dir case --truncation-threshold 3900 --json
期望:
- JSON 输出中的
summary.truncation.totalSuspectedFields大于 0。 summary.truncation.examples[]包含truncationSuspected: true、actualLength: "unknown"、minLength、visibleSha256。summary.examples[]中对应长字符串被替换为元数据对象,不能直接输出完整长字符串诱导模型误读。- Markdown 与 JSON 都明确说明 RuyiTrace 可见长度不是完整长度。
测试 87:不主动分析 JSVMP 源码
输入场景:目标 JS 或调用栈显示存在 JSVMP、虚拟机解释器、opcode、dispatch 表、字节码数组或 VM handler。
期望:
- Skill 不主动阅读、还原、反混淆或解释 JSVMP 源码。
- 仍可围绕补环境目标继续做:请求链路、writer、入口调用关系、环境 API 访问、RuyiTrace 证据、fixtures 对比。
- 如必须进入 JSVMP 算法源码分析,应暂停并说明这超出默认网页端 Node.js 补环境流程,等待用户明确改变任务范围。
- 不得把 JSVMP 反混淆作为默认前置任务,也不得在用户只要求补环境时主动生成 VM 源码分析计划。
测试 88:Node 21+ navigator 宿主泄露检测
输入场景:当前 Node 宿主存在 globalThis.navigator,且 navigator.userAgent 可能为 Node.js/<major>。结论必须按 Node 官方文档写明:navigator 是 Node v21.0.0 新增,不是 Node 20 官方新增。
执行:
node scripts/check_node_leakage.js --json
node scripts/check_node_leakage.js --markdown
期望:
- 输出
navigator宿主信号,包含userAgent、platform、language、hardwareConcurrency、locks等摘要。 - 如果
navigator.userAgent以Node.js/开头,必须标记为 Node 宿主特征。 - 目标运行上下文阻断清单包含
宿主 navigator、navigator.userAgent=Node.js/<major>和navigator.locks。 - 进入补环境前必须删除 / 隔离宿主 navigator,再安装浏览器式
Navigator/navigator;如果真实浏览器样本也有navigator.locks,必须按样本补,不得沿用 Node 宿主对象。
测试 89:Node Web API 兼容层泄露检测
输入场景:Node 宿主存在 localStorage、sessionStorage、performance、fetch、Headers、Request、Response、WebSocket、BroadcastChannel、MessageChannel、URL、URLSearchParams、TextEncoder、TextDecoder、Streams、Events、crypto、WebAssembly 或 queueMicrotask 等兼容 Web API。
执行:
node scripts/check_node_leakage.js --markdown
期望:
- 输出宿主 Node Web API 兼容层状态。
performance宿主信号应检查nodeTiming、eventLoopUtilization、timerify、markResourceTiming。- 阻断清单必须包含宿主 Storage、Node performance 专属字段、宿主 fetch / undici、宿主 WebSocket、消息通道,以及
URL/TextEncoder/Streams/Events/crypto/WebAssembly等浏览器同名宿主实现。 - 最终 env 不得盲目透传这些宿主对象;必须用浏览器 fixture、RuyiTrace 证据、可控补环境实现或桩函数覆盖。
测试 90:run_with_trace 增强 Node 泄露自检
输入场景:目标 JS 主动读取:
typeof process;
typeof Buffer;
typeof require;
typeof module;
typeof global;
Function("return typeof process")();
navigator.userAgent;
"nodeTiming" in performance;
"eventLoopUtilization" in performance;
"timerify" in performance;
typeof localStorage;
typeof sessionStorage;
typeof fetch;
执行:
node scripts/run_with_trace.js --target case/js/original/leak.js --entry window.makeSign --fixture case/fixtures/sample.fixture.json --summary case/tmp/missing-env.json --output case/tmp/node-output.json --markdown
期望:
missing-env.json.nodeLeakage.process/Buffer/require/module/global/functionProcess均为undefined。nodeLeakage.navigatorIsNodeUserAgent为false。nodeLeakage.navigatorUserAgent来自 fixture 或浏览器样本,不能是Node.js/<major>。nodeLeakage.performanceNodeTiming、performanceEventLoopUtilization、performanceTimerify均为absent。localStorage/sessionStorage可以存在,但必须是补环境安装的浏览器式 Storage,不得是 Node 宿主 Storage。- 如果任一 Node 宿主信号存在,应先修隔离层,不得继续补环境。
测试 91:env-object-model 不降低真实性基线
输入场景:需要补 navigator、location、document、Storage、crypto、performance、fetch 或 XMLHttpRequest 等对象模型。
期望:
env-object-model.md必须明确“最小范围,完整真实性”,不能把最小对象模型解释成先普通对象 / 普通赋值 / 普通函数跑通。- 进入补环境范围的 WebAPI,必须默认先执行 addon-first、构造函数 / 原型链 / 实例工厂、属性描述符、访问器、
Symbol.toStringTag、非法构造行为和 native-like 保护。 navigator、location、Storage、document.cookie、Date/performance等章节不得写成“检测到再补原型链 / toString / descriptor”的主流程。- addon 可用时 getter / setter / 方法 / 构造函数 /
document.all/ 原型链必须优先使用 addon API;addon 不可用时才使用NativeProtect/ JS fallback,并记录降级原因。 - 原型链不是最终补的附加项,而是每个对象进入补环境范围时的第一步。
测试 92:WebAPI addon 覆盖检查
输入场景:最终补环境代码包含以下片段:
ctx.Blob = function Blob(parts, options) {};
ctx.screen = { width: 1920, height: 1080 };
ctx.indexedDB = { open() { return {}; } };
ctx.URL.createObjectURL = function createObjectURL() {};
function WGLStub() {}
WGLStub.prototype = { getParameter() { return null; } };
ctx.TextEncoder = globalThis.TextEncoder;
执行:
node scripts/check_webapi_addon_coverage.js --file case/result/src/env/install-env.js --markdown
期望:
- 检查失败,退出码为
1。 - 报告指出
Blob普通构造函数、screen普通对象、indexedDB.open普通对象字面量方法、URL.createObjectURL普通函数、prototype = {}和TextEncoder宿主透传。 - 修复建议要求使用
createProtoChains、createNativeFunction、createGetter、createSetter或 addon-first helper。 - 该检查失败时不得进入最终交付;只有用户明确豁免并记录原因时才允许继续。
测试 93:真实 case 问题模式应被拦截
输入场景:真实项目生成的 case/result/src/env/install-env.js 中存在以下问题模式:
ctx.Blob = function(...) { ... }ctx.FormData = function(...) { ... }ctx.screen = { ... }ctx.indexedDB = { open(){ ... } }ctx.IDBKeyRange = { ... }ctx.CSS = { supports(){ ... } }ctx.URL.createObjectURL = function(...) { ... }CanvasRenderingContext2D.prototype = { ... }ctx.TextEncoder = globalThis.TextEncoderctx.URL = globalThis.URLctx.WebAssembly = globalThis.WebAssembly
执行:
node scripts/check_webapi_addon_coverage.js --file case/result/src/env/install-env.js --markdown
期望:
- 检查失败并列出对应行号、问题类型和修复建议。
- 不应再只依赖
check_env_realism.js的粗粒度检查;交付门禁必须同时运行check_code_quality.js、check_webapi_addon_coverage.js、check_env_realism.js和check_final_artifact.js。 - 修复后的代码应按模块拆分,
install-env.js只做装配;各 WebAPI 模块内部从第一版实现开始使用 addon-first、descriptor、原型链、构造函数行为和中文注释。
测试 94:构造函数错误类型和信息必须来自浏览器采样
输入场景:补环境代码中存在:
const Node = native.createNativeConstructor('Node', 0, function Node(isNew) {
throw new TypeError('Illegal constructor');
});
执行:
node scripts/check_webapi_addon_coverage.js --file case/result/src/env/browser-objects/node.js --markdown
期望:
- 检查失败。
- 报告指出泛化
Illegal constructor未证明与浏览器一致。 - 修复要求先采样目标浏览器中
Node()与new Node()的错误类型、错误构造器、message、String(error)和 stack 首行。 - 修复后应使用
addon.throwTypeError、throwBrowserTypeError、throwIllegalConstructor或按样本实现对应错误类型;如果不是TypeError,不能强行写成TypeError。
测试 95:addon 实例不得用 markObjectType 二次伪装
输入场景:补环境代码中存在:
const chains = native.createProtoChains([{ name: 'Blob', instanceFactoryName: 'createBlob' }], addon);
const blob = chains.createBlob();
native.markObjectType(blob, 'Blob');
执行:
node scripts/check_webapi_addon_coverage.js --file case/result/src/env/browser-objects/blob.js --markdown
期望:
- 检查失败并指出
markObjectType不是批准 API,语义不明确。 - 修复方向是删除二次标记;addon 构造函数 /
createProtoChains实例工厂创建出的对象本身应处理Object.prototype.toString。 - 只有 addon 不可用、创建的是普通 JS fallback 对象时,才允许
markObjectToString/Symbol.toStringTag,且必须在附近注释、阶段报告和最终总结中记录 fallback 原因。
测试 96:单行堆叠代码必须被格式化检查拦截
输入场景:补环境代码中存在:
Object.defineProperty(Navigator.prototype, 'userAgent', { get: native.createGetter('userAgent', 0, function(){ return ua; }), enumerable: true, configurable: true });
ctx.indexedDB = { open(){ return {}; }, deleteDatabase(){ return {}; } };
try { Object.defineProperty(obj, 'x', { value: 1, enumerable: true, configurable: true }); } catch {}
执行:
node scripts/check_code_quality.js --file case/result/src/env/install-env.js --markdown
期望:
- 检查失败。
- 报告指出属性描述符压在一行、全局 WebAPI 对象 / 方法堆叠、较长单行控制流等问题。
- 修复后应拆成多行具名函数、清晰 descriptor、模块化安装函数,并补充中文注释说明来源和 fallback 原因。
测试 97:补环境前必须询问框架选择且默认不使用
输入场景:用户已确认参数、入口、JS 文件、取证模式和最终请求客户端,准备进入 Node.js 补环境阶段。
期望:
- Skill 必须先读取
references/runtime-frameworks.md。 - 必须提醒用户选择:不使用补环境框架(默认)、
isolated-vm、Node.js 内置vm、jsEnv。 - 用户未明确选择时,记录为“不使用补环境框架”,不得自动启用
isolated-vm、vm或jsEnv。 - 最终项目中不得混入未选择的 runtime 模板或依赖。
测试 98:Trace 复杂度评估不绑定框架选择
输入场景:case/ruyi-trace/logs/trace.ndjson 或 case/tmp/env-trace.jsonl 存在,日志命中 Canvas、WebGL、Storage、Function.prototype.toString 和 Object.getOwnPropertyDescriptor。
执行:
node scripts/analyze_trace_complexity.js --case-dir case --markdown
期望:
- 输出复杂度等级、命中 WebAPI 类别、真实性检测、指纹、异步、状态依赖和风险。
- 报告必须明确“复杂度评估不决定框架选择”。
- 即使复杂度为高,也不得自动选择
isolated-vm、vm或jsEnv;框架选择仍以用户确认结果为准。 - 阶段报告应记录复杂度评估结果和独立的补环境框架选择。
测试 99:普通上下文无法继续时二次提醒而不是自动切换
输入场景:用户最初未选择补环境框架,后续普通上下文反复出现 Node 泄露、Realm / intrinsic 差异、Function("return this")() 或 constructor.constructor 检测问题。
期望:
- Skill 暂停并说明当前问题可能需要补环境框架辅助。
- 再次让用户选择
isolated-vm、vm、jsEnv或继续不使用框架。 - 不得擅自把最终项目切换到
isolated-vm、vm或jsEnv。 - 如果用户继续不使用框架,应在阶段报告和最终总结记录风险。
测试 100:新版 addon API 导出与随包产物更新
输入场景:当前平台存在随包 assets/native-addon/<platform>-<arch>/addon.node,执行 addon 加载检查。
执行:
node scripts/load_native_addon.js --json
期望:
- Windows x64 产物应从新版
addon.node复制到assets/native-addon/win32-x64/addon.node与addon-win32-x64.node。 exports至少包含createNativeFunction、createGetter、createSetter、createNativeObject、createProtoChains、getProtoChainRegistry、deleteProtoChainRegistryEntry、clearProtoChainRegistry、setPrivate、getPrivate、hasPrivate、deletePrivate、createInterceptor、createNativeCollection、getMimeTypesAndPlugins、createUndetectable、throwTypeError。- 不应依赖
hello;如果导出列表没有hello,不视为失败。
测试 101:plugins 和 mimeTypes 必须优先 getMimeTypesAndPlugins
输入场景:最终 env 代码安装 navigator.plugins 或 navigator.mimeTypes,但只写了普通数组、普通对象或手写 PluginArray / MimeTypeArray,没有 getMimeTypesAndPlugins。
执行:
node scripts/check_webapi_addon_coverage.js --file case/result/src/env/navigator-env.js --markdown
期望:
- 检查失败。
- 报告指出
navigator.plugins/navigator.mimeTypes未体现getMimeTypesAndPlugins(config)addon-first。 - 修复方向要求 addon 可用时使用
addon.getMimeTypesAndPlugins(config),真实浏览器插件数据不同则用 config 生成;addon 不可用时才允许 JS fallback 并记录原因。
测试 102:浏览器集合对象必须优先 createNativeCollection
输入场景:最终 env 代码用普通 class、普通 function、数组或普通对象实现 HTMLCollection、NodeList、PluginArray、MimeTypeArray、DOMTokenList 或 StyleSheetList,没有 createNativeCollection 或 getMimeTypesAndPlugins 证据。
执行:
node scripts/check_webapi_addon_coverage.js --dir case/result/src/env --markdown
期望:
- 检查失败。
- 报告指出集合对象缺少
createNativeCollection/getMimeTypesAndPluginsaddon-first。 - 修复后集合对象应具备
length、数字索引、名称访问、item()、namedItem()、迭代器、构造函数非法调用行为和正确的Object.prototype.toString。
测试 103:jsEnv 只能由用户明确选择且不能虚构 API
输入场景:进入正式补环境阶段前,用户还没有选择补环境框架,或只说“可以考虑 jsEnv”但没有提供 jsEnv 项目路径、入口文件和使用文档。
期望:
- Skill 默认仍按“不使用补环境框架”继续。
- 不得因为 Trace 复杂度高或模型推断自动选择 jsEnv。
- 如果用户明确选择 jsEnv,必须先要求用户提供项目路径、安装方式、入口文件和使用文档,并检测可用性。
- 未检测通过前不得复制
jsenv-runtime.js到最终项目,也不得虚构jsEnv.createContext、jsEnv.run等 API。 - 最终项目只保留用户确认的 runtime;未选择 jsEnv 时不得出现 jsEnv runtime、adapter 或依赖。
测试 104:选择 isolated-vm 时必须使用随包魔改 xbs isolated-vm
输入:
我选择使用 isolated-vm 作为补环境框架。
期望:
- 先读取
references/runtime-frameworks.md与references/xbs-isolated-vm-api.md。 - 运行
node scripts/check_xbs_isolated_vm.js --markdown或等价检测。 - 检测内容必须包含当前 Node 版本、ABI、平台、二进制路径、是否加载成功、
window === globalThis、window.xbs是否存在、17 个 xbs API 是否齐全。 - 如果当前平台目录缺失或 ABI 不匹配,必须提示用户提供当前平台 / 架构 / Node ABI 匹配的魔改 xbs isolated-vm 构建产物,或改选不使用框架 / vm / jsEnv。
- 不得自动安装 npm 原版
isolated-vm,不得把旧addon.node桥接进 isolated-vm。 - 最终项目仅在用户选择 isolated-vm 时复制
xbs-isolated-vm/<platform>-<arch>/isolated_vm.node。
测试 105:xbs native-first 证据被 addon-first 门禁识别
输入:最终 env 中存在以下 Context 内补环境代码:
const chain = xbs.createProtoChains([{ name: 'Navigator', constructor() {}, instanceFactoryName: 'createNavigator' }]);
Object.defineProperty(chain.Navigator.prototype, 'userAgent', {
get: xbs.createGetter('userAgent', 0, function () { return 'Mozilla/5.0'; }),
enumerable: true,
configurable: true,
});
const plugins = xbs.getMimeTypesAndPlugins({ plugins: [] });
期望:
check_env_realism.js将xbs.createProtoChains/xbs.createGetter/xbs.getMimeTypesAndPlugins识别为 native-first 证据。check_webapi_addon_coverage.js不应因为使用xbs.而误报“未发现 addon-first 证据”。- 若源码只使用
NativeProtect/ 普通函数 / 普通对象而没有addon.node或xbs证据,应继续失败。
测试 106:xbs isolated-vm ABI 不匹配时的可解释失败
输入:
node scripts/check_xbs_isolated_vm.js --json
期望:
- 如果当前 Node ABI 与随包
isolated_vm.node不匹配,脚本输出status: "abi-mismatch"、当前 Node 版本、当前 ABI、平台、二进制路径和中文处理建议。 - 默认模式下该可解释失败不崩溃,便于 Skill 自检;真实 case 已选择 isolated-vm 时使用
--strict作为阻断门禁。 - 提示用户提供匹配二进制或改选框架,不得建议自动退回 npm 原版
isolated-vm。
测试 107:动态 HTML / JS 必须运行时刷新
输入场景:case/notes/resource-manifest.json 中存在资源:
{
"resources": [
{
"url": "https://example.com/challenge.js?ts=1",
"type": "js",
"file": "case/js/snapshots/challenge.js",
"sha256": "abc",
"dynamic": true,
"use": "analysis-snapshot",
"requiredForFinal": true,
"runtimeRefresh": false
}
]
}
执行:
node scripts/check_dynamic_resources.js --case-dir case --require-runtime-refresh --markdown
期望:
- 检查失败,退出码为
1。 - 明确指出该动态资源影响最终参数生成,但未声明
runtimeRefresh: true,且缺少refreshEntry。 - Skill 不得继续把旧 HTML / JS / challenge 快照固定写入最终 signer。
测试 108:最终产物不得包含动态快照
输入场景:resource-manifest.json 标记 case/js/snapshots/challenge.js 为 dynamic: true,同时 case/result/ 中存在相同内容或 snapshots/challenge.js。
执行:
node scripts/check_dynamic_resources.js --case-dir case --require-runtime-refresh --markdown
期望:
- 检查失败。
- 报告指出动态快照内容疑似被复制到最终产物,或
result/中存在 snapshots 路径。 - 修复方向是把旧快照留在
case/js/snapshots/用于分析,把最终资源获取逻辑迁移到result/src/resources/fetch-runtime-resources.js或等价模块。
测试 109:动态资源刷新模块通过检查
输入场景:动态资源影响最终参数生成,但 manifest 中已设置:
{
"dynamic": true,
"use": "analysis-snapshot",
"requiredForFinal": true,
"runtimeRefresh": true,
"refreshEntry": "result/src/resources/fetch-runtime-resources.js"
}
并且 case/result/final.js 中先调用 fetchRuntimeResources 或等价刷新函数,再调用 signer 生成参数。
执行:
node scripts/check_dynamic_resources.js --case-dir case --require-runtime-refresh --markdown
期望:
- 检查通过。
- 输出动态资源数量、影响最终参数生成的资源数量、刷新模块路径。
- 仍需由
check_final_artifact.js确认最终入口唯一、无自动化代码、请求由已确认 TLS 指纹兼容客户端完成。
测试 110:fixture 资源 hash 变化先判断过期
输入场景:fixture 中记录 htmlSha256 / jsSha256 / challengeSeed,当前运行时刷新得到的 hash 与 fixture 不一致。
期望:
- 不直接把参数不一致归因于补环境错误。
- 先检查
resource-manifest.json、Cache-Control、Set-Cookie、HTML seed、challenge JS URL 和当前 runtime refresh 结果。 - 如果确认资源过期或 seed 更新,先刷新资源并补采 fixture;只有当前有效资源一致但输出仍不一致时,才继续补 WebAPI。
测试 111:验证码接口确认门禁
输入场景:用户已提供完整 URL、API、cURL、参数、取证模式和 TLS 客户端,但接口名或参数包含 captcha、verify、challenge、track 等验证码特征。
期望:
- 在任何浏览器取证、RuyiTrace 捕获、Hook、断点、JS 下载或接口重放前,先确认是否为验证码 / 风控验证接口。
- 如果用户确认是验证码接口,必须让用户选择“提供从触发到验证的完整流程由 AI 自动取证”或“用户自己完成流程,AI 只捕获”。
- 用户未选择前,不得开始验证码链路取证。
测试 112:用户手动完成验证码流程时必须等待确认
输入场景:用户选择自己完成验证码触发到验证流程,AI 负责抓包和 Trace。
期望:
- 先开启已确认取证工具的网络捕获、Hook 或 RuyiTrace 记录。
- 明确提示用户完成“触发验证码 → 交互 → 点击验证 / 提交”后回复“已经完成触发到验证流程”。
- 未收到该回复前,不得停止捕获、不得导入日志并宣称链路完整。
测试 113:验证码 RuyiTrace 必须覆盖完整链路
输入场景:取证模式为 ruyiPage + RuyiTrace,目标为验证码接口,但 NDJSON 只包含页面加载阶段,没有交互事件或 verify 接口附近调用栈。
期望:
- 不进入正式补环境。
- 要求重新采集覆盖触发、展示、交互、验证提交和 verify 接口返回的日志。
- 阶段报告记录当前 Trace 未覆盖完整验证码流程。
测试 114:验证码事件轨迹 fixture 必须可替换且有中文注释
输入场景:验证码加密参数依赖鼠标轨迹,最终 env / signer 代码中需要旧轨迹。
期望:
- 代码提供
motionTrack/eventFixture/verifyContext等可替换入口。 - 中文注释说明旧轨迹只用于补环境生成加密参数,后续由
web-verify-patcher替换为识别后的轨迹。 - 中文注释 UTF-8 正常显示,不出现问号、连续问号或乱码。
- 不得把旧轨迹硬编码成不可替换逻辑,不得宣称验证码最终验证一定成功。
测试 115:调用 web-verify-patcher 前必须检测安装
输入场景:验证码加密参数已经通过补环境生成,下一步需要识别验证码图片、坐标换算、生成轨迹或提交验证分析。
执行:
node scripts/check_web_verify_patcher.js --require --markdown
期望:
- 已安装时输出命中目录。
- 未安装时检查失败,退出码为
1,并给出自动安装 / 自行安装指引。 - 自动安装前必须让用户确认安装目录;克隆
https://github.com/lwjjike/xbsReverseSkill后必须确认存在web-verify-patcher/目录。若仓库当前分支没有该目录,不得假装安装成功。
测试 116:isTrusted 可信输入规则必须前置
输入场景:用户选择 ruyiPage、Camoufox 或 CloakBrowser 自动点击、拖拽、键盘输入、滚动或验证码交互。
期望:
- 在执行交互前读取
references/trusted-input-and-isTrusted.md。 - ruyiPage 优先使用
page.actions、human_move、human_click或drag;如果必须 JS 构造事件,事件初始化参数必须包含ruyi: true。 - Camoufox / CloakBrowser 必须从启动开始启用
humanize并使用官方原生输入 / humanize 交互方法。 - 普通
dispatchEvent(new MouseEvent(...))、new KeyboardEvent(...)、page.evaluate(() => dispatchEvent(...))不能作为验证码或高风控交互主路径;无法保证可信输入时暂停让用户手动操作、切换工具或明确接受风险。
测试 117:addon ABI 不兼容时先询问 Node.js v25.8.2
输入场景:node scripts/load_native_addon.js --json 返回 abiMismatch: true,或错误信息包含 NODE_MODULE_VERSION / compiled against。
执行:
node scripts/check_node_runtime_compat.js --target addon --markdown
期望:
- 输出 addon 兼容 Node.js 版本
v25.8.2、当前 Node、当前 ABI 和 nvm 检测结果。 - 不得直接降级到 NativeProtect / JS fallback。
- 必须让用户选择自动安装 nvm、手动安装 nvm、提供已安装 nvm 路径,或拒绝安装兼容 Node。
- 用户同意后执行
nvm install 25.8.2、nvm use 25.8.2并重新运行load_native_addon.js。 - 只有用户拒绝或切换后仍失败,才允许 fallback,并在阶段报告、代码变更记忆和最终总结记录。
测试 118:isolated-vm ABI 不兼容时先询问 Node.js v26.3.1
输入场景:用户明确选择 isolated-vm,但 node scripts/check_xbs_isolated_vm.js --json 返回 status: "abi-mismatch" 或 abiMismatch: true。
执行:
node scripts/check_node_runtime_compat.js --target isolated-vm --markdown
期望:
- 输出 xbs isolated-vm 兼容 Node.js 版本
v26.3.1、当前 Node、当前 ABI 和 nvm 检测结果。 - 不得自动退回 npm 原版
isolated-vm,不得桥接旧addon.node。 - 必须让用户选择自动安装 nvm、手动安装 nvm、提供已安装 nvm 路径,或拒绝安装兼容 Node。
- 用户同意后执行
nvm install 26.3.1、nvm use 26.3.1并重新运行check_xbs_isolated_vm.js --strict --json。 - 用户拒绝或切换后仍失败时,才允许提供当前 ABI 匹配的魔改
isolated_vm.node构建产物,或改选不使用框架 / vm / jsEnv。
测试 119:纯 JS、addon 与 xbs 都无法覆盖时必须输出 native 能力缺口闭环
输入场景:目标检测依赖浏览器引擎级行为,例如 document.all 同时要求 typeof document.all === "undefined"、document.all.length、document.all.item() 和 [object HTMLAllCollection],当前纯 JS fallback 无法满足,当前 addon.node 与 xbs isolated-vm API 也无法让最小行为测试通过。
期望:
- 先读取
references/native-capability-gap.md。 - 不继续用状态化 getter、普通对象、Proxy 或只针对当前报错的 workaround 硬凑稳定方案。
- 先排除实现不完整和已有 native API 用法错误;如果已有 addon / xbs API 可覆盖,必须改为 native-first。
- 确认为能力缺口时,生成
case/notes/native-capability-gap.md,包含阻塞点、触发位置、真实浏览器基线、纯 JS / addon / xbs 当前结果、无法解决原因、建议新增 native API、最小行为测试用例和通过标准。 - 给用户的测试用例必须是行为契约,能在真实浏览器和目标 native 后端运行,失败时输出具体差异。
- 用户更新 addon.node 或 xbs isolated-vm 后,先运行该测试用例;通过后才继续补环境。
- 用户拒绝扩展 native 能力且目标参数生成必须依赖该行为时,标记 case 阻塞;如果用户接受临时 workaround,阶段报告和最终总结必须写明“仅当前样本路径临时兼容”。
测试 101:取证指纹基线必须固定
输入场景:用户选择 ruyiPage / RuyiTrace / Camoufox / CloakBrowser 取证,第一次采样 language=zh-CN、timezone=Asia/Shanghai,第二次重新启动工具后随机成 language=en-US 或 WebGL / screen 改变。
期望:
- 必须先读取
fingerprint-baseline-consistency.md。 - 第一次成功取证后生成
case/notes/fingerprint-baseline.json和baselineId。 - 第二次采样前复用同一 profile / seed / 代理 / 语言 / 时区 / UA / Client Hints / screen / WebGL 基线。
- 如果发现字段冲突,写入
case/notes/fingerprint-baseline-diff.md并阻塞,不得混用样本。 fingerprint.fixture.json必须包含同一baselineId。
测试 102:指纹 fixture baselineId 检查
输入场景:case/fixtures/fingerprint.fixture.json 缺少 baselineId,或与 case/notes/fingerprint-baseline.json 中的 baselineId 不一致。
执行:
node scripts/check_fingerprint_fixture.js --case-dir case --require canvas,webgl --markdown
期望:
- 检查失败。
- 明确指出缺少 fingerprint baseline 或 baselineId 不一致。
- 要求重新采样或重新绑定同一 baseline,不能继续最终交付。
测试 103:最终请求一律使用 Session 模式
输入场景:case/result/final.js 使用 CycleTLS / impers / curl-cffi-node 或 case/result/final.py 使用 curl_cffi / cffi_curl / cyCronet 发请求,但只写了单次无状态请求函数,没有 session client、Cookie jar 或 close / destroy 逻辑。
执行:
node scripts/check_final_artifact.js --case-dir case --markdown
期望:
- 检查失败。
- 要求最终请求使用 Session 模式,即使只有一个请求也要创建 session client。
- 动态资源刷新、Cookie / challenge 生成、目标 API 必须复用同一 session。
- 成功、失败或异常后必须销毁 session,并清理 Cookie jar / 敏感运行态。
测试 104:Session 请求链通过示例
输入场景:最终项目包含 final.js、src/request/client.js,client.js 导出 createRequestSession(),内部维护 Cookie jar,并提供 request() 与 close();final.js 在 try/finally 中创建 session、刷新动态资源、生成参数、发送目标 API,最后调用 session.close()。
期望:
check_final_artifact.js不因 Session 模式缺失而失败。- 最终总结“TLS 请求验证与 Session 请求链”章节记录 session client 类型、请求链、Cookie jar 来源和销毁方式。
- 最终项目仍不得包含浏览器自动化代码。
测试 120:指纹值必须 Trace 未截断优先,Trace 不可用再采样
输入场景:目标访问 canvas.toDataURL()、WebGLRenderingContext.getParameter()、navigator.userAgent 或 screen.width 等具体值;用户选择了 RuyiTrace,并且 NDJSON 覆盖当前业务路径。
期望:
- 先读取并导入 RuyiTrace NDJSON,检查
notes/ruyitrace-summary.md和原始日志中对应 API 的值、调用栈、baseline 和截断状态。 - 如果字段未截断且与当前
baselineId一致,优先把该真实值作为 fixture 来源,并记录source.traceStatus = "used-untruncated"。 - 如果字段达到或接近 4000 字符、真实长度为
unknown、trace 未覆盖或 baseline 冲突,不能把 trace 可见片段作为最终result;必须使用用户已确认的 ruyiPage / Camoufox / CloakBrowser / 手动浏览器在同一 baseline 下补采。 - 每个最终样本必须记录
baselineId、source / capturedBy、traceStatus、truncated、长度和 hash。
测试 121:禁止 AI 猜指纹值或用 Node.js 模拟库结果替代真实值
输入场景:fingerprint.fixture.json 中的 canvas.toDataURL、webgl.getParameter 或 navigator.languages 没有 trace 证据,也没有自动化 / 手动浏览器采样来源,只写了默认值、随机值、AI 推断值,或最终 env 使用 node-canvas / headless-gl / jsdom 的输出作为指纹结果。
执行:
node scripts/check_fingerprint_fixture.js --case-dir case --require canvas,webgl --markdown
node scripts/check_final_artifact.js --case-dir case --markdown
期望:
- 检查失败或阶段门禁阻塞。
- 明确指出缺少真实值来源,要求优先查看未截断 Trace;Trace 不可用时用当前已确认取证工具补采。
- 不得把 AI 猜值、静态分析、默认值、随机值、mock 值、Node.js / jsdom / node-canvas / headless-gl 结果作为最终回放值。
- 最终项目不得包含指纹采样 Hook 或浏览器自动化代码;只能回放已经采样并绑定同一
baselineId的真实值。
测试 122:高强度检测不能只围绕单 API 补环境
输入场景:用户只提供目标 API cURL,响应为 403 / 429 / challenge / bot block / verify / 风控页,或浏览器从入口页访问后 API 才成功。
期望:
- 必须读取
references/high-strength-browser-detection.md。 - 要求确认入口 HTML、前置 JS / 检测脚本、Cookie / Storage、动态资源和目标 API 的关系。
- 不得只根据单个 API cURL 直接写补环境或反复修改 signer。
- 阶段报告记录“高强度检测通用门禁”触发证据。
测试 123:高强度指纹不得随机化或 AI 猜值
输入场景:补环境代码对 Canvas / WebGL / Audio / Fonts / DOM geometry / Permissions / Plugins 使用 Math.random()、固定默认值、AI 经验值、node-canvas / headless-gl / jsdom 结果,或每次运行生成不同指纹。
期望:
- 检查失败或阶段门禁阻塞。
- 要求优先使用 Trace 未截断值;Trace 缺失 / 截断时使用用户已确认取证工具在同一
baselineId下采样。 fingerprint.fixture.json必须记录source / capturedBy / traceStatus / baselineId / valueLength / hash / truncated。
测试 124:自动化 / CDP / Headless 风险必须前置处理
输入场景:目标疑似高强度检测,但取证阶段准备先用普通 headless Playwright / Puppeteer / Selenium / 系统浏览器探测,或检测到 navigator.webdriver、Selenium / PhantomJS / NightmareJS honeypot、CDP / DevTools 侧信道、isTrusted=false 交互风险。
期望:
- 必须回到
browser-acquisition.md让用户确认 ruyiPage / Camoufox / CloakBrowser / 手动浏览器等高保真取证路径。 - 不得先普通自动化失败后再切换。
- 首次成功取证后固定 fingerprint baseline;后续不得混用随机 profile。
测试 125:UA / Client Hints / TLS / Header 与取证 baseline 不一致必须阻塞
输入场景:浏览器取证使用 Firefox 或某一套 UA / locale / timezone / proxy,但最终请求 Header 伪装 Chrome、Client Hints 不匹配、普通 fetch / requests 无 TLS impersonate、或代理 / IP / 地区变化。
期望:
- 必须读取
tls-request-validation.md与session-request-chain.md。 - 阻塞最终真实请求,要求统一 UA、UA-CH、Accept-Language、Sec-Fetch、Referer、Origin、Header 顺序、TLS JA3/JA4、代理 / IP 和 fingerprint baseline。
- 不得把网络一致性问题误判成 JS 补环境失败。
测试 126:Permissions / Plugins / MimeTypes 进入范围后不能用普通对象糊弄
输入场景:Trace 或目标 JS 访问 navigator.permissions.query、navigator.plugins、navigator.mimeTypes、PluginArray / MimeTypeArray 方法和描述符。
期望:
- 必须读取
env-object-model.md的高强度补充 WebAPI 对象清单。 - addon 可用时 plugins / mimeTypes 优先
getMimeTypesAndPlugins(config);集合对象优先 native collection。 - Permissions API 要采样 Promise 行为、
PermissionStatus原型链、state、事件属性和错误类型。 - 不得返回空数组、普通对象或同步假值作为高强度主路径。
测试 127:请求顺序和入口页状态链必须进入最终 Session
输入场景:目标 API 依赖入口 HTML、动态 JS、首访 Cookie、Storage、challenge / telemetry 资源或前置接口;最终项目只在 final.js 中直接请求目标 API。
期望:
session-request-chain.md检查失败或人工门禁阻塞。- 最终入口必须在同一 TLS 指纹兼容 Session 中完成入口页 / 动态资源刷新 / Cookie 或状态链更新 / 参数生成 / 目标 API 请求。
- 如果用户选择只输出本地参数,必须明确不发真实请求,不能伪造请求成功。
测试 128:高强度失败排查顺序必须先于反复改 env
输入场景:参数不一致或最终请求失败,模型准备直接修改 env.js 中某个 WebAPI 返回值。
期望:
- 先按
high-strength-browser-detection.md排查:是否风控页、入口页缺失、Cookie / Storage 过期、UA / TLS / IP / Header 不一致、baseline 混用、trace 截断、指纹缺样本、自动化暴露、请求顺序缺失。 - 排除以上问题后,才定位目标 JS 补环境对象、writer 或 signer 逻辑。
- 排查结论写入阶段报告、代码变更记忆和最终总结。
测试 129:长指纹日志 4000 / 4096 截断不得作为最终值
输入场景:RuyiTrace / NDJSON 中记录了 canvas.toDataURL()、WebGLRenderingContext.readPixels()、navigator.gpu.requestAdapter()、OfflineAudioContext.startRendering() 或类似长指纹 API 的返回值,日志中可见字符串长度为 4000、4096 或接近阈值。
执行:
node scripts/import_ruyitrace_log.js --input trace.ndjson --case-dir case --truncation-threshold 3900 --markdown
node scripts/check_fingerprint_fixture.js --case-dir case --require canvas,webgl --markdown
期望:
import_ruyitrace_log.js在摘要中把该字段标记为疑似截断,真实长度为unknown,只记录可见长度和可见片段 hash。fingerprint.fixture.json如果直接把 trace 可见片段写成最终result,检查失败。- 必须使用用户已确认的 ruyiPage / Camoufox / CloakBrowser / 手动浏览器在同一
baselineId下补采完整浏览器真实值。 - 使用
generate_fingerprint_hook.js生成的采样 Hook 时,复制结果前必须执行await window.__WEB_JS_ENV_PATCHER_FINALIZE_FINGERPRINT__();Hook 不得包含clip(result, 4096)、slice(0, 4096)等裁剪逻辑。 - 完整长值直接保存或分片保存均可;分片保存必须记录
encoding: "string-chunks"或encoding: "base64-chunks"、valueLength、chunkSize、chunks、sha256、truncated: false和真实来源。 - 数值型返回值本身等于 4096 不一定是截断;本规则针对日志中的长字符串、长数组、base64、序列化对象和二进制编码结果。
测试 130:signer / probe 不得承载补环境主体
输入场景:最终项目中出现 src/signer/akamai_runtime_probe.js、runtime_probe.js、probe.js、diagnostic.js 或类似文件,并且该文件同时实现 navigator、document、canvas、webgl、performance、XMLHttpRequest、fetch、Storage、Cookie、DOM 构造链等多类 WebAPI。
执行:
node scripts/check_code_quality.js --case-dir case --markdown
node scripts/check_code_quality.js --dir case/result --json
期望:
check_code_quality.js必须识别 signer / probe / runtime 入口文件承载多域 WebAPI 补环境主体,并返回失败。- 不能因为文件名包含
probe、runtime、signer、diagnostic、或当前脚本只是“诊断执行器”就豁免模块化要求。 - 修复方向必须是:probe / signer 只保留入口编排和结果摘要;WebAPI 主体拆入
src/env/或src/node-runtime/env/,例如browser-objects/navigator.js、browser-objects/document.js、fingerprint/canvas.js、fingerprint/webgl.js、network/xhr.js、network/fetch.js。 - 质量检查失败时不得继续最终请求验证或交付;必须先重构、补充 UTF-8 中文注释、复跑
check_code_quality.js与check_webapi_addon_coverage.js通过后再继续。
测试 131:Trace inventory 通过但 runtime 行为不一致必须阻断
输入场景:原始 Trace 已命中 XMLHttpRequest 与 performance,trace-api-inventory.json 把两项都标为 implemented-first-pass;当前 Node runtime 虽然存在同名对象,但 XHR 的 brand / prototype 为 [object EventTarget],或 Performance 的继承链、descriptor、receiver、返回值与浏览器 Trace 不一致。
执行:
node scripts/build_trace_runtime_contract.js --case-dir case --baseline-id baseline-a --markdown
node scripts/run_trace_runtime_audit.js --case-dir case --entry case/result/final.js --markdown
node scripts/check_trace_runtime_conformance.js --case-dir case --markdown
node scripts/check_trace_api_coverage.js --case-dir case --require-runtime-closure --markdown
期望:
- 仅有同名对象、inventory 状态或手工
matched不得通过。 - contract 必须包含 realm、receiver、descriptor、brand、prototype、ownKeys、结果 / 异常摘要和 sequence 证据;Node audit 必须逐项提供实际观测。
- XHR brand / prototype 或 Performance 继承链错误时,P0/P1 mismatch 大于 0,检查失败。
- 修正 Node runtime 后重新生成 audit,且
traceSourceHash、contractHash、runtimeSourceHash、baselineId均匹配时才允许通过。
测试 132:XHR 幻影请求、错误 responseURL 与生命周期差异必须阻断
输入场景:浏览器 transcript 只有一条 POST XHR;Node transcript 除该 POST 外额外产生一条 GET,或失败 XHR 的 status=0 仍把 request URL 写入 responseURL,或 readyState / load / error / loadend 顺序与浏览器不同。
执行:
node scripts/check_xhr_fetch_semantics.js --case-dir case --require --require-no-send --out case/tmp/xhr-fetch-semantics-audit.json --markdown
期望:
- 多余 GET 必须列入
extraNodeRequests并阻断,不得按“目标请求成功”忽略。 status=0时responseURL必须为空;非空时无条件失败。- actor、realm、navigation epoch、method、URL、Header 有序列表、重复 Header、body length/SHA256/content-type、status/statusText/responseURL、readyState/event/Promise 顺序都必须实际比较。
- 修正 transcript 后 mismatch 与 extra Node request 同时为 0 才允许通过。
测试 133:对象形状不得只按 target 名称或私有属性前缀判断
输入场景:浏览器与 Node audit 都包含名为 XMLHttpRequest 的 target,且 Node 对象没有 _ / __ 自有属性,但 Node 的 Symbol.toStringTag、prototype chain、ownKeys、descriptor 或非法 receiver 行为与浏览器 baseline 不一致。
执行:
node scripts/check_object_shape_audit.js --case-dir case --markdown
期望:
- target 名称相同、没有下划线属性或手工填写
matched都不能直接通过。 - 必须逐字段比较 brand、prototype chain、ownKeys、descriptor、getter / method receiver、构造行为和异常类型。
- 任一必需字段缺失或不同都要阻断;修正实际对象形状并重新采样 Node audit 后才允许通过。
测试 134:Session Bridge 必须有运行时同 Session 证明
输入场景:源码包含 curl_cffi、IPC、live-session-bridge 等关键词,但 bridge audit 没有真实 round trip、sameSessionVerified=false、runtime hash 已过期,或 Python curl_cffi 场景由 Node 而不是 final.py 持有 session。
执行:
node scripts/check_xhr_fetch_session_bridge.js --case-dir case --require-live --tls-client curl_cffi --markdown
期望:
- 静态关键词与架构说明只算线索,不算通过证据。
- 必须存在
xhr-fetch-session-bridge-audit/v2,记录实际 round trip、同一 Cookie jar / session id、runtime source hash 和通过的 XHR/fetch semantics audit。 sameSessionVerified=false、零 round trip、hash 失效或缺少语义审计时必须失败。- 使用 Python
curl_cffi时sessionOwner必须为final.py;Node 只能负责 WebAPI 语义与 IPC 协议。
测试 135:真实请求前必须聚合执行 environment closure
输入场景:Trace coverage、对象形状、WebAPI 检测矩阵、XHR/fetch 语义和 Session Bridge 中四项通过,但 Trace runtime inventory / contract / audit 缺失或存在 P0/P1 mismatch。
执行:
node scripts/check_environment_closure.js --case-dir case --before-real-request --require-live --tls-client curl_cffi --markdown
期望:
- 总门禁必须实际调用并汇总 Trace runtime、对象形状、WebAPI 检测矩阵、XHR/fetch semantics 与 Session Bridge 五类检查。
- 任一子检查失败时总检查必须非零退出,不得因为其余检查通过而放行真实请求。
- 输出必须记录每个子检查的状态、阻断原因及
traceSourceHash、contractHash、runtimeSourceHash、baselineId、P0/P1 mismatch、network mismatch、extra Node request 数。 - 所有子检查使用当前源码与当前 baseline 的机器生成证据通过后,才允许进入真实请求。
测试 136:WebAPI 同名 probe 只有 status/evidence 必须失败
输入场景:browser baseline 与 Node audit 使用相同类别和 probe 名称,均填写 status: matched 与证据文件路径,但没有 observation/observed/result/value/output/expected。
执行:
node scripts/check_webapi_env_detection_matrix.js --case-dir case --require --json
期望:
- 检查失败,明确指出证据文本不能替代实际行为观测。
- browser/Node 都缺结果时也不得按“结构相同”通过。
- 缺少或不一致的
probeSuiteVersion、probeSourceFile、probeSourceHash必须阻断;声明 hash 与 case 内实际 probe 源文件不一致也必须失败。
测试 137:iframe / Worker 复用主 Realm 构造器或公开对象必须失败
输入场景:iframe 或 Worker 直接复用主环境的 Object/Function/Array/Promise/Event/EventTarget/URL/Blob/Headers/Request/Response/XMLHttpRequest,或复用主 navigator/performance/crypto/storage/fetch/timer wrapper。
期望:
iframe-realm必须覆盖 global relations、ECMAScript/WebAPI constructor isolation、object isolation、document relations 和 navigation lifecycle。worker-task必须覆盖 Worker-only/Window-only global surface、constructor/object isolation。frame.self/window/globalThis/frames、parent/top、contentWindow/contentDocument/defaultView/frameElement关系错误时阻断。- 共享底层同源 Cookie/Storage/Session 不得被误写成共享公开 wrapper。
测试 138:Worker terminate 与 MessagePort 双端生命周期必须逐组合检测
输入场景:Worker 只实现 terminate() 标记,pending timer/message 仍可派发;MessagePort 只检查 peer closed,不检查 sender closed、receiver closed、start、消息入队后 close 或 transfer。
期望:
worker-terminate-immediate与worker-terminate-deferred均必须有 browser/Node observation。- sender close、receiver close、双方 close、入队后 close、
start()、隐式 start、transfer 后原端口失效均必须覆盖。 - 任一缺失 capability、顺序差异或 close 后仍派发均阻断。
测试 139:DOM CRUD、合法 selector、Comment 与集合活性必须一致
输入场景:Node 把合法 div > span 当作非法选择器抛 SyntaxError,HTML parser 丢弃 Comment,childNodes/children/getElementsBy* 与 querySelectorAll 都实现为同一种静态数组,或 mutation 后 parent/sibling/ownerDocument/isConnected 不更新。
期望:
dom-selector-validity证明合法 selector 不抛错,非法 selector 按浏览器抛错。dom-html-parsing保留 Comment/Text/Element 及正确原型。dom-live-collections区分 live collection 与 static NodeList。- tree mutation、DocumentFragment 展开、clone/import/adopt、MutationObserver record 与时序不一致时阻断。
测试 140:双方同时缺失 XHR 字段或 Header 值为空必须失败
输入场景:browser/Node transcript 的事件名称和 pairKey 完全相同,但都缺少 URL、body SHA-256、responseURL、responseHeaders,或 Header 只有名称且 value 为 ""。
执行:
node scripts/check_xhr_fetch_semantics.js --case-dir case --require --require-no-send --json
期望:
network-transcript/v3缺失、meta provenance 不完整或networkAttempts未明确为 0 时失败。- 缺失字段不得被默认值归一化后判 matched。
- Header 必须有真实值或
{redacted,length,sha256};空值直接失败。 - POST/body 请求必须比较 contentType、byte length、SHA-256;响应必须比较 status/statusText/responseURL/response headers/body hash/lifecycle。
测试 141:Trace 状态事件顺序不同必须失败
输入场景:browser Trace 的折叠时间线为 XHR.open → XHR.send → reload → old-realm-cancel,Node audit 为 XHR.open → reload → XHR.send → old-realm-cancel,但逐 API observation 和调用次数相同。
执行:
node scripts/check_trace_runtime_conformance.js --case-dir case --json
期望:
trace-runtime-contract/v3与node-trace-runtime-audit/v3的 timeline hash 不同,检查失败。- 对 observation sequence 排序、只比较数量或从分组 observations 反推时间线均不能通过。
- Node audit 必须声明 timeline 来自原始 runtime event timeline。
测试 142:多份历史 Trace 不得自动拼成一条时间线
输入场景:case/ruyi-trace/logs/ 中存在两份来自不同阶段或不同 navigation 的 Trace,调用 build 命令时没有显式 --trace。
执行:
node scripts/build_trace_runtime_contract.js --case-dir case --baseline-id baseline-a --json
期望:
- 构建失败并要求显式选择当前 baseline 的完整 Trace。
- 重复
--trace传入多文件分片时,只有所有状态事件具有跨文件唯一全局 sequence 才允许合并。 - 不得按文件名或文件遍历顺序静默串联历史采集。
测试 143:阶段报告或 Trace 已出现网络/Realm/DOM 信号时 closure 必须主动触发
输入场景:result/ 暂时没有明显 XHR 文件名,但阶段报告、Trace、notes 或已有 transcript 已出现 XHR/fetch、iframe/Worker/MessagePort、DOM CRUD 或 ownKeys 信号。
执行:
node scripts/check_environment_closure.js --case-dir case --before-real-request --json
期望:
- closure 从整个 case 证据面识别信号,不依赖用户再次提醒,也不只扫描
result/静态关键词。 - 自动执行 Trace-runtime、对象形状、WebAPI 矩阵、XHR/fetch semantics、Session bridge、代码质量和 addon-first 中已触发的组件。
- 输出为摘要而不是嵌入所有子检查明细,并保留 baseline/hash/mismatch/extra request/networkAttempts 等关键指标。