审计(DevDocs/audit/11-trace-observability.md 发现 #1):scheduler 用 span.SetProp("persona", sub.PersonaID) 设了这个 prop,api-client v0.47 也已把它写进 对外承诺,但 trace/graph.go 的 safePropKeys 白名单不含 "persona",而 safeSpanProps 只遍历白名单 ⇒ 该键在到达客户端前被静默丢弃(实测:整个 props 键都消失)。 修法:把 "persona" 加进 safePropKeys,并在同处写清它为什么可以前送 —— ① 它必然是注册表校验过的角色 id(scheduler.checkPersona 未知 id 一律 ErrUnknownPersona 拒绝整批派发);② 它本来就随 GET /personas 与 message_persisted.personaId 对外可见; ③ 值仍过 redactValue → RedactText(凭据形状清洗 + 80 rune 截断)。 测试:新增 trace/graph_persona_test.go(真 Tracer → 真 SetProp → 真 Snapshot,两条断言: 有 persona / 不指定角色时键不出现 = 钉住 v0.47 的"纯增量")+ 网关 flow_update_ws_test.go 追加 TestFlowGraphUpdateRelaysPersonaProp(真 bus Publish → 真 WS 帧 → 断言帧内节点 props.persona=="yuki")。 验证:go build/vet 绿;trace + gateway 包测试绿;全树 go test ./... = 58 包 ok / 0 FAIL; linux/amd64 + darwin/arm64 交叉编译绿;gofmt -l 干净;三文件 471/57/370 行、最长函数 64 行。 变异验证:把 persona 从白名单摘掉 → 两条断言分别 FAIL(trace 层 props 为空; WS 帧里 span-sub 节点的 props 键整个消失),还原后复绿。 遗留(登记):前端尚未消费该键(flow 节点未显示"以谁的身份替班")。
主人 2026-10-03 拍板「注释一律中文」;gateway 至此整包注释中文化完成(本会话共 3 批: 已推库 16 个文件 + 本批剩余文件)。 校验:机械校验(非注释改动行)= 空;剥注释后代码文本逐行比对全等(不一致文件数 0); 全树 go test ./... 58 包 ok / 0 FAIL;交叉编译绿。
`#/admin/flow` 报障调查发现:flow 链路每一环都是对的(loop 的 FlowPublisher 三入口 在真实回合里都被调用 / wire.go 的 allow 白名单正确 / parseGraph 与 Snapshot 字段逐条对得上), 但**「bus 的 ws.graph_update 经 ws_bridge 中继成 WS 帧」这一跳此前完全没有测试**—— 逐环人工核对永远核不到它。补两个契约测试把它钉死: - TestFlowGraphUpdateRelayedToWS:真 bus Publish("ws.graph_update", <真 trace.RunGraph.Snapshot()>) → 断言 WS 收到 graph_update 且数据逐字节未被改写 - TestFlowGraphUpdateWireFields:精确断言 graph/node/edge/log 四层的 key 集合 = 前端 parseGraph 读取的那一套(改名/多字段/少必填都 FAIL) 验证:go build/vet 绿;-race 网关 ok;全量 58 包 ok / 0 FAIL;交叉编译绿。 变异验证:① 改 trace.FlowNode.Label 的 json tag → 键集断言 FAIL; ② 让 ws_bridge 的 normalizeEvent 丢掉 ws.graph_update → 中继测试 i/o timeout FAIL。