stderr 的 JSONL 是无主人在场的落盘面,却在此前原样落工具结果(result)、 子代理回复(text/summary)与上游报文,等于一次 tail 就能拷走整段对话。 本切片交付两件地基: 1) 写侧脱敏(trace.JSONRecorder) - 新增 trace/span_props.go:safePropKeys 白名单与 projectSpanProps 投影, 读侧(safeSpanProps)与写侧共用同一张表、同一个投影函数; - WriteSpan 落盘前经 trace.SanitizeRecord 投影:白名单键清洗,表外键只留 Digest(bytes/runes/sha256 前缀,收进 omitted),事件先 RedactEvent 再把 正文键折成 Digest。落到磁盘的只有元数据,正文一个字节都不留; - 新增 trace/digest.go:Digest/DigestOf/DigestOfValue,给「脱敏后仍要能诊断」 一个构造上不含正文的取值形态(体积 + 指纹),两条投影都按类型放行它。 2) 共享上游错误体收敛 helper(给 M41/M42,禁止三家各写一份) - trace.UpstreamError(upstream, status, contentType, body):只保留 status / contentType / bodyLen / body sha256 前缀 / 上游 JSON 的 error.code / error.type / 截断 128 rune 的 error.message,其余一律丢弃,响应体原文绝不 进 error 或日志;*UpstreamErrorInfo 提供 Error()/Attrs()/Unwrap()(errors.Is 可判 ErrUpstream 走降级链); - trace.HostOf / trace.MaskQuery:日志里的 URL 只回来源,凭据类 query 与 fragment 值打码为 ***,user:pass@ 整段打码。 3) 剥掉三处正文上 span - loop:tool span 不再放 result,改放 result_summary(与 tool_execution.end 帧同源、已脱敏截断)与 result_digest; - orchestration:subagent span 不再放 text,subagent.done 事件不再放 summary, 改记 status/steps/chars/sha256; - automations:AddRuleByName 不再 %v 整个 payload,改记 subject/type/bytes/sha256。 测试:以哨兵正文在落盘字节上断言(JSONL / slog 输出),并分别对「编排层收到的 原始 span」与「写侧投影」两层各钉一遍;UpstreamError 用回显 input 的 422 报文 与 HTML 错误页各钉一条;解析出/未解析出 JSON 都不回原文。以上均做过变异验证 (去掉保护即变红)。 验收:go build ./... + go vet ./... + go test -count=1 ./... 全绿; trace/loop/orchestration 另跑 -race 全绿。
- 11.4.2:三类节点首次真进图 —— memory.recall/memory.write(loop/memory.go 召回与写入点)、 guardrail.input/output(流式主路径两侧 + agent.RunStep 静音路径)、orchestration.spawn (scheduler 每次派发/收束);新增 trace.ChildSpan 让不持有 Tracer 的叶子包也能开子 span - 11.4.3(设计先行,规格先写进 design/19 §1.1):tool 节点参数摘要 —— 放行表 argValueKeys + trace.IsSecretKey 统一判据(密钥类键不给值)+ 单值 80 rune / ≤24 条 + 出图前再清洗; 前端 NodeDetail 新增「参数摘要」区,未放行键显示「值未展示」 - 13.4.1:流式主路径输出侧护栏改后台 goroutine(脱离 context、30s 兜底、不阻塞回合), 输入侧仍在模型调用前同步拦下;拦截闭环到 guardrail 节点 + 审计事件 - 拆文件:scheduler.go 加 span 后 546 行 → 编排 span 助手拆出 scheduler_spans.go(回到 492) - 契约:无帧名/事件形状变化;graph_update 节点 props 新增**可选**键(tool args_keys/args_summary、 guardrail action/allow/elapsed_ms、memory action/scope/hits/…、orchestration subagent/persona), 文档同步由主会话统一落
执行方案 DevDocs/audit/_plan.md 阶段 0 · G0-B:该文件距 500 行红线仅 29 行,而后续 11.4.2(memory/guardrail/orchestration 三类 span 生产者)等改动必然推进它 ⇒ 先拆。 - graph.go(159):对外类型与快照 API(FlowStatus* / FlowNode / FlowEdge / FlowGraph / NodeSpec / RunGraph;NewRunGraph / Start / SeedInput / SeedOutput / Snapshot) - graph_build.go(245):构图与折叠(Upsert / rememberParent / laneOf / merge / addEdge / AddSpan / AddSpanStart / kindForSpan / labelForSpan / statusForFinished) - graph_props.go(77):prop 白名单与脱敏(safeSpanProps / safePropKeys / summarize / truncate) 纯搬移机械证明:拆前与拆后(取非空、非 package、非 import 块行)排序后 **md5 相同、 diff 为空**;声明集合 28 条守恒;唯一新增文本 = 两个新文件的 package 行与 import 块。 `safePropKeys`(含 4bf1f7c 刚加入的 "persona")原样落在 graph_props.go,逐字节未动。 验证:go build/vet 绿;internal/runtime/trace + internal/services/gateway 测试绿(含 graph_persona_test 与 flow_update_ws_test 的 graph_update 线上帧成对契约回归); linux/amd64 + darwin/arm64 交叉编译绿;三文件 159/245/77 行均 ≤500;gofmt -l 无输出。
4bf1f7c