外观
11 · 数据与持久化
What lands on disk
插件运行态共六个文件(paths.ts:L202 RUNTIME_STATE_BASENAMES 六员:history.jsonl / audit.jsonl / approval-debug.jsonl / review-mode.json / llm-latency.jsonl / learning.json)——这名单同时是保护对象:任何工具调用改写它们都会被静态引擎无条件硬拒。
11.1 四条 JSONL 的真实形态(取自本仓库现网样例)
11.1.1 history.jsonl(推论可搜、可清空)
json
{"sessionId":"session-…c2a8","toolName":"bash",
"outcome":"allowed-once","source":"timeout-allow",
"llmDecision":"ESCALATE","id":"hmt2rrtff_ccr1k1",
"at":1787305877691}字段全集(index.ts:L735-753):id / at / sessionId / toolName / outcome / source / llmDecision? / llmRisk? / llmReason?(先脱敏)/ attempts?(重试时逐次失败轨迹)/ breaker? / breakerReasons? / 类别三字段 category? · categoryDecision? · mode?。写入走 pushHistory(index.ts:L798-822):llmReason 先过脱敏 → 内存窗口 200 条 → history.jsonl 追加、>1MB 用内存窗口重写轮转;同一条再以 type:'decision' 落进审计。启动时 loadHistory 恢复。
11.1.2 audit.jsonl(append-only,清空留墓碑)
json
{"type":"decision","sessionId":"…",
"toolName":"bash","outcome":"allowed-once",
"source":"timeout-allow","llmDecision":"ESCALATE",
"id":"hmt2rrtff_ccr1k1","at":1787305877691}
{"type":"clear","at":…,"cleared":6}pushHistory 每次附带写一条 type:'decision';UI 清历史只清内存+history 文件,审计只剩墓碑。>5MiB 保尾 5000 行。查询:node scripts/audit-query.mjs [--last N | --tool X | --session S | --source S | --since ISO | --json]。
11.1.3 review-mode.json(每会话评审模式)
json
{
"session-…c2a8": "manual",
"session-5fb…e3a2b": "unattended"
}只存非默认(≠smart)的会话;原子 tmp+rename;损坏非致命。会话销毁自动删键,文件不会无限变大。
11.1.4 approval-debug.jsonl(仅 debug=true)
json
{"at":…,"ev":"request","callId":"…","toolName":"bash","sessionKey":"…"}
{"at":…,"ev":"review","callId":"…","decision":"ESCALATE",
"risk":null,"startAt":…,"tookMs":14,"scope":"medium"}
{"at":…,"ev":"resolve","callId":"…","outcome":"allowed-once",
"timedOut":true,"source":"timeout-allow","auto":false,
"seconds":8,"elapsedMs":8011,"requestToResolveMs":8014,
"llmDecision":"ESCALATE"}事件点:request / review / follow / review-error / resolve。用来回答「LLM 到底看没看、看了多久、说了什么」——区分超时误标与真实延迟。>1MB 保尾 2000 行。
11.1.5 llm-latency.jsonl(评审耗时遥测,与历史分离)
json
{"at":1787480239339,"tookMs":1928,"settled":true}
{"at":…,"tookMs":8011,"settled":false,"attempts":2}独立于审批历史:历史记「裁决事实」,耗时是性能遥测——被打断的调用(倒计时超时/网络失败/解析失败/无路由)没有历史记录可挂,回写就会伪造裁决。所以它住自己的环形缓冲(内存 200 条,latency.ts:L47)+ 同款 append+轮转文件(>1MB 重写,latency.ts:L109),损坏行跳过。样本二分:settled=true 才是真响应时间;aborted 是等待上限,永不混入 MIN/AVG/MAX(UI 汇总窗口最近 100 条,单列「超时/无响应」计数)。
11.2 learning.json(确认制学习条目)
json
{"version":1,
"entries":{"<sha256>":{"sigVersion":1,"workspace":"C:\\ws\\proj",
"kind":"shell-bash","skeleton":"git push --force-with-lease <in:path>",
"count":3,"firstAt":…,"lastAt":…}}}- 键:SHA-256(
sigVersion|kind|workspace|signature)(learning.ts:L221-223)——签名是确定性整行模板(§18),不含任何原始值。 - 骨架卫生:模板先过
redactSecrets再落盘,且只允许字符白名单、长度 ≤512(learning.ts:L64-65)。 - 回收:TTL 默认 30 天、上限默认 100 条,按
lastAtLRU 逐出(evictLearning,learning.ts:L305-315);关闭开关不清数据。 - 写入:同步
tmp + rename原子替换(persistLearning,learning.ts:L339-347),best-effort,进程内副本兜底。 - 隔离:查找要求
entry.workspace === 当前工作区精确相等(learning.ts:L401)——一个项目学到的放行资格不会带到另一个项目。
TIP
审计刻意存普通文件而非会话 user/message 事件:主模型永远无法把它读回来当成提示注入通道,同时保证「清空可恢复」。