Files
yaklang-chrome-extension/docs/AUTO_PROFILE_INFERENCE_ARCHITECTURE.md
T

590 lines
26 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Browser Profile 自动推断与 AI 协作架构
## 1. 产品决定
自动推断 Profile 不是明文网关的辅助功能,而是浏览器现场的默认完成路径。
用户不应先理解混淆变量、复制密钥、编写包装函数,再手工配置参数路径和输出映射。正常流程必须从一次真实业务操作开始:
```text
用户执行登录 / 查询 / 提交
-> Recorder 生成有界业务 Trace
-> 确定性推断器关联明文点、页面调用和请求字段
-> 已知模式直接生成候选
-> 未知模式请求 AI 解释业务帧和参数语义
-> 必要时引导用户再执行一次操作以捕获业务闭包
-> 编译为文档绑定的 Profile
-> 使用录制样本做页面内回放校验
```
手写 JavaScript 保留为高级模式,不再作为主流程或文档中的首选方案。
本设计不包含“发送真实 HTTP 请求验证”。真实请求仍由 Yak / Web Fuzzer 的既有数据面负责。本阶段只负责发现、推断、捕获、编译和页面内样本校验。
## 2. 用户结果
以一次 CryptoJS 调用为例,默认界面应展示:
```text
已识别请求转换
POST /api/login
JSON 明文 -> CryptoJS.AES.encrypt -> body.encryptedData
输入 argument 0 <- 请求明文 JSON
Key argument 1 <- 页面内 WordArray · 16 B
IV options.iv <- 页面内 WordArray · 16 B
模式 CBC / Pkcs7
输出 toString -> URL encode -> encryptedData
证据 4 项 · 高置信度
[生成 Profile]
```
`_0x67b862` 一类混淆名称只能出现在折叠的原始证据中。主界面使用 `Key``IV``明文输入``请求字段` 等语义角色。
用户应能回答三个问题:
1. 插件为什么认为这是加密链路;
2. 哪些结论是确定事实,哪些是推测;
3. 还需要用户执行什么操作才能完成 Profile。
## 3. 设计原则
### 3.1 证据先于 AI
指纹相等、请求字段解析、调用顺序、运行时对象类型和调用栈属于确定性证据。AI 不重复判断这些事实,只消费其结构化结果。
### 3.2 AI 不能成为执行边界
AI 可以:
- 给业务 frame 排序;
- 将参数标注为 payload、key、iv、nonce、timestamp 或 signature
- 从有限源码片段中解释序列化和包装步骤;
- 在多个候选之间给出理由;
- 建议下一次捕获点。
AI 不可以:
- 直接提交任意 JavaScript 作为生产 Profile
- 引用不存在的事件、frame、参数或页面函数;
- 读取或输出 key、Cookie、token、密码等原始值;
- 绕过 grant、document、origin 或人工接管状态;
- 将猜测标记为已经验证的事实。
### 3.3 页面是执行环境,不是密钥导出器
Key、IV、CryptoKey、key promise、WASM 实例和闭包变量继续保留在原页面。Profile 只保存页面内 opaque callable 引用和经过校验的参数映射。
### 3.4 已知模式不依赖 AI,未知模式不依赖库清单
WebCrypto、CryptoJS、JSEncrypt 以及后续 sm-crypto、node-forge 等已知模式,连同 URLSearchParams、JSON、FormData 和常见编码链,应优先由确定性规则推断。AI 只处理业务语义和未知代码,避免增加延迟、成本和不确定性。
录制协议只暴露统一的 `crypto` 事件,库差异进入结构化 `adapterId / providerKind / family / operation / algorithm / mode / padding / encoding / state / key metadata`。推断器、时间线、Deep Capture 和 Agent 不再分别判断 `webcrypto``cryptojs` 等事件类型。新增密码库时只扩展 MAIN-world adapter、扩展自带的 manifest 和受限元数据归一化器,不扩展整条产品协议。
已知 adapter 只负责提供更准确的参数角色、算法和状态语义,不是通用性的唯一来源。对于 ESM/Webpack 闭包、Worker、WASM 或完全未知的业务封装,系统必须从请求/消息边界和调用栈恢复上层业务 callable;算法尚未命名不能单独成为 `insufficient-evidence`。adapter 协议的开放化、Worker/MessagePort 边界、高价值库优先级与反靶场特化验收见 [`FRONTEND_CRYPTO_GENERALIZATION_ROADMAP.md`](FRONTEND_CRYPTO_GENERALIZATION_ROADMAP.md)。
### 3.5 无兼容负担
插件尚未正式投入使用。页面配方、运行时适配器和 Transform Profile 可以直接收敛到新模型,不保留旧数据迁移或双写逻辑。
## 4. 总体架构
```text
MAIN-world Recorder
| bounded events + opaque handles + semantic argument metadata
v
Evidence Normalizer
| request fields / call slots / encodings / exact & normalized links
v
Evidence Graph
| proven edges + supported edges + hypotheses
+-----------------------+
| |
v v
Deterministic Inference AI Analysis
| known patterns | frame ranking / semantic labels / unknown code
+-----------+-------------+
v
Candidate Merger
| schema validation + evidence reference validation
v
Pipeline Compiler v2
| page callable graph, no arbitrary generated code
v
Local Sample Replay
| deterministic compare or structural assertions
v
Document-bound Profile
```
推断计算在扩展后台完成。Yakit、Options 和 AI Agent 读取同一候选结构,不各自实现一套启发式规则。
## 5. Evidence Graph
### 5.1 节点
```ts
type EvidenceNode =
| RecordingEventNode
| RecordedValueNode
| RequestFieldNode
| CallableNode
| CallArgumentNode
| StackFrameNode
| SourceExcerptNode
```
节点只使用录制会话内稳定 ID。原始敏感值不是图节点属性。
### 5.2 边
```ts
type EvidenceStrength = "proven" | "supported" | "hypothesis"
type EvidenceEdgeKind =
| "exact-value"
| "normalized-value"
| "parent-call"
| "same-trace"
| "stack-frame"
| "argument-role"
| "request-destination"
```
- `exact-value`:同一录制盐下的指纹完全相同;
- `normalized-value`:经过有界白名单转换后相同,例如 URL decode、JSON field extraction 或 Base64 表示;
- `parent-call`:Recorder 的同步父调用关系;
- `same-trace`:弱证据,只证明时间和用户操作相关;
- `hypothesis`:只能由 AI 或启发式产生,必须列出依据。
### 5.3 请求边界归一化
网络事件在边界处解析,不全局 Hook `JSON.stringify``encodeURIComponent`
- JSON:递归提取最多 64 层、100,000 节点;
- `application/x-www-form-urlencoded`:字段级 URL decode
- `FormData`:字段名、字符串值和文件元数据;
- Headers:规范化名称但保留原始大小写用于展示;
- Query:字段级解析;
- 原始 body:保留整体指纹和类型。
归一化候选只允许白名单操作并设置总预算。不得对每个值进行无界编码组合爆炸。
### 5.4 参数语义
Recorder 对已知库记录参数角色而不是变量名:
```ts
interface CallArgumentEvidence {
index: number
role: "data" | "key" | "iv" | "algorithm" | "options" | "signature" |
"salt" | "nonce" | "aad" | "unknown"
dataType: string
byteLength?: number
replaceable: boolean
retained: boolean
summary?: string
}
```
例如 CryptoJS AES
- `argument 0`data,可替换;
- `argument 1`key,不导出,页面内保留;
- `argument 2`options,提取 mode、padding 和 IV 长度,不提取 IV 值。
例如 JSEncrypt RSA
- `argument 0`:UTF-8 data,可替换;对象输入按稳定 JSON 序列化后再交给原函数;
- receiver:保留实际 JSEncrypt 实例,不重建、不导出;
- key:只记录 public/private、模数位数和本次录制随机加盐的指纹;
- padding:记录 `PKCS1-v1_5` 等可解释元数据;
- output:记录 Base64 形态并与 JSON/Form/Header/Query 请求字段做 exact link
- 公私钥 PEM、模数、指数和页面实例永不进入候选或 AI 上下文。
如果一次 RSA 输出精确进入一个请求字段,且原函数、receiver 和参数模板仍在当前 document 中,候选可以直接进入 `ready`,不要求用户填写函数表达式或先进入 Deep Capture。
## 6. 统一 Page Callable
当前页面配方和深度捕获适配器表达的是同一概念:在当前文档中可重复调用的页面函数。两套注册表应合并为 `BrowserPageCallable`
```ts
interface BrowserPageCallable {
id: string
kind: "recorded-call" | "business-closure" | "global-function"
name: string
target: BrowserTarget
lifecycle: "document"
inputSlots: CallableInputSlot[]
output: CallableOutputShape
provenance: {
recordingId?: string
traceId?: string
eventId?: string
frameId?: string
sourceUrl?: string
lineNumber?: number
}
}
```
`recorded-call` 保存原函数、receiver、固定参数模板和可替换槽位;`business-closure` 保存 CDP 暂停时捕获的业务函数与闭包;两者使用同一执行、授权、生命周期和审计接口。
Profile 不再引用 `recipeId``adapterId`,只引用 `callableId`
## 7. Pipeline v2
手工 JavaScript 中常见的 JSON 序列化、编码、调用和封装应变成可审计的类型化节点:
```ts
type PipelineNode =
| { kind: "context.read"; path: string }
| { kind: "builtin"; operation: BuiltinOperation; inputs: NodeRef[]; options?: object }
| { kind: "page.call"; callableId: string; arguments: NodeRef[] }
| { kind: "output.write"; destination: string; source: NodeRef; encoding: ValueEncoding }
```
首批 `BuiltinOperation`
```text
value.literal
json.stringify
json.parse
text.toString
url.encode
url.decode
base64.encode
base64.decode
hex.encode
hex.decode
object.pick
object.compose
form.compose
```
`value.literal` 只允许字符串、数字、布尔值或 `null`,用于编译器生成固定的协议元数据,例如表单
`Content-Type`。它不接受输入,也不能持有函数、对象或页面秘密。
每个节点有明确输入输出类型和大小预算。未知操作不能通过 AI 临时创造;用户确实需要自定义代码时,进入独立的高级节点,并沿用程序 Eval 的高风险授权。
## 8. 推断候选
候选不是立即生效的 Profile
```ts
interface BrowserProfileInferenceCandidate {
id: string
recordingId: string
traceId: string
target: BrowserTarget
request: { eventId: string; method: string; url: string }
direction: "request" | "response"
status: "ready" | "capture-required" | "mapping-required" | "insufficient-evidence"
confidence: { score: number; level: "high" | "medium" | "low" }
summary: string
pipeline: PipelineNodeDraft[]
evidence: InferenceEvidenceRef[]
missing: InferenceMissingStep[]
aiContext: BrowserInferenceAIContext
}
```
置信度不是 AI 的主观百分比。分数由固定规则产生,并在 UI 中解释:
- 请求字段与加密输出 exact link:强加分;
- 可重复 callable 已保留:强加分;
- 同一用户 Trace 且顺序正确:中等加分;
- 仅时间接近:弱加分;
- 多个同分候选:降分;
- 缺少输入映射或输出封装:状态不能为 ready。
## 9. 自动业务函数捕获
低层 `CryptoJS.AES.encrypt``crypto.subtle.encrypt` 往往不足以构造完整线上报文。推断器应把它作为断点入口,然后寻找上层业务函数。
```text
候选指出需要业务 callable
-> 用户点击“自动捕获完整加密流程”
-> 插件在已知低层调用处 arm 一次性断点
-> 用户重复相同操作
-> 页面暂停并立即显示控制面
-> 后台排除 Hook/依赖帧,并使用多来源共同祖先提示排序页面帧
-> 纯函数用 selected-frame;负责 DOM 取值/组包/发送的函数用 request-transaction
-> 页面立即恢复
-> 新明文映射到参数或页面控件,仅返回被拦截的线上 envelope
```
录制器只从每个来源事件的有界同步栈提取页面帧提示,并对 `functionName + script URL` 求交集;支持来源更多、平均深度更浅的共同祖先优先。捕获入口选择最早已确认的密码来源,而不是已经离开上层异步函数后的 Fetch 边界。后台再结合真实 CDP `scriptId`、函数位置、来源分类和副作用检查做最终选择,因此前端不能通过提交 URL、行号或函数名把任意对象伪装成推荐帧。
当最高候选唯一、可解析且未发现副作用时,默认路径使用 `selected-frame`。如果多个密码来源的最近共同页面祖先本身包含网络、DOM 或条件导航,系统不会跳过它去选更外层的事件 handler,而是建立 `request-transaction`:保留真实函数、receiver 和固定参数,在页面内替换明文控件,拦截唯一的目标 Fetch/XHR/Beacon/Form,校验所有预期输出字段后回滚 DOM。
存储副作用、多个或未授权请求、无法唯一绑定函数、或共同祖先证据并列时,系统保持页面暂停并解释原因。函数引用表达式只存在于高级模式。页面暂停不等待远程 AI;AI 只能在页面恢复后基于同一份有界证据做解释和候选补丁。
函数捕获后,后台从 `Function.prototype.toString` 恢复包括默认参数在内的有序参数名。单参数业务函数默认读取整个逻辑 Body;多参数且名称可靠时,引导配置生成 `body.<parameter>` 读取节点;`arg0` 这类占位名不会被冒充为已确认字段。Options 同时从已授权暂停帧的 local/block/closure scope 取同名原始值,构造一次性的本地回放 Body。完整暂停作用域始终只存在于当前会话;只有用户明确生成并保存明文网关后,选中的短时样本才会复制到独立的本机回放草稿。该草稿按 `profileId + request/response` 隔离,不写入 Profile、Bridge、审计、Yak/AI、诊断或导出,并可由用户单独清空。
### 9.1 多密码调用按请求建图
一个请求可能同时包含 AES ciphertext、RSA-encrypted session key、HMAC signature、nonce 和 timestamp。即使每个低层输出都与请求字段精确匹配,也不能把这些调用分别保存后独立回放:它们可能共享同一随机 key、IV、nonce 或闭包状态。
推断器因此按请求边界合并多个来源,生成一个 request-level candidate
```text
plaintext -----------------> AES.encrypt ----------> body.data
dynamic AES key -----------> JSEncrypt.encrypt ----> body.encryptedKey
canonical request fields --> HMAC.sign ------------> header.X-Sign
|
+-- 同一上层业务 callable 保证动态值一致
```
界面展示每个密码调用及其线上目标,但状态固定为 `capture-required`。用户点击“自动捕获完整加密流程”时,Deep Capture 优先在仍保留上层业务调用栈的密码来源处武装断点,并捕获一次上层业务封装;系统不会把多个看似 ready 的低层调用拆成多个可执行 Profile,也不会误导用户反复缩短已经足够短的录制操作。
### 9.2 请求事务的输入与输出契约
`request-transaction` 对明文只暴露一个 `body` 输入槽,对 Pipeline 返回被页面业务代码生成的整个请求 Body。因此 AES + RSA 之类多输出流程会直接编译为:
```text
context.read(body)
-> page.call(sendDataAesRsa 请求事务)
-> output.write(body)
```
事务保留暂停现场的 URL/event/receiver 等固定参数。逻辑 Body 是对象时,先按 input `name/id` 向页面控件做同名映射;参数名明确是 `payload/data/body/request/params/input` 时才直接替换参数。已混淆的单参数如果其保留值解析后等于目标 URL,必须继续保留,不得被明文对象覆盖。
## 10. AI Agent 集成
### 10.1 绑定资源
Yakit 从浏览器集成页启动 AI 分析时,附加一个类型化资源:
```text
AttachedResourceInfo.type = browser_session
AttachedResourceInfo.key = context
```
Value 只在 Yak 进程内解析,包含 device、grant、document、selected trace 和 candidate ID。渲染给模型的内容只包含安全摘要,不暴露 device token、grant secret 或录制值。
资源必须绑定:
```text
timeline session
AI task
deviceId
grantId
tabId + frameId + documentId + origin
expiresAt
```
### 10.2 Agent 工具
不要把几十个 Bridge RPC 原样暴露给模型,也不要提供通用 `method + params` 工具。首批提供三个领域工具:
```text
browser_observe
page summary / actionable nodes / trace / inference / status / diff
browser_inference
list candidates / inspect evidence / arm capture / choose callable /
propose mapping / compile candidate / local replay
browser_act
stable node action / tab activation / human handoff
```
工具回调从当前 AI task 的 `browser_session` 资源解析绑定,AI 参数中不存在 `deviceId``grantId` 或任意 Bridge method。
`browser_observe` 默认只读;`browser_inference` 的读取和推断无需额外确认,arm debugger、创建 callable 和发布 Profile 使用现有细分 scope`browser_act` 遵循 Agent review policy 和人机接管状态。
### 10.3 AI 输出 Schema
AI 只能返回候选补丁:
```ts
interface AIInferencePatch {
candidateId: string
labels: Array<{ evidenceId: string; role: SemanticRole; reason: string }>
preferredFrameId?: string
argumentBindings?: Array<{ slotId: string; contextPath: string; reason: string }>
suggestedBuiltins?: Array<{ operation: BuiltinOperation; evidenceIds: string[] }>
unresolved: string[]
}
```
Candidate Merger 必须验证所有 ID 存在、document 未变化、操作在白名单内、映射路径合法。验证失败只产生新的待处理项,不能退化为执行 AI 代码。
## 11. UI / UX
录制是入口,自动推断是录制完成后的主结果。三列工作台保持不变:
```text
Trace 列 | 数据流与候选 | 推断证据 / 下一步
```
右侧主区域按状态显示:
- `ready`:一键生成 Profile
- `capture-required`:解释原因并提供“自动捕获完整加密流程”;
- `mapping-required`:只让用户选择少量无法确定的明文字段;
- `insufficient-evidence`:建议重新录制,并明确缺少哪类证据。
证据采用三种强度:
- 已证实:实线和明确措辞;
- 有支持:普通文本并展示依据;
- 待确认:虚线或次级文本,不使用成功色。
AI 是候选的解释者,不单独占据一个聊天面板。主要入口是“让 AI 深入分析”,结果回填到同一证据区域。需要继续对话时再打开 Yakit AI 会话,并携带相同 `browser_session` 资源。
手工 Pipeline 编辑器移入“高级编辑”,默认只展示推断出的可读流程和少量可修改字段。
默认 Profile 编辑器不是节点画布,而是三个业务决定:
```text
1. 明文从哪里来
2. 交给哪个页面函数
3. 线上结果写到哪里
```
当第三步选择“写入表单字段”并填写 `encryptedData` 时,编译器自动生成
`form.compose(keys=["encryptedData"])`、固定 Content-Type、Header 输出和 Body 输出。用户不需要看到或填写
`keys`、节点 ID、输入引用和输出引用。已有非规范 DAG 不会被静默改写,只能继续在高级模式中编辑,或由用户明确替换为引导流程。
## 12. 性能预算
- 单次快照最多 500 事件、每事件 48 个 evidence
- 图构建使用 fingerprint/path 索引,目标复杂度 `O(E + V)`
- normalized link 每值最多生成 8 个白名单变体;
- 候选最多 16 个,发送给 AI 的候选最多 3 个;
- scope 每次最多 8 个 frame,源码片段按需读取并限制总字节;
- 推断结果按 `recordingId + event revision` 缓存,增量追加事件时只处理新增部分;
- 不在页面主线程执行全量源码搜索、AST 构建或全局 JSON/URL 编码 Hook
- Pipeline 在目标 document 内一次执行完成,每次请求/响应只跨扩展到页面边界一次,不按节点往返;
- 页面暂停路径绝不等待网络或 AI。
## 13. 隐私与授权
- 默认推断只使用指纹、类型、长度、路径、算法摘要和源码位置;
- 敏感录制预览即使被用户开启,也不自动进入 AI context;
- Key、IV、CryptoKey 和闭包值只显示语义、类型与长度;
- 源码片段可能包含硬编码 secret,发送 AI 前先进行字面量脱敏并由用户授权;
- 推断读取使用 `browser.recording.read`
- scope/source 深入读取使用 `browser.debugger.read`
- arm/resume 与 callable 创建使用 `browser.debugger.control`
- callable 创建、执行与本地回放使用 `browser.callable.execute`;从暂停 frame 捕获 callable 还需要 `browser.debugger.control`
- Profile 发布使用 `browser.transform.manage`
- document、origin 或 grant 变化后候选立即标记 stale,不静默重绑。
## 14. 生命周期与恢复
Profile 是 document-bound。刷新后不能继续调用旧闭包,但推断定义可以保留为恢复计划:
```text
页面刷新
-> callable stale
-> Profile disabled
-> 插件按原 operation / script / route 重新 arm
-> 用户正常执行一次业务操作
-> 重新捕获 callable
-> 本地样本校验
-> 用户确认后重新启用
```
恢复计划不保存 key 或源码计算结果,只保存捕获入口、业务 frame 特征、参数语义和映射结构。
## 15. 分阶段实现
### P0:证据与候选基线
- [已完成] 使用统一 `crypto` 事件记录 WebCrypto / CryptoJS / JSEncrypt / sm-crypto / node-forge 的 adapter、provider kind、family、调用、参数角色、类型、长度和 state/retained 状态;
- [已完成] MAIN-world 密码适配器注册表支持稳定 adapter 与运行时晚加载 adapter
- [已完成] JSEncrypt RSA encrypt/decrypt/sign/verify 保留真实 receiver,并仅输出公私钥类型、位数和加盐指纹;
- [已完成] 为 CryptoJS 结果补充安全的字符串表示 evidence;
- [已完成] 从 exact link、请求字段和调用顺序生成只读候选;
- [已完成] Options / Yakit 展示置信度、证据和缺失步骤;
- [已完成] 候选结构可通过 `browser.recording.get` 提供给 Agent。
### P1:统一 Callable 与 Pipeline v2
- [已完成] 删除 recipe / adapter 双模型,不保留旧方法别名或迁移分支;
- [已完成] 页面 callable 使用统一注册表、来源信息、生命周期和命名 input slot schema
- [已完成] Pipeline v2 使用有序 DAG,并加入类型化 context.read / builtin / page.call / output.write 节点;
- [已完成] builtin 限定为 JSON、文本、URL、Base64、Hex、对象和表单组合白名单;
- [已完成] 输出支持 body、字段级 body、header 和 query,并由 Yak 二次限制 URL 只能改变 query;
- [已完成] 单条 exact value link 且保留可执行调用句柄的 stateless/receiver 模式可直接编译候选;stateful/stream 模式必须捕获上层 callable
- [已完成] 同一请求的多个密码来源合并为 request-level candidate,并强制捕获上层业务 callable 以保持动态值关系;
- [已完成] JSON 字段、表单字段、Header、Query 和完整 Body 会编译为对应的引导式输出,不要求用户理解 DAG;
- [已完成] 录制短时样本自动填入 Options/Yakit 明文网关本地回放,并允许编辑后恢复原样本;
- 为页面内回放生成确定性/结构性断言。
### P2:自动业务函数捕获
- [已完成] 候选一键 arm,并在已有捕获等待或页面暂停时拒绝覆盖;
- [已完成] 业务 frame 使用来源、边界距离、函数可解析性、副作用、命名和作用域信息做确定性排序;
- 参数槽位与 request context 自动映射;
- 文档刷新后的引导式重新捕获。
### P3Yak AI Agent
- `browser_session` attached resource
- task-bound 三个 Agent 工具;
- AIInferencePatch schema 与 Candidate Merger
- Yakit 从候选直接启动带上下文的 AI 会话;
- Agent 操作写入现有 session timeline。
### P4:复杂应用
- Axios/interceptor、GraphQL、WebSocket frame、protobuf 与自定义 serializer
- [已完成] 按通用化路线迁移 adapter host,加入 sm-crypto、node-forge 与 Beacon/Worker/MessagePort 边界,并通过随机 ESM + WASM holdout
- jsrsasign、jose 与后续现代密码生态按真实样本继续推进;
- sourcemap 存在时的业务 frame 增强;
- 多候选对比和跨操作共用 callable 识别。
P4 的实现顺序、协议草案、性能门禁和随机化测试矩阵以 [`FRONTEND_CRYPTO_GENERALIZATION_ROADMAP.md`](FRONTEND_CRYPTO_GENERALIZATION_ROADMAP.md) 为准。
## 16. 验收夹具
至少覆盖:
1. 固定 CryptoJS AES,混淆变量名,JSON 字段输出;
2. 真实 JSEncrypt RSA + form-urlencoded `data` 字段,独立服务端用私钥解密验收;保留实例 receiver,停止录制后对象明文仍可回放;
3. RSA 候选和 AI 上下文只包含 key 类型、位数与加盐指纹,不包含 PEM 或模数;
4. WebCrypto AES-GCM + HMAC,闭包内不可导出 key 和动态 nonce/IV
5. AES + RSA + HMAC 同请求多来源图,不允许拆分低层调用回放;
6. 动态 key promise,页面刷新后重新捕获;
7. Axios interceptor 中的请求签名;
8. Form URL encode 和 Header signature
9. 自定义业务 wrapper,低层库调用不足以构造完整报文;
10. 未知函数与多个同分业务 frame,AI 只能补全候选,不能直接执行代码;
11. WASM 导出函数,只能观察输入输出和业务 wrapper;
12. 敏感预览开启时,AI payload、审计和诊断仍不含原始值;
13. 500 事件 / 24,000 evidence 的性能与内存预算。
## 17. 目标目录
```text
src/features/browser-recording/
evidence.ts
recorder.ts
src/features/browser-inference/
graph.ts
normalize.ts
rules/
candidates.ts
compiler.ts
ai-context.ts
src/features/browser-callable/
registry.ts
execute.ts
lifecycle.ts
src/features/browser-transform/
pipeline-v2.ts
profile.ts
replay.ts
```
Yak 侧将 `browser_session` 资源解析和 Agent 工具放在独立包中,依赖一个最小的 Bridge caller interface,避免 `common/ai` 直接依赖 gRPC Server。