Files

108 KiB
Raw Permalink Blame History

测试与验收要求

本文件用于测试 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.js vm 中运行。
  • 输出 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 分别返回:

  1. ruyiPage managed runtime 中的 Firefox。
  2. 普通系统 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

步骤:

  1. 用 ruyiPage 定制 Firefox + smart_fingerprint() 打开 https://www.jd.com/。
  2. 在导航前启动 page.capture.start(targets="pc_home_feed", collect_bodies=True)。
  3. 等待并最少量滚动触发首页 feed。

期望:

  • navigator.webdriver === false。
  • 捕获到 URL 包含 pc_home_feed 的 2xx 响应。
  • 请求 URL 中能观察到接口所需的动态参数,例如 h5st。

美团外卖 shopList

步骤:

  1. 用 ruyiPage 定制 Firefox + smart_fingerprint() 打开 https://h5.waimai.meituan.com/waimai/mindex/home。
  2. 在导航前启动 page.capture.start(targets="shopList", collect_bodies=True)。
  3. 等待并最少量滚动触发列表请求。

期望:

  • navigator.webdriver === false。
  • 至少捕获到一个非 OPTIONS 的 shopList 2xx 业务响应。
  • 单独的 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”并继续流程;该行为不通过。

输入场景:

目标网站无需登录。
目标接口返回 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”;该行为不通过。

输入场景:

目标接口需要账号登录。
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 == null
    • document.all !== undefined
    • Boolean(document.all) === false
    • 'all' in document === true
    • Object.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.toString fallback。
  • 报告中说明“addon 不可用 / 调用失败 / ABI 不兼容”的降级原因;不得声称 document.all fallback 与真实 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 不可用或调用失败时才使用 NativeProtect fallback。
  • 如果用户明确要求不使用 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.TextEncoder
  • ctx.URL = globalThis.URL
  • ctx.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 / getMimeTypesAndPlugins addon-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 等关键指标。