Flyto Agent - 细节补齐清单¶
归档: 已完成的 815 项见 TODO_DONE.md. 本文件只列当前未完成的 11 项, 加速日常读取.
每个细节都是"专业"和"玩具"的差距.逐一补齐,不留历史债.
优先级说明¶
- 🔴 P0:安全/准确性 - 不修就是漏洞
- 🟡 P1:功能完整性 - 不修就是残缺
- 🟢 P2:体验/性能 - 不修就是粗糙
- ⚪ P3:扩展性 - 不修就是僵硬
模块 0:可观测性基础设施 ✅¶
0.1 EngineObserver 接口体系 ✅¶
0.2 默认实现 ✅¶
0.3 StrictMode 严格模式 ✅¶
0.4 Engine 接入 ✅¶
模块 1:Bash 工具 ✅ 已完成¶
1.1 AST 解析替代字符串分割 ✅¶
1.2 环境变量前缀跳过 ✅¶
1.3 引号感知命令分割 ✅¶
1.4 进程管理 ✅¶
1.5 输出截断策略 ✅¶
1.6 后台运行 (run_in_background) ✅¶
1.7 命令分类 ✅¶
模块 2:FileEdit 工具 ✅ 已完成¶
2.1 Curly Quote 保留 ✅(早期方案精妙设计)¶
2.2 Desanitization ✅¶
2.3 两步验证设计 ✅¶
2.4 文件缓存集成 ✅¶
补完 ✅¶
模块 3:FileRead 工具 ✅ 已完成¶
3.1 图片处理 ✅¶
3.2 PDF 支持 ✅¶
3.3 Jupyter Notebook ✅¶
3.4 设备文件阻止 ✅¶
3.5 路径安全 ✅¶
模块 4:Glob & Grep ✅ 已完成(升华重构)¶
4.1 双引擎策略 ✅(升华设计)¶
4.2 多行匹配 ✅¶
4.3 类型过滤 ✅¶
4.4 分页 + 排序 ✅(升华设计)¶
4.5 安全加固 ✅(G8-D review)¶
模块 5:权限系统 🔴¶
5.1 自动模式分类器 ✅¶
5.2 Compound 命令完整处理 ✅¶
5.3 Sed 脚本验证 ✅¶
5.4 重定向目标分析 ✅¶
5.5 权限决策缓存 → 规则应用管道 + 去重 ✅¶
模块 6:上下文压缩 ✅¶
6.1 压缩后恢复精细度 ✅¶
6.2 消息分组 ✅¶
6.3 压缩前图像移除 ✅¶
6.4 多策略压缩 ✅¶
6.5 三层压缩降级 + 断路器改进 ✅¶
模块 7:查询循环 ✅¶
7.1 消息规范化管道 ✅(升华重构)¶
7.2 stop_reason 完整处理 ✅¶
7.3 Tool Result 配对修复 + 可观测性基础设施 ✅¶
7.4 Token 预算精细度 ✅¶
7.5 查询链追踪 ✅¶
7.6 查询循环防御性 ✅¶
模块 8:API 客户端 ✅¶
8.1 错误分类精细化 ✅¶
8.2 重试策略完善 ✅¶
8.3 API 预连接 ✅¶
8.4 SSE 边界情况 ✅¶
模块 9:Hook 系统 ✅¶
9.1 Hook 输出影响行为 ✅¶
9.2 pre/post-sampling hook ✅¶
9.3 插件级 Hook 注册 ✅¶
模块 10:Memory 系统 ✅¶
10.1 路径遍历防护 ✅¶
10.2 团队记忆同步 ✅¶
10.3 自动提取代理 ✅¶
10.4 新鲜度警告 ✅¶
模块 11:MCP 客户端 ✅ 已完成¶
11.0 工具名格式统一 ✅¶
11.1 Transport 接口 + 多传输支持 ✅¶
11.2 Client 重构 ✅¶
11.3 Schema 转换完整性 ✅¶
11.4 资源预取和缓存 ✅¶
11.5 Elicitation 处理 ✅¶
11.6 MCP 防御性 ✅¶
模块 12:Plugin 系统 ✅(核心完成)¶
12.1 依赖解析 ✅¶
- [N/A] 语义版本约束(^1.0.0, ~1.2.3)- 不做.插件模型是叠加式(无代码级耦合), 版本约束需要 registry + 多版本共存,生态尚不存在.官方插件全部无相互依赖印证此判断. minEngineVersion 待引擎 API 稳定后再考虑.
12.2 LoadResult + 结构化错误 ✅¶
12.3 Claude Code 格式兼容 ✅¶
12.4 SDK 内置注册 ✅¶
12.5 Plugin 完整性校验 ✅ (原 DXT/MCPB Bundle, 2026-04-15 反转重命名)¶
12.6 插件配置 Schema ✅¶
12.7 Plugin 声明式 tool 注册 ✅ (2026-04-15 新增)¶
- 驱动: 产品经理 2026-04-15 对话纠正: 原话"注册 tool 本来就是现成的功能", 指出 commit 58c3ab5 的"plugin 只能通过 MCP server 间接暴露 tool"是不完整 framing. tools.Registry.Register 本就是公开接口, plugin loader 只需补一层 manifest → pluginShellTool → Register 的数据翻译即可. 本 commit 填补了这个功能缺口.
12.8 Plugin MCP server engine 集成 ✅ (2026-04-15 新增)¶
- 驱动: 上次对话 073da52 LSP 审计发现 engine 层 pluginHost 和 toolsRegistry 的 MCP wiring gap: Plugin.Hooks 有 syncPluginHooks, Plugin.Tools 有 syncPluginTools, 但 Plugin.MCPServers 无对称 sync 方法. internal/mcp 已有完整 5647 行 Manager+Client+Transport, 本任务是纯 wiring 不是造轮子.
模块 13:Agent 子进程 ✅¶
13.1 预定义代理类型 🟢¶
13.2 工具过滤精细度 🟢¶
13.3 Prompt Cache 共享 ✅¶
13.4 工具权限精细控制 ✅¶
模块 14:Skill 系统 ✅¶
14.1 SkillDef + SkillRegistry ✅¶
14.2 Frontmatter 完整支持 ✅¶
14.3 文件发现 ✅¶
14.4 Inline/Fork 执行 ✅¶
14.5 SkillTool ✅¶
14.P1 ✅¶
模块 15:系统提示词 ✅¶
15.1 PromptBundle + BundleRegistry ✅¶
15.2 缓存边界优化 ✅¶
15.3 默认 Bundle(claude+programming)✅¶
15.4 SDK 扩展 API ✅¶
15.7 中文 Bundle ✅¶
15.6 P1 补充 ✅¶
15.5 测试 ✅(47+ 测试)¶
模块 16:AutoDream(记忆巩固)✅¶
KAIROS 系统核心.与 C 方案自进化直接关联 - Dream 整理记忆,自进化基于记忆改进.
16.1 Dream 引擎 ✅¶
16.2 Dream 四阶段提示 ✅¶
16.3 DreamTask ✅¶
16.4 Stop Hook 集成 ✅¶
16.5 SubAgent 扩展 ✅¶
模块 17:UltraPlan(高级计划模式)✅¶
17.1 计划生成(P0)✅¶
17.2 计划步骤(P1)✅¶
注:17.3 远程计划移至模块 20,仅适用于本地进程(CLI/SDK本地部署)提交计划到守护进程执行.
模块 18:Coordinator Mode(多 Agent 协调)✅¶
18.1 协调器角色 ✅¶
18.2 任务通知 ✅¶
18.3 Scratchpad ✅¶
18.4 Worker 生命周期 ✅¶
模块 19:Bridge Mode(远程桥接)✅¶
实现位置:platform/pkg/bridge/(平台层,非引擎层) 架构决策:v1/v2 是 Anthropic 私有云协议,不复刻;改为通用 BridgeTransport 接口.
19.1 核心接口 ✅¶
19.2 消息去重与批量上传 ✅¶
19.3 SSE Transport ✅¶
模块 20:Daemon Mode(守护进程)✅¶
实现位置:platform/pkg/daemon/(平台层,非引擎层) 架构决策:Go goroutine pool 替代 Node.js 子进程;Idle Timeout 替代固定 24h.
20.1 会话生命周期管理 ✅¶
20.2 健康检测 ✅¶
20.3 远程计划(来自17.3)🟢 ✅¶
适用于本地进程(CLI 或 SDK 本地部署)提交计划到守护进程执行. HTTP API 不需要此功能--服务端本身就是执行方,客户端调用即是"远程".
Platform HTTP API Server ✅¶
实现位置:
platform/pkg/server/server.go(平台层,在引擎层之上) 对应:PLATFORM_TODO.md §1.1 HTTP API Server P0 全部完成
模块 21:UDS Inbox(进程间通信)🟢¶
21.1 内存 Inbox(同进程通信)✅¶
21.2 消息协议 🟢¶
模块 22:精妙细节(从早期方案深度分析中发现)✅¶
这些是产品级和玩具级的分水岭.
22.1 API 交互细节 ✅¶
22.2 缓存和性能细节 ✅¶
22.3 安全细节 ✅¶
22.4 消息处理细节 ✅¶
模块 23:SQL 工具链 ✅(2026-04-23)¶
面向 staging / 影子表的三件套. AI 写业务 DB 走 "Agent → staging → ML 审批 → WMS API 写生产" 三步流程 (memory
project_db_ai_relationship.md) 中的 staging 一跳. TODO.md 之前把这三条归在 "消费层待实现不属于引擎层" 是 2026-04-08 立项时的保守判断; 实际业务逻辑 schema-agnostic / driver-agnostic, 通过 StagingDB newtype + *sql.DB DI 让客户端注入 driver, 引擎层仅 importdatabase/sql标准库, 零生产第三方依赖, 所有客户复用.
23.1 SQL 只读校验器 ✅ (commit 79670c7)¶
- 纯字符串解析, 零 DB 依赖
- 规则: 非 SELECT/WITH/EXPLAIN 拒 / 多语句拒 / LIMIT 可注入或校验 / 表名白名单
- quote-aware 扫描 (字符串 / identifier quote 内的
--和/*不被误识) - schema-qualified 表名 (
public.orders) 支持
23.2 SQL CAS 乐观锁 ✅ (commit bf31278)¶
StagingDBnewtype +NewSQLCASTool(db, maxRetries)DI (构造处强制显式声明 staging 作用域)- maxRetries 默认 0 (fail-fast; AI Agent 看 version 冲突应重 plan 非 silent retry)
- version 非 int 运行时 reject (避免 timestamp / CDC 复制场景 silent 失效)
- identifier
[a-zA-Z_]\w*白名单拒 quoted, 所有 value 走?参数化防注入 modernc.org/sqlitetest-only dep (core 第一条非图像处理第三方依赖, 仅_test.goimport)
23.3 SQL Dry-run 三路 ✅ (commit a935604)¶
- 方案 E (before + after 都 SELECT), UPDATE/DELETE/INSERT 按 operation 刻意不对称
- LLM 传
preview_predicate(工具不 parse SQL), 一致性检查标mismatch/after_predicate_mismatch信号 - 100 行 truncate 显式提示 (非 silent sampling 的 approval theatre)
DryRunResult3 字段首次 write point (SQLDryRunTool 填), 外部 UI / audit 反序列化消费 (pull API 归档状态保持不变)
基础设施层(服务端能力)🔴¶
早期方案是客户端,背后有 Anthropic 服务端.我们是客户端+服务端,必须自建这些基础设施. 原则:涉及代码面越广的越先做,否则后面改动太大.
INF-1 可观测性(EngineObserver)✅(与模块 0 相同,详见顶部)¶
INF-2 文件历史/回滚 + ToolCapability 协议 ✅¶
INF-3 优雅关闭 ✅¶
INF-4 会话活动追踪 ✅¶
INF-7 引擎竞态修复 ✅(2026-04-07)¶
INF-5 安全审计 ✅¶
INF-6 版本兼容 ✅¶
INF-7 数据安全(文件/DB/API 三维度)📄 文档完成¶
文档:
docs/data-safety.md(已完成,含凭据安全章节) 代码:消费层实现,引擎层接口已就绪
引擎层--框架质量修复(代码审查)¶
引擎层--凭据安全¶
引擎层--SDK 编排能力¶
- [x] 🟡 L952b → L407: platform 消费层文档自动化三件套 ✅(2026-04-26, commit C0-C6:
89c38d3C0 path bug fix/v1/* → /api/v1/*(Caddyfile + ADR-0002 + server.go 8 mux 路由 + server_test.go ~25 处 + main.go 注释);26bc732C1 server.go 8 handler swag 注解 + 3 named response type (HealthResponse/StatusResponse/ListToolsResponse) 替代 ad-hoc map + swag.go seed file + docs/{swagger.json 22.5K 12 schema, swagger.yaml 12.3K, docs.go 23.1K Go embed} 首版;bce7670C2 cmd/common --swagger flag + Swagger UI endpoint (httpSwagger v2 + side-effect import docs, authMiddleware/rateLimit allow-list 加 /swagger/);22b6388C3 core/Makefile 4 docs target (docs-swag/docs-grpc/docs-consumers/docs-all) + tool install pin (swag@v1.16.6 + protoc-gen-doc@v1.5.1) + grpc-api.md 首版 278 行 + .gitea/release.yml docs drift gate (apt-get protoc + make docs-install + docs-swag/grpc + git diff --exit-code);a9b04abC4 docs/CONSUMERS.md 顶层 wrapper 133 行 (端口拓扑/env/flag/OIDC auth 流程图/业务 REST 一次性+多轮会话 curl 例子/观测 gRPC SafetyChain 指引/进一步阅读链);bf5af1dC5 Caddyfile handle /swagger/ → common:8080 + docker-compose --swagger flag (HK-133 lab 默认开, 生产另份 compose 关); 本 commit C6 TODO/CHANGELOG/CLAUDE.md 同步). 三件套全产: 业务 REST → docs/swagger.{json,yaml,docs.go} (12 schema, swag init 产物); 观测 gRPC → docs/grpc-api.md (HealthService + SafetyChainService 字段表); 顶层 docs/CONSUMERS.md (133 行 wrapper, 链 swagger.json + grpc-api.md 不重复). CI drift gate 在 release.yml dead-field-ratchet 后插, push tag 时 install protoc + swag + protoc-gen-doc 跑 docs-swag/docs-grpc + git diff --exit-code, 偏差 fail tag 构建 (业界对照: Stripe / Anthropic / OpenAI 都对 OpenAPI spec 跑同等闸). 意外+顺手修 (C0): 上一会话 commit 5 (c35e761) Caddyfilehandle /api/v1/*不剥前缀, server.go mux 注册/v1/*不匹配, 经 hub.flytoex.net 全 404, L407 之前先打通真实部署链 (memoryfeedback_validate_network_path_before_deploy警告再次成立). smoke: ANTHROPIC_API_KEY=fake go run ./cmd/common --rest-addr=:18080 --swagger → /api/v1/health 200 + /swagger/index.html 200 + /swagger/doc.json 200 返回 commit 1 嵌入 spec; -race 全绿. 不做* (rule of two): SDK 自动生成 (Stainless 模式, 等 5+ 语言客户端); .proto 字段注释完善 (health.proto 部分字段 description 列空, protoc-gen-doc 自动反映, 后续工作). - [ ] 🟢 L952c: 场景化编排 Go 使用教程 (P3, 2026-04-17 拆自 L952). 产出:
core/examples/orchestration/{ssh_deploy,db_migration,system_config}/main.go三个可跑示例 +core/docs/orchestration_scenarios.md指向它们. 演示 Checkpoint / Reversible / DryRun / SecretStore 组合用法. 成本: 500-1500 行 Go. 不紧急: 当前无明确第三方集成需求, 投机未来回报率低. 等有实际集成方催再补不迟.
引擎层(已就绪,无需再实现)¶
CLI TUI 消费层(ccm/tui/ - P0+P1 完成, 新功能冻结 2026-04-15)¶
agent-engine CLI 修复(2026-04-08 发现)¶
server / transport 低优先问题(2026-04-08 Review 发现)¶
- ~~
internal/server/已删除,迁移至 platform/ 从零开始~~
消费层集成测试(2026-04-08 立项)¶
消费层待实现(不属于引擎层,由平台/消费者完成)¶
- [ ] 🟡 ML 验证器接入(diff 序列化 → ML 推理 → 通过/拒绝) — core 接口就绪 (Validator / LLMValidator / CompositeValidator / AlwaysApprove + NewValidatedTool nil fail-fast, 见 L699+). platform 接外部 ML backend 实现 + 装配即可启用.
- [ ] 🟡 熔断器(连续 N 次 ML 拒绝 → 暂停 AI 写权限 + 告警) — core 三态 breaker + VerdictSink 桥接就绪 (commit
3342425). platform 选作用域 (全熔/只熔写/每工具一熔) 并 wire ValidatedTool sink 即可启用. - [x] 🟡 Staging 表管理(决策包级 pending_tech/rejected_tech/pending_ml/rejected_ml/approved/executed/failed 7 状态机 + 混合控制: staging 主动 ValidateTech/Biz + 外部推 MarkExecuted/MarkFailed + 可插拔 DependencyGuard + InMemoryStore 参考实现) ✅(2026-04-24, commit 1/2/3: d9992d5/2c38e46/本 commit). 复用
validator.Validator为两层 slot,reflector.EvaluatorAsValidator适配 Evaluator 接入. pull-only query API. SQL-backed Store 由平台层实现 (contract 见core/pkg/staging/store.go). - [x] 🟡 影子表管理(多轮推理场景:session 级镜像表 + 会话结束清理) ✅(2026-04-25, commit 1/2/3: 2c84209/e140952/本 commit). 方案 C 列标记隔离 (
pkg/shadowdb/): 物理 shadow 表加 session_id VARCHAR(64) NOT NULL 列, 按 session_id filter 做跨 session 隔离. 规避 PG TEMP TABLE 在 pooled *sql.DB 下 temp 表蒸发 + driver 分裂问题. 零 DDL 纯 INSERT/UPDATE/DELETE/SELECT + ? 参数, PG/MySQL/SQLite 通吃. Opener 接口 + InMemoryOpener 参考实现 + pull-only Reap 孤儿 GC (core 不起 goroutine) + EnforceSessionFilter 三层防御中层 (quote-aware string/comment 剥离). 与 staging 边界: staging 决策级 pre-commit, shadowdb session 级推理中 scratchpad; shadow -> staging -> production 单向, shadow 永不 merge. - [x] 🟡 L692: platform/common 业务 REST/SSE 通道激活 ✅(2026-04-26, commit 1-6:
01f08e7/8189d05/694bd07/e1db327/c35e761/本 commit). 3-agent review reconcile (调研 11 LLM API + grpc-gateway / 质疑 6 道硬题 / 设计 4 备选), PM 拍板方案 A 修正版: 激活 server.go 1263 行已写好的业务 REST/SSE + grpc-gateway 砍掉 (admin/server.go 已实现观测面 REST handler) + ADR-0002 立 "REST 业务 / gRPC 观测" bifurcation (与 9 天前 memoryfeedback_architecture_principle_over_rule_of_two.md的 "gRPC 优 HTTP" 是分层不是反悔). commit 顺序:01f08e7C1 server.go 拆 Serve+wrapper 让出 signal handling;8189d05C2 Verifier 替代 BearerToken 走 auth.HTTPMiddleware (raw shared-secret + ConstantTimeCompare 删除, OIDC 与 admin 一致);694bd07C3 Attach + HandlePermission 拆 anthropic provider 写死, server 不再读 ANTHROPIC_API_KEY 不再 hard-code 模型;e1db327C4 cmd/common 加--rest-addrflag 装配 anthropic provider + engine + s.Attach + 第三 listener wire (signal handler 三路协调: grpc.GracefulStop / httpSrv.Shutdown / restCancel);c35e761C5 docker-compose expose 8080 + Caddyfile/api/v1/*(flush_interval -1 + response_header_timeout 0 SSE 透传, ANTHROPIC_API_KEY${...:?...}必填); 本 commit C6 ADR-0002 + TODO/CHANGELOG/CLAUDE 同步. Tool 级安全链装饰刻意不在 cmd/common 装 — 一刀切 AlwaysApprove + DefaultExtractor 会把所有 Tool 锁同一组合或 fan out 到不匹配 Tool 语义的 wrap. common 保持纯 transport, verdictStore 接线就绪, 由行业驱动代码 (logistics 等) 在 Tool 注册时装饰并写数据 (ADR-0002 § Decision 第 3 条记录这个分工). 业界对照: 11 LLM API (Anthropic / OpenAI / Bedrock / Cohere / Mistral / Replicate / LM Studio / Ollama / LangServe / Together / Fireworks) 全单通道 REST/SSE; Vertex AI 是 gRPC-first 例外, 但 GCP transcoding 模式不仿照. ADR-0002 引用 11 框架矩阵 + grpc-gateway / gRPC-Web 现状 + ConnectRPC 替代论证. 测试: server_test.go 既有 546 行用 httptest 直接打 handler 无须改, 4 个 raw bearer TestAuth_* 删除 (auth.HTTPMiddleware 自身覆盖在 internal/auth 包测试), 新加TestServer_Serve_RespectsCtxctx 取消干净返回. -race 全绿. cmd/common binary 集成验证--help显示--rest-addr. 实测 (docker exec curl + SSE chunk timing) 留 push tag 前按 memoryfeedback_validate_network_path_before_deploy走. - [ ] 🟢 AuditSink 数据库实现(写入 PostgreSQL,按 session_id 查询,支持批量回滚)
- [ ] 🟢 WMS 波次建立参考实现(状态机新增"任务已建待确认"状态)
- [x] 🟡 L693: 业务 REST 多副本 SessionStore interface ✅(2026-04-26, commit 1-4:
eec48fe/beaff60/96e893a/本 commit). 3-agent review reconcile (调研 LangGraph/Vercel/Temporal/Express/Django 业界 prior art / 质疑 6 道击中 3 道 / 设计 3 alternatives 选 typed Alt 2), PM 拍板"整个 platform 都 Postgres". 真相: 多副本真阻塞不是 sessions map, 是三层进程内 pin (server.permCh + Session.pendingPermissions + engine.sessionState), 后两层在 core 引擎层平台层不能解, 必须 LB sticky routing; SessionStore 价值降级为"replica 重启不丢元数据 + 滚动部署 drain + Postgres audit". commit 顺序:eec48feC1 SessionStore 接口 (Create/Get/Delete 三方法, 不要 Touch/List 投机) + InMemoryStore drop-in 替换 server.sessions map + 4 handler 改造 + TOCTOU race 折叠 (319 行 + 改 server.go 182 行);beaff60C2 Postgres 后端 +internal/db/共享池 (中央 schema 权威 platformMigrations + Migrate 启动期 idempotent) +--postgres-dsnflag + docker-compose pg service + healthcheck + persistent volume + release.yml POSTGRES_PASSWORD secret + testcontainers-go 真 pg 测试 (~510 行 + 改 main.go 53 行 + docker-compose 48 行);96e893aC3 ADR-0003 (387 行, 8 节, 三层 pin 物理事实分析 + sticky routing phase 1 ip_hash + phase 2 X-Session-ID 升级路径 + cache miss 503 fallback) + Caddyfile 注释 (单副本 vs 多副本部署区别); 本 commit C4 TODO + CHANGELOG + CLAUDE.md 同步. 关键决策: drop Redis 档 (元数据 payload 太薄, 共享 staging pg 池更经济); drop staging Postgres 后端 (PM 接受 YAGNI 跳过, 等 staging 真有消费者再做, ADR-0003 § 5.5 登记触发条件); engine.SnapshotStore 接线 cache miss 自动恢复历史留 follow-up. 不引正式 migration 工具 (1 张表, plain CREATE IF NOT EXISTS 自检足够; 等 ≥ 5 张 + schema 稳定再引). 测试: 6 InMemoryStore 测试 + 5 testcontainers Postgres 测试 + 2 db pool 测试, 全模块 -race 全绿; dead-field-scanner baseline 220 不变 (scanner 只扫 core/). PM 部署侧必做 (v0.4 release 前): Gitea secrets 配 POSTGRES_PASSWORD (跟 ANTHROPIC_API_KEY 同位). - [ ] ⚪ L694: gRPC + REST cross-transport request-id / trace 串通 (P3, 2026-04-26 登记自 L692 ADR-0002 tracked debt). 背景: server.go 自己生成 request-id (server.go:331 getRequestID), gRPC 侧没有. 用户从 logistics C# 发 gRPC ListVerdicts 想看 "我的请求触发了什么 verdict" — request-id 串不起来. 产出: OpenTelemetry trace span 跨 transport 注入 (HTTP header + gRPC metadata), Tempo / Jaeger 一类观测后端落. 成本: 引入 OpenTelemetry SDK + collector / exporter wire, 中等. 不阻塞 v0.3: 当前单租户 dogfood 不需要, 上量后才有 ROI.
- [ ] ⚪ L695: SSE 1000 单/s 带宽监控 (P3, 2026-04-26 登记自 L692 质疑 agent Q1.3). 背景: SSE framing (
event:...\ndata:...\n\n文本) 比 gRPC binary protobuf 多 5-10x overhead. 业界共识 (LLM API 全 SSE) 接受这个代价, 但 logistics 1000 单/s × 平均 20 events/单 = 20K events/s 真上量后跨 region 流量成本要量化. 产出: prometheus exporter 暴露sse_bytes_per_second/sse_events_per_secondmetrics, Grafana dashboard 跟踪. 不优化: 监控只是为了量化, 真到瓶颈再优化 (压缩 / batch / fallback gRPC streaming, 都是 v1.0+ 课题).
INF-8 公共契约包 + Provider 工厂 ✅(2026-04-07)¶
INF-8.1 pkg/flyto 公共契约包 ✅¶
INF-8.2 内部协议适配器¶
INF-8.3 Provider 工厂实现 ✅¶
INF-8.4 SSE 架构重构 ✅(2026-04)¶
INF-8.5 待完成(P1)¶
- [ ] 🟢 P2: provider 静态模型表自动更新工具(爬取 Anthropic/MiniMax/OpenAI 文档页面检测变化)
INF-8.6 能力层(基于探测矩阵驱动引擎行为)¶
核心原则:能力差异在引擎层抹平,消费者写标准代码,引擎负责 provider 适配. 细节决定成败--$ref 展开,schema 约束裁剪,工具数量保护,每一项都是引擎的护城河. 探测数据(2026-04):Anthropic Sonnet/Opus 缓存阈值 1024t,Haiku 4096t,MiniMax ~1024t. OpenRouter → Anthropic 路径 cache_control 无法透传(probe 确认 cr=0@7200t). $ref 双重序列化 bug:MiniMax 直连 + OpenRouter→Gemini 均复现,DeepSeek/GPT-4o 正常.
CAP-1: flyto.Request 意图字段 ✅(2026-04)¶
CAP-2: Provider 自动 Caching 决策 ✅(2026-04)¶
CAP-3: StructuredOut Provider 自适应 ✅(2026-04)¶
CAP-5: Tool Schema $ref 自动展开 ✅(2026-04)¶
probe 实测(2026-04):MiniMax 直连 + OpenRouter→Gemini 均有双重序列化 bug. $ref 字段值返回 JSON 字符串而非 object,下游 map[string]any 拿到 string → 静默数据损坏.
CAP-6: Tool Schema 约束 Provider 适配 ✅(2026-04)¶
各 provider 对 JSON Schema 约束支持不一,消费者写标准 schema,引擎自动裁剪不支持的约束.
CAP-7: Tool 数量上限保护 ✅(2026-04)¶
超出上限直接报 400,消费者无提示.引擎提前检测,给出可读错误.
CAP-8: Schema 复杂度限制保护 ✅(2026-04)¶
OpenAI strict 有隐藏限制,消费者超出时只拿到 400 和晦涩错误信息.
CAP-4: 能力探测自动化 🟢 P2¶
- [ ] 通过 Flyto CLI 无头模式自消费(不依赖外部脚本调用)
- [ ] CI/CD 集成:新模型上线后自动触发探测,更新 capabilities.json
- [ ] 探测前强制 WebSearch 最新文档,规范阈值和测试范围(防止训练数据过期导致参数设置错误)
evolve v0.2+ 接口矩阵实现 🟢 P2¶
战略背景见
docs/evolve-strategy.md. 接口契约已在core/pkg/evolve/interfaces.go落定 (commit bf6c3ad), 本段追踪每个接口的引用实现进度. 引擎只提供文件实现, SQL 多租户实现属 platform 层.
- [x]
ParameterStore--FileParameterStore(本地文件 + 版本化 + Lock + Watch, in-process 订阅) - [x]
Generator--LLMGenerator(窄 LLMClient 抽象 + text/template prompt + JSON array 解析, 支持 markdown 围栏剥离) - [x]
Evaluator--WeightedEvaluator(加权线性, feature/weight 一一校验, raw breakdown, normalize 可选) +FuncEvaluator(非线性 escape hatch) - [x]
Reflector--AggregatorReflector(entity×metric 描述统计 + pending 追踪 + RWMutex 并发安全) +FuncReflector(escape hatch) - [x]
ParameterEvolver--DefaultParameterEvolver(ProposerFunc 注入 + Apply approved/rejected 两分支 + AuditLogger 钩子) - [x]
LogSource--FileLogSource(JSONL + UTC 日期分片 + Append/Read/Days, O_APPEND 原子写) - [x]
LogReplayer--DefaultLogReplayer(懒 per-entity feedback 缓存 + first-touch per-metric 配对, ReplayerOption 模式) - [x]
FeedbackChannel--FileFeedbackChannel(二级分片 entity/UTC-date, Report/Query, url.PathEscape entity) - [x]
ShadowRunner--DefaultShadowRunner(CandidateSampler + ParamApplier 注入, 相对 divergence ∈ [0,1], Meta 审计链路)
代码质量 / 技术债(G1 Review 发现)¶
来源:2026-04-08 G1 Review(session + normalize + audit + worktree 批次)
已修复(本批 5 项)¶
已修复(Session 生命周期 4 项,2026-04-09)¶
待修复(低/中优先级)¶
可靠性¶
规范化管道¶
历史债 / 魔法数字¶
抽象设计(需讨论,不直接改)¶
G2 Review 发现(Dream + Plan + QueryChain + TokenBudget + Elicitation)¶
来源:2026-04-08 G2 Review
已修复¶
待修复¶
并发 / 可靠性
历史债
抽象设计
G3 Review 发现(pkg/engine/ 第三部分:agent/skill/scratchpad/team/observer)¶
来源:2026-04-08 G3 Review
已修复¶
待修复¶
安全
Bug / 可靠性
历史债
G4 Review 发现(memory/context/permission/config/flyto/hooks/inbox)¶
来源:2026-04-09 G4 Review
已修复¶
待修复¶
接口设计
-
[x] 🟢 反事实工作流引擎级 enforcement (2026-04-16 登记 → 2026-04-25 缩水做 6 commit). 3-agent review reconcile 否决原方案 A 完整版 (引擎级 8 模块 1500-2500 行), 走 Option 2-Plus 缩水方案 4 件套 + ADR-0001 归档. 实施: (b)+(c)+(d) 子集 + 进化沉淀接线 + reference hook. commit 顺序:
248253eC1core/pkg/counterfactual/Deliverable schema (五步反向思维标准化数据结构, MetadataKey "flyto.counterfactual.deliverable" 跨包 Record.Metadata 落点);0385efdC2core/pkg/skills/reverse_think/MiniMax Anthropic 兼容端点 Go 化 client (替代~/.claude/skills/reverse-think/SKILL.md软性 markdown 在生产 Agent 不可调的 gap);c4b755fC3tools.Metadata.RequiresReverseThinkingopt-in flag (与 RequiresCheckpoint 同源 rule of two);4618b79C4Deliverable.AsReplayEvent→evolve.LogReplayer跨包 adapter (counterfactual import evolve 单向, evolve schema-agnostic 不感知 counterfactual; 关上 PM 担心的 "各行业自写 skill 进化结果停在哪里" 循环);40aae31C5platform/common/safetychain/ReverseThinkingHookreference hook (走 hooks.PreToolUse 不 wrap Tool, 与 Assemble 平行, fail-open advisory LLM 错不阻断业务); 本 commit C6 文档 + ADR-0001 同步. 方案 A 完整版否决理由 (写入 ADR-0001): 与 hooks/permission/validator/staging/RequiresCheckpoint 5 套现有 gate 概念重叠 + 业界 8 框架 (Claude Agent SDK / OpenAI Assistants / Vertex ADK / LangGraph / AutoGen / CrewAI / Semantic Kernel / Cline) 全部走 prompt-level + tool desc + 开发者自填策略零先例 engine-level 强制 reasoning gate + 范畴错位 (dev review 协议错配 runtime gate) + 吞吐数学不成立 (logistics 1000 单/s × 即使 10% 触发 → MiniMax token plan call 数被打爆). 3-agent 并行 review 流程: 调研 agent (8 框架矩阵 + 决策前 gate 形态调查 + 业界共识 reasoning) / 质疑 agent (5 道硬质疑含 RequiresCheckpoint 已实装 anchor 修正) / 设计 agent (4 备选 + 边界图 + 拍板假设矩阵). PM 拍板 Option 2-Plus (在原 Option 1 不做 + Option 2 缩水间, 加一件 evolve 接线解决 "进化结果停在哪" 担忧). 总量: ~2,131 行 (含双语 godoc + 测试), 6 commit. 测试: counterfactual 13 + reverse_think 12 + tools 1 新 + safetychain 9 = 35 测试 -race 全绿. core + platform/common 双 module build 干净. -
[ ] 🟢 微信 ClawBot 接入 (platform 层) (P3 低优, 2026-04-16 登记, 不属于 core 引擎层). 背景: 腾讯 2026-03-22 开放 WeChat ClawBot 插件 + iLink Bot API, 中国大陆唯一合法的个人微信第三方 Bot 通道. Hermes Agent v0.9.0 (2026-04-13) 已接入. 架构定位: 属于消费层 (platform/) 不进 core/, 遵守宪法原则 9 "引擎核心不假设特定场景" — 微信是腾讯产品 × 中国市场 × ClawBot 商业条款, 三重非中立. 代码位置:
platform/internal/messaging/weixin/ilink_bot.go(新建), 实现core/pkg/bridge/transport.BridgeTransport接口. 技术栈: HTTP/JSON long-poll 35s, AES-128-ECB, user-bound token (扫码登录), 不需要公网 IP. 商务门槛≈0: 不需要 Tencent 开发者证, user-bound 不是 platform-bound. 部署模式: 国内直连 ilinkai.weixin.qq.com / 海外 BYOT (Bring Your Own Token) + 域名隔离规避深圳南山司法管辖. 战略价值: 14 亿用户入口, 中国 to C 市场 unblocker. 优先级 P3: 不属于引擎层, 平台层做; 排在 platform 层其他工作之后. 详:core/docs/agent_teams_competitive.md§4.6. (P3, 属于 platform/ 层不属于 core/)
G5 Review 发现(pkg/tools/builtin/)¶
来源:2026-04-09 G5 Review
已修复¶
待修复¶
安全 / 可靠性
Bug
历史债
G6 Review 发现(pkg/providers/ - 7 个 provider,20 个文件)¶
来源:2026-04-09 G6 Review
已修复¶
待修复¶
安全
一致性 / 历史债
G7 Review 发现(internal/ - bash/mcp/cache/logger/server/diff/tokenizer/git)¶
来源:2026-04-08 G7 Review
已修复¶
待修复¶
安全 P0
安全 P1
正确性 P2
P3
G9-G12 架构审查修复(2026-04-09)¶
G9 系列:引擎层 Anthropic 解耦¶
G10 系列:Prompt/Context/Config 层解耦¶
G11 系列:Permission/Query/Wire 层¶
G12 系列:工具类包¶
G8 P2 补充修复¶
Phase 2 架构清理(2026-04-09)¶
实现债务 (dead-field scanner 追踪)¶
2026-04-19 新增, 同日 A 档 4 条 wire 完毕. core/tools/dead-field-scan 扫到 26 条已声明但扫描模块内从未被读的 exported field, MiniMax M2.7 triage 过, spot-check 4/4 通过 (见 commit 6c01d15 的 scan-baseline.json). 这些字段不是"可删垃圾", 是"设计意图先行、实现未连"的 feature gap. 类比 engine.Config.MCPServers (57a06c6) 和 Config.Plugins (07fe345) 的修复思路: wire, 不是 delete.
A 档 wire 同日完成 (2026-04-19): 两轮 commit 达成真 wire, 不是"让 scanner 满意"的形式实现.
第一轮 (commit d2c647c) — 满足 scanner read site:
- 3 APIError 字段经扩 Error() 方法展示 Hint / TokenGap / Body (256B preview). Hint 到位 (日志即用户看诊断); Body 半到位 (preview 在日志, 完整 body 可 SelectorExpr 直访); TokenGap 仅 print 数字.
- Config.Verbose 经 engine.New 尾 verbose_startup 事件, 只一条启动标记.
第二轮 (commit 本轮) — 真设计意图兑现 (用户反向挑战"scanner 满足 ≠ wire 完成"后补):
- TokenGap 接 compactor: agentctx.CompactTiered(..., WithTokenGap(n)) + 内部 truncateAndRetryCompact 精确跳步分支 (累积最旧组直到 >= tokenGap 一次丢掉) + TestTruncateAndRetryCompact_TokenGapStride + _ZeroSkipsStride 两条 regression guard. engine runLoop 从 *api.APIError 解 TokenGap 透传给 forceCompact. 字段 godoc 承诺的 "压缩模块一步跳过 N token" 从声明兑现到行为.
- Verbose 加第二处 trace: runLoop 入口 verbose_run_loop_started 快照含 model / message_count / tool_count / prompt_len / max_turns / is_skill_prompt. 默认 observer 零行为影响 (新 event 名, 不 gate 现有 event), verbose 模式有完整 trace 起点.
baseline 438 → 434 自第一轮起锁定, 第二轮不变动 baseline (两个字段已被读过, scanner 视角已 alive) 但实质意图层面从"形式"升到"真"wire.
原 A 档第 5 条 LLMCallOpts.Temperature 经 verify 发现是 scanner 间接假阳性 (test 验 forward, 公开 API, 字段真的 wire, 但 FlytoLLMClient adapter 刻意忽略), 降档到 C 档重评估.
ratchet 规则 (见 make dead-field-scan-ratchet): baseline 只能减不能增. 新加 dead field → CI fail. 修完一条 → baseline shrink, 提示 commit. 下面 26 条是当前 debt list, 每 wire 一条就从 baseline.json 少一行, 对应条目从本 section 勾掉.
A 档 (v0.1 要做, 小 wire) — 4 条 (全部已 wire)¶
- [x]
transport.APIError.Body— 扩Error()把 body 前 256 字节带入日志行 (2026-04-19) - [x]
transport.APIError.Hint—Error()附 hint 字段 (2026-04-19) - [x]
transport.APIError.TokenGap—Error()附(token_gap=N)+ 真设计意图达成: compactortruncateAndRetryCompact接WithTokenGapoption, 从 API 精确溢出值一步跳步 (字段 godoc 承诺的"让压缩模块一步跳过 N token 的消息组"兑现), 带TestTruncateAndRetryCompact_TokenGapStride锁定 (2026-04-19) - [x]
engine.Config.Verbose— engine.New 尾verbose_startup+ runLoop 尾verbose_run_loop_startedtrace (model / message_count / tool_count / prompt_len), 非 Verbose 路径零行为影响; "详细日志模式"真意图兑现 (2026-04-19)
B 档 (v1.0 要做, 特性框架 wire) — 17 条 (Skill 3 条 2026-04-19 从 C 档移入)¶
- [x]
internal/syslib/bash.Node.Background— bash&backgrounded job 语义真 wire (2026-04-20): 比 heredoc 深一级 — parser 从不写入 Background, 字段定义但永远为零值. 4 sub-claim 端到端: (a) parser.go parseListop=="&" → list.Background=true+ 尾部孤立&wrap 单 child NodeList (Bash 语义:cmd &把 cmd 放后台). (b) extract.go extractContext 加background bool, 两处 NodeList 分支 (extractFromNode + extractAllFromNode) 实现 "left 继承 / right 清掉" 传播:cmd1 & cmd2cmd1 bg cmd2 fg;cmd1 && cmd2 & cmd3整个 && 组 bg cmd3 fg. (c) CommandInfo 新增Background bool字段 (双语 godoc 说明 "escapes foreground control" 风险), extractSimpleCommand 从 ctx.background 填入. (d) bash_security.go AnalyzeDanger 新 helperamplifyBackground(info, c)在所有 danger return 点调用: Reason 附 "backgrounded -- escapes foreground control", Pattern 前缀 "& ". 把 bash.CommandInfo.Background 从 parser 装饰属性接入安全决策面 — 过去rm -rf / &和rm -rf /同样报警无区分, 现在 TUI/审计能告诉用户哪个能通过取消会话中止哪个不能. 4 条 regression test 一 sub-claim 一 test (3 bash 包 / 1 permission 包): TestParseList_BackgroundWriteSite (4 子 case 覆盖&正向和&&/;/|反向) / TestExtractCommands_BackgroundPropagation (简单 + nested) / TestExtractCommands_BackgroundFieldPopulated (字段暴露 + 反向无误标) / TestAnalyzeDanger_BackgroundCommand_Annotated (含前台对照). baseline 391 → 390 - [x]
internal/syslib/bash.Node.HeredocBody+HeredocQuoted+HeredocStripTabs+HeredocTag— heredoc 4 字段真 wire 端到端 (2026-04-20): RedirectionInfo 扩 4 字段 (Tag/StripTabs/Quoted/Body) 为 canonical 门面, extract.go NodeHeredoc 分支填入 + Target 回填自 Tag + IsStatic 重算. extractAllFromNode 对 unquoted heredoc body 递归解析 (Quoted=false 时 Parse body 抓嵌套$(rm -rf /)类绕过, 仿 Assignments.Value precedent). bash 包新增公共 helperResolveHeredocBody(redir):<<-形式返回 strip 行首 tab 后的 body (匹配 bash 运行时), 普通<<原样返回, nil/非 heredoc 返回 "". bash_security.goIsDangerousCommand+AnalyzeDanger用 ResolveHeredocBody 拼 checkStr, 对 body 做 dangerous-file 字面检测 (过去cat > out <<EOF\n.ssh/authorized_keys\nEOF全透明).AnalyzeDanger真实消费redir.HeredocTag+redir.HeredocQuoted: 当危险字面量源于 heredoc body 时 Pattern 带<<TAG:前缀, Reason 对 Quoted/Unquoted 分别附 "inert literal" / "runtime expansion possible" 措辞 — TUI 多 heredoc 场景能定位触发源并告诉用户是字面 payload 还是动态展开. 工作流教训: 第一轮只扩 RedirectionInfo 字段 + test 锁 shape, scanner 净 -2 (Node 4 条 drop, RI 层 3 条新增 dead), 用户反向挑战 "没消费者不代表没用"+advisor 同诊断但走了"删字段"捷径 — 拒绝删, 改走"补真 cross-package consumer" 路径 (ResolveHeredocBody + DangerInfo Tag/Quoted 措辞), 字段全部保留并每条有真语义读 site. 8 条 regression test 一 sub-claim 一 test (5 在 bash 包 / 3 在 permission 包), assert 的是 consumer 行为不是字段填值. baseline 397 → 391 (heredoc 4 条 + RedirectionInfo.Operator / Target bonus 激活) - [x]
internal/syslib/bash.Node.Quoted— 字符串引号语义真 wire 端到端 (2026-04-20): CommandInfo 新增ArgQuoted []boolparallel slice 与 Args 同长度 (双语 godoc 说明 "inert literal vs possibly expanded" 与 heredoc Quoted 契约镜像), extractSimpleCommand 收集 word 时读child.Quoted(parser 三处写入: 单引号 true / 双引号 false / ANSI-C$'...'true 的唯一产线读点) 填 wordQuoted 并切出 ArgQuoted. bash_security.go AnalyzeDanger dangerousFile 命中分支新增 arg-level attribution: 当危险字面量不在 heredoc body 内时, 查找含字面量的 arg index, 按c.ArgQuoted[i]对 Reason 附 "literal arg -- no runtime expansion" (单引号/ANSI-C) 或 "arg may expand at runtime" (双引号/unquoted), 与 heredoc Quoted 分支同形 TUI shape. 选 B 重量方案 (跨包真消费) 而非 A 轻量 (canonical 路径选择 resolveWordValue 改读 node.Quoted) — 后者同构于"走捷径过 scanner"被 feedback_scanner_pass_vs_intent_done 禁止. Args[]string保公共 API 兼容不动, ArgQuoted 为新增 surface. 4 sub-claim 一 test: TestExtractSimpleCommand_ArgQuotedParallel (regime 1+3+4 extract 层映射: 单/双/ANSI-C/unquoted + 无 arg nil 对照) / TestAnalyzeDanger_ArgQuoted_LiteralInReason (sub-claim 2+4 permission 消费: 单引号 vs unquoted) / TestAnalyzeDanger_ArgQuoted_ANSIC_LiteralInReason (sub-claim 3: ANSI-C 走完 extract→permission 往返 Quoted=true 不失真). baseline 390 → 389 - [x]
internal/transport/retry.RetryContext.QuerySource— 真 wire 端到端: (1)retry.WithQuerySource/QuerySourceFromCtxctx helpers. (2)internal/transport/client.go在 rctx 构造时读 ctx 填 QuerySource (write site). (3)Retryer.Do构造CannotRetryError.Reason时调reasonWithSource(rctx)嵌入(source=xxx)后缀 — 真 SelectorExpr read site, 让运维看错误流时能按来源归因 (不是诊断事件那种 observer-dependent, 而是错误消息本身即带信息). (4) 7 处 provider.Stream call site 注入 ctx:BuildAndStream=main_thread, subagent=sub_agent, tool_summary=summary, memory query=background, compact="compact", classifier="classifier", evolve="evolve". pkg/context 等包无法 import pkg/engine 的枚举, 按 godoc "free-form string" 用小写标签. godoc 升级到完整 Wire 段 (inject/write/read/future-policy-branching 四步). 3 条 regression test: WithQuerySource_RoundTrip / EmbedsQuerySourceInCannotRetryReason / EmptyQuerySource_ReasonUnchanged (后者锁降级: 未注入时 Reason 干净不带 stray "(source=)" 尾). advisor 警示 "写不算读" 后补第三步 reasonWithSource, 避免 scanner-pass-not-intent 陷阱 (2026-04-19) - [x]
pkg/context.Section.Static— 真 wire 为 runtime invariant:BuildPromptBlocks遍历StaticSections()/DynamicSections()时读s.Static, 违规 (非 Static section 放进 static bucket, 或 Static section 放进 dynamic bucket) 发section_contract_violationobserver 事件携带{name, bucket, expected_static, actual_static}. SDK 消费者手搓&Section{...}放错 bucket 时 wire time 立即暴露, 不用等数周后 cache 行为回归. 诊断非 fatal, 计算仍继续. godoc 从"内容全局不变...适合 global cache scope"升级到完整三层说明 (runtime invariant check + 未来 Anthropic global cache-scope 分支点 + SectionRegistry cache 字符串分配避免).SectionRegistry.emitEvent复用 observer 字段 (commit 前序引入). 3 条 regression test: StaticBucket_NonStaticSection_EmitsViolation / DynamicBucket_StaticSection_EmitsViolation / DefaultBundle_NoViolations (2026-04-19) - [x]
pkg/context.Section.NoCacheReason— 真 wire 三层: (1)SectionRegistry.ComputeCacheBreak 分支发section_cache_breakobserver 事件携带{name, reason}, engine 经buildBundleAndSectionRegistry(observer)透传 observer (NewSectionRegistryWithObserver新构造器保持NewSectionRegistry向后兼容). (2) 默认 bundle 新增首个生产 VolatileSection:default_bundle.go追加mcp_serversvolatile section,engine.buildSystemPromptWithContext从mcpMgr.ClientNames()+GetClient(...).IsAlive()收集状态经SetMCPServerStatuses注入 — 真实生产路径 (非 overlay 嫌疑) 每轮触发 CacheBreak 分支. (3) godoc 从"文档和代码审查"升级到"文档 + 代码审查 + 运行时诊断 + 未来事件驱动失效". 5 条 regression test 锁意图 (CacheBreak_EmitsDiagnosticWithReason / NonCacheBreak_NoDiagnosticEvent / NilObserver_NoCrash / DefaultBundle_MCPServersVolatile_EndToEnd / DefaultBundle_MCPServersVolatile_EmptyStatuses_NoBlock). 用户反向挑战"scanner 过 + test 绿 ≠ runtime 真触发"后补第二层 — 彻底根除"死代码真 wire"嫌疑 (2026-04-19) - [x]
pkg/daemon.DaemonConfig.CrashRecovery— daemon 崩溃恢复配置真 wire 端到端 (2026-04-20): 子组件 CrashRecovery 独立完整但 DaemonManager 从不实例化, 字段被声明却零消费. DaemonManager 新增非导出crashRecovery *CrashRecovery字段, NewDaemonManager 里if cfg.CrashRecovery != nil → NewCrashRecovery(*cfg.CrashRecovery)(唯一产线 SelectorExpr read 点, 字段透传: MaxRetries/InitialDelay/MaxDelay/Multiplier/OnCrash/OnGiveUp). 消费点 receiveMessages 的 ClientMessagePrompt 分支: 若 crashRecovery 非 nil 则dm.crashRecovery.RunWithRecovery(dm.ctx, sessionID, runFn)包裹 handlePrompt 调用, 超过 MaxRetries 后 log "gave up". 新公共 helperrunWithRecover(fn func()) error是 panic→error 桥接: 正常完成返 nil (CrashRecovery 不重试成功 prompt, 防御 "每次 prompt 附赠 3 次重试" 类回归), panic 被 defer-recover 捕获转fmt.Errorf("prompt handler panicked: ..."). 无 crashRecovery 时保持原语义 (panic 继续传播, daemon 级监管决定去留). 5 条 regression test 一 sub-claim 一 test: TestDaemonManager_CrashRecoveryDisabled_NoWrapper (nil policy 不构造) / TestDaemonManager_CrashRecoveryEnabled_ForwardsConfig (4 字段 MaxRetries/InitialDelay/MaxDelay/Multiplier 透传) / TestRunWithRecover_NormalReturnsNil (正常 fn 返 nil, 防御错误重试) / TestRunWithRecover_PanicToError (panic 冒泡 non-nil, CrashRecovery 才能触发) / TestCrashRecovery_WrapsPanickingPromptRun (端到端: runWithRecover + RunWithRecovery 组合, OnCrash 每 attempt 一次 × 3 + OnGiveUp × 1 + fn 调用 MaxRetries+1=3 次). 选 C1 panic-recover 路径而非 C3 形式 wire (后者同构"走捷径过 scanner"被禁). baseline 387 → 386 - [x]
pkg/daemon.DaemonConfig.HeartbeatInterval+HeartbeatTimeout— DaemonManager 心跳 2 字段真 wire 端到端 (2026-04-20): 子组件 HeartbeatService 此前独立完整但 DaemonManager 构造器从不启动它, 两字段被声明却零消费. DaemonManager 新增非导出heartbeat *HeartbeatService字段, NewDaemonManager 里if cfg.HeartbeatInterval > 0 → NewHeartbeatService({Interval: cfg.HeartbeatInterval, Timeout: cfg.HeartbeatTimeout}, dm.closeSession)(两字段唯一产线 SelectorExpr read 点). 生命周期钩子全 wire: Start 里 heartbeat.Start (启 ticker goroutine), Shutdown 里 heartbeat.Stop (取消 ticker ctx), getOrCreateSession 尾部 heartbeat.Register (加入扫描 map), closeSession 头部 heartbeat.Unregister (正常关闭路径不留 stale ID, 否则下次 tick 对已失踪会话再调 closeSession), receiveMessages 收到客户端消息时 heartbeat.Beat (任何 inbound 视作活性). 运行时行为真改变: 半死连接被 ticker 扫出并真 close (释放 pool 槽 + 清 isolation + 断 conn). 3 条 regression test 一 sub-claim 一 test: TestDaemonManager_HeartbeatDisabled_NoService (interval=0 不泄漏 HeartbeatService goroutine) / TestDaemonManager_HeartbeatEnabled_ForwardsConfig (interval 和 timeout 两字段均被读并透传到 HeartbeatConfig) / TestDaemonManager_CloseSession_UnregistersFromHeartbeat (生命周期钩子真流到 heartbeat 面). baseline 389 → 387 - [x]
pkg/engine.Config.ElicitationHandler+pkg/engine.ElicitationField.Default— MCP elicitation 端到端接线 (2026-04-19): 新增engine/elicitation_adapter.go桥接 mcp.ElicitationHandler ↔ engine.ElicitationHandler (mcp 包不能 import engine, 必须 adapter);engine.New在mcp.NewManager后立即mgr.SetElicitationHandler(adaptElicitationHandler(cfg.ElicitationHandler))(nil 接 NoopElicitationHandler 退化为 auto-cancel, 之前是 silent dead). 正向转 mcp.ElicitationProperty.Default (any) → engine.ElicitationField.Default (string) (string 透传 / number/bool 走 fmt.Sprint / 复合走 json.Marshal 兜底); 反向 accept 时 schema-defaulted optional fields 缺失自动 fill (web 表单 UX, MCP spec auto-fill 未规定但便利消费层); decline/cancel 透传空 Content. 6 个 sub test 锁 5 个 godoc 承诺. 顺手 wire 14 条 baseline drop (415→401): 主目标 2 + adapter 读 mcp.Elicitation{Schema,Property} 全字段 6 + 反向转换读 engine.Elicitation{Field,Response} 3 + 前序 ContentBlock.MarshalJSON commit 副作用 3 - [x]
pkg/engine.TeamConfig.PermissionHandler— Worker→Leader 权限冒泡 P1 端到端 wire (2026-04-19): SubAgent 加 permissionChecker (ModeDefault) + pendingPermissions map; bubblingHandler 把 permission.Request → MsgPermissionRequest → router.Send → 阻塞等响应; Engine.runLoop poll 加 MsgPermissionRequest 路由分支 (调 cfg.PermissionHandler / nil 自动批准 / 发 MsgPermissionResponse 回); permission.Response 加 UpdatedInput 字段; PermissionHandler interface 扩 (approved, updatedInput, reason); 顺手 wire PermissionRequestPayload × 5 + PermissionResponsePayload × 4 共 10 条 baseline drop. 端到端 test 锁 godoc 承诺 ("nil 自动批准" / "消费层实现的权限确认" 两条) - [x]
pkg/evolve.Config.AutoApproveReadOnly— 真 wire 为审批 short-circuit: (1)Evolverstruct 加autoApproveReadOnly bool+New()赋值. (2)Propose()审批逻辑前置 short-circuit:autoApproveReadOnly=true && isReadOnlyEvolution(proposal) → approved=true绕过 approvalFunc. (3)isReadOnlyEvolutionhelper 刻意收窄, 当前仅EvolveNewSkill符合 (只写 markdown, 不执行代码);EvolveNewTool/EvolveOptimize/EvolveSelfAdjust即便标称 read-only 也不 auto-approve, 因其内容会执行代码或改运行时. (4) 新evolution_auto_approvedobserver 事件与evolution_approved分离, 让安全审计可按事件名区分自动批准 vs 人工批准路径. (5) godoc 升级完整三段: 范围定义 / 安全人机工程权衡 / 其他进化类型永不放宽. 3 条 regression test (ApprovesSkillWithoutApprovalFunc / DoesNotBypassForNonReadOnlyTypes × 3 子 case / FalseKeepsHumanGate) 锁安全边界 (2026-04-19) - [x]
pkg/engine.Skill.AgentType+Skill.FilePath+Skill.Version+pkg/engine.AgentDefinition.MaxTurns— Skill wire 四字段端到端 (2026-04-19 两轮, 从 C 档"可能残留"重分类为 B 档真 wire): 第一轮 (形式 wire, 被用户反向挑战"真实现吗"推翻): 三字段加 SetAgentRegistry/SetObserver setter + invokeFork 只填 AllowedSubAgentTypes + Invoke 发 skill_invoked. 用户核实暴露 AgentType godoc "fork 模式下使用的 Agent 类型" 只兑现 1/7 sub-claim, test 绿但锁的是形式 wire, 不是 godoc 承诺. 第二轮 (真 wire, 本条最终状态): 按 sub-claim checklist 补齐 — (a) cfg.AllowedTools = ResolveToolset(def, parentTools) 四层过滤 (parent ∩ def.AllowedTools → Background 收窄 → 去 DisallowedTools ∪ globalDisallowed) (b) DisallowedTools 随 a 生效 (c) cfg.Model fallback 到 def.Model (d) cfg.MaxTurns fallback 到 def.MaxTurns, 都 0 时兜底 10 (e) AllowedSubAgentTypes (原有) (f) skill 声明 AllowedTools 时与 def 取交集防逃逸 (g) 未命中发 skill_fork_unknown_agent_type (原有). SkillRegistry 加第三个字段 parentToolNames func()[]string + SetParentToolNames setter, engine.New 注入func() []string { return eng.tools.Names() }. 三字段 godoc 升级双语完整 Wire 段 (AgentType 段枚举 (a)-(g) 全部). 11 条 regression test 覆盖全部 sub-claim (每条 test 锁一条 sub-claim, 防"一条 test 掩盖另一条缺失"): AppliesResolveToolsetWhenSkillSilent / SkillToolsIntersectWithDef_NoEscape / ModelFallsBackToDef / SkillModelOverridesDef / MaxTurnsFallsBackToDef / BothMaxTurnsZeroDefaultsTo10 / PopulatesAllowedSubAgentTypes / UnknownEmitsDiagnostic / EmptySkipsRegistryAndNoDiagnostic / InMemorySkill (file_path="" 显式保留) / FileSkill (路径+版本). baseline 401 → 397 (4 条实 drop: Skill.AgentType/FilePath/Version + AgentDefinition.MaxTurns side-effect 激活). 工作流教训: "先核实真实现再写 test" (feedback_verify_real_wire_before_test.md) 新增
C 档 (重评估, 可能删 / 可能 scanner 假阳性) — 5 条 ✅ 全部消除 (2026-04-25 L683 收尾)¶
- [x]
pkg/evolve.LLMCallOpts.Temperature— Temperature + TopP cross-provider passthrough 端到端 wire (2026-04-25, L683 子包 3 commit):flyto.Request.{Temperature,TopP} *float64加字段 +flyto.Float()helper, 7 provider (anthropic / openai / minimax / gemini / ollama / lmstudio / openrouter) 全部接通 sampling 旋钮 (此前 7 provider 的 Config 与 Stream 一律不传, 是 day-1 产品功能缺失而非简单 wire). 纯 passthrough + 极小特例: 越界一律不在 flyto 层 clamp 由上游 4xx 自然冒泡 (业界共识 — Vercel AI SDK/LangChain/instructor 全 passthrough), 仅 1 个 in-Request 已知冲突预拦 (anthropic + NeedsThinking + Temperature != 1.0 / TopP < 0.95 → silent override 1.0 +parameter_overriddenWarningEvent). 不加 OpenAI o-prefix 检测 (server 4xx 已清晰, litellm drop_params 实证维护 burden 不值). 0 是合法 deterministic 值,*float64+omitempty干净分离 nil/0. ADR rule of two: TopK/Seed/penalty 走 follow-up TODO 等真消费者驱动. evolve 串通:LLMCallOpts.TopP+WithTopP+buildMeta写meta[top_p](ParameterEvolver 与 evaluator 现可追溯完整 sampling 配置). FlytoLLMClient adapter 把 zero=未设 翻译到 nil, 非零 →flyto.Float(v). 23 tests 全绿 (17 wire/provider + 6 evolve), baseline 220 → 219 (LLMCallOpts.Temperature 实际 drain). 3-agent 并行 review (调研 7 provider API + 5 OSS prior art, 质疑扩 contract 必要性 4 道硬问题, 设计 4 备选方案 + 推荐 + 升华 + tracked debt 预测) reconcile 后开干. 上一会话归 C 档重评估的判断本会话被产品需求驱动翻盘 (provider 层产品力 day-1 缺失, evolve 进化闭环). - [x]
internal/syslib/bash.Assignment.Name— verify 为真 write-only (parser 写, extract.go 只用 Value 不用 Name, 消费零). 不删, 改真 wire 带安全价值:pkg/permission/bash_security.go加dangerousEnvVarPrefixesmap (LD_PRELOAD / LD_LIBRARY_PATH / DYLD_INSERT_LIBRARIES / IFS / BASH_ENV / PROMPT_COMMAND / PATH / PYTHONPATH / NODE_OPTIONS / GIT_SSH_COMMAND 等 Linux/macOS 后利用常见向量).IsDangerousCommand+AnalyzeDanger遍历c.Assignments读assign.Name(case-insensitive) 拦截 env-var 前缀注入 (LD_PRELOAD=./evil.so curl ...过去会绕过所有检查因 ExtractCommandName 剥前缀, 现在精确抓).DangerInfo.Reason含具体 env-var 名,Pattern含完整NAME=VALUE前缀供 TUI / 审计渲染. 顺带 dropCommandInfo.Assignments(同字段路径下 selector read). 14 条 regression test (9 dangerous / 3 benign 不过拦 / 1 case-insensitive / 1 AnalyzeDanger 结构化) (2026-04-19) - [x]
pkg/context.BundleKey.ModelFamily— verify 为 struct-as-map-key 假阳性 (BundleKey 作map[BundleKey]PromptBundle键 +key == (BundleKey{})值比较, 字段参与 hash/eq 但无 SelectorExpr read). 真 wire 为(k BundleKey) String() string方法, 返回"<family>/<scenario>"用于日志 / 错误消息 / observer 事件 payload — 字段在 String() 内被 SelectorExpr 读, 同时给运维人类可读输出. Table-driven regression test 5 case (default / industry / zero_value / partial_empty_family / partial_empty_scenario) (2026-04-19) - [x]
pkg/context.BundleKey.Scenario— 同上, 随 BundleKey.String() 一并 wire (2026-04-19) - [x]
pkg/context.MessageGroup.Index— verify 为 write-only (非 test 代码字段被多处写, 0 处读). 真 wire:compact_token_gap_strideobserver 事件扩dropped_group_indices []intpayload, Compressor 在 stride 分支 slice 重建之前快照每个被丢 group 的 Index 数组. 运维 grep 事件能看到哪几个 API-round group 被削 (如[1, 2, 3]) 而非仅 count. regression test 扩断言: 有 >=1 个 index / 无 0 (preamble 保留不变量) / len(indices)==dropped_groups 同源不变量 (2026-04-19)
2026-04-23 validator 子包引入 ✅ 本 session 5 commit 内消除¶
Commit 2 新增 core/pkg/validator/ 子包的 RuleValidator 后, scanner 检出 8 个 validator 字段 dead (DiffInput.SourceTool + Verdict.{Approved, Details, PolicyVersion, Reason, Score, Severity, ValidatorName}). 属 "设计意图先行, 实现未连" — 接口 + 数据类型先落地, 参考实现逐步真 wire:
- Commit 1 (
30639fb) 接口 + 数据类型: 引入 8 字段, 零消费 - Commit 2 (
e6239c2) RuleValidator: 只 set 不 read, baseline 212 → 220 - Commit 3 (
ca6309e) LLMValidator:renderPrompt读 SourceTool +parseLLMVerdictnormalise 读 Severity, drain 2, baseline 220 → 218 - Commit 4 (
8b1d556) CompositeValidator:childDetail读 Approved / Score / Details / Reason, drain 4, baseline 218 → 214 - Commit 5 (本 commit) ValidatedTool Decorator:
formatBlockedOutput读 ValidatorName + PolicyVersion, drain 2, baseline 214 → 212
Exit criteria 达成: baseline 回到 212, 8 字段全部真 wire, 无残留 validator 字段 tracked debt. pkg/validator/ 子包 (Validator 接口 + RuleValidator / LLMValidator / CompositeValidator 3 参考实现) + pkg/tools/builtin/validated_tool.go (Decorator + VerdictSink hook) 一套基础设施就绪, 为消费层 P1 L434 ML 验证器接入 (platform 接外部 ML backend) 和 P1 L435 熔断器 (状态机消费 VerdictSink 信号) 提供 core 接口层. 这 2 条 P1 仍在 open 状态, 核心已降; 待 platform 层完成.
2026-04-24 nil Validator 严格化 + AlwaysApprove 显式 opt-out (C1 / core 安全链 enforcement)¶
候选 A (platform 集成 Validator + Breaker 端到端) 启动前, 先把 core 层的"显式审批不能隐式继承"契约落到编译/构造期可见 — 产品拍板: platform 装配框架无默认, industry 不 wire 就是不装. 为避免 "industry 以为开了审批实际忘 wire" 的静默安全假象, core 层追加两件强约束:
pkg/validator/always_approve.go新增AlwaysApprove{}: Validator 接口显式 opt-out 实现, 忽略 diff 永远 Approved=true, ValidatorName="always-approve" 作哨兵标识供审计 dashboard 过滤.pkg/tools/builtin.NewValidatedTool构造期对 nil Validator / nil extractor panic (而非首次 Execute 时静默 nil-deref). Industry 刻意 opt-out 必须显式传validator.AlwaysApprove{}, code review 能抓到, 日志里 ValidatorName 能看到.
4 新 test (TestAlwaysApprove_* × 4 + TestNewValidatedTool_Nil*_Panics × 2 + TestValidatedTool_WithAlwaysApprove_PassesThrough) 全绿, baseline 212 不变 (AlwaysApprove 空 struct 无字段). 这条是 Agent Teams 3 角色 review 里"质疑"角色的 TOP#2 观察 — 独立于"装配框架做不做"决策, 属于 core 层 enforcement 职责, 无论 platform 怎么做都应落地.
消费层 L434/L435 P1 核心前置已就绪 (core 接口 + Decorator + 熔断器 + 显式 opt-out + 启动期 fail-fast), platform 层装配 / 观测 / gRPC 暴露继续 C2-C4.
2026-04-24 platform/common safetychain 装配层 (C2)¶
产品拍板抽象方向 (行业 platform 自选 LLM/ML backend + 熔断作用域) 后, 在 platform/common/safetychain/ 公共包落装配框架. 无默认, 显式 opt-in; Go 行业可直接 import, C# logistics 走 gRPC (C4).
Assemble(inner, v, extractor, scope, sink) tools.Tool: 一行装配 inner Tool + Validator + (可选) breaker scope + (可选) 观察 sink, 返回可注册的 tools.Tool. Validator / extractor 为 nil 时 core 构造期 panic (C1 保证), industry 显式 opt-out 必须传validator.AlwaysApprove{}.BreakerScopePolicy(func type): 决定每个 Tool 要哪个 breaker. 刻意选函数类型不是 interface — 质疑角色认为 3 个无状态实现抽 interface 是 YAGNI, 行业想自定义直接写同形状函数.- 3 个内置工厂:
NoOpScope()(不挂 breaker) /DestructiveOnlyScope(cfg)(destructive tools 共享 1 breaker, 对齐 "写路径整体保护" 语义) /PerToolScope(cfg)(每 tool 独立 lazy 分配). BreakerRegistry: 每个工厂返回(policy, registry)双元组, registry 给 C3 admin 端点消费 (Snapshot() map[string]circuitbreaker.State+Names() []stringsorted).- fan-out 顺序契约: Assemble 同时拿到 industry sink 和 breaker sink 时, industry sink 先 (记录样本到 store 不丢), breaker sink 后 (推进状态). C3 观察 store 后消费 verdict 流水, 这个顺序保证审计不缺.
16 test (TestAssemble_* × 6 + TestFanOut_AllCombinations + scope 系列 × 9) 全绿. core baseline 212 不变 (C2 只在 platform/common 加代码, 不碰 core).
消费层 L434/L435 现在 core + common 装配层就绪, 剩 C3 观测端点 + C4 gRPC 暴露. 端到端"industry 选 backend + Assemble + gRPC 暴露"链路逐步闭合.
2026-04-24 platform/common admin 观测端点 (C3)¶
安全链运维可见性: VerdictStore 接口 + RingStore bounded 内存实现 + admin HTTP 2 新端点.
safetychain.VerdictStore接口:Record(tool, verdict)(签名对齐builtin.VerdictSink可直接作为Assemblesink 不需 wrapper) +Snapshot() []VerdictRecord返拷贝. 实现方并发安全.safetychain.RingStore: bounded 内存环形缓冲, O(1) Record 热路径无分配. 容量显式参数无默认 (各行业 Warn 流量差异大), clock 可注入 (复用circuitbreaker.Clock, 测试 deterministic).admin.New(version, verifier, opts ...Option): 改 variadic 向后兼容. 新WithSafetyChain(store, registry)option, 任一 nil 视作不启用 (配对契约阻止接线错漏).- 2 新端点
GET /admin/safetychain/{verdicts,breakers}: 仅 WithSafetyChain opt-in 时挂载, 默认 404. 鉴权和/admin/tenant同级 (verifier 非 nil 时套 auth middleware, Verdict.Reason 可能带运营敏感信息).authed()helper 收敛鉴权策略. - 输出形状: verdicts →
[]VerdictRecord{Timestamp,ToolName,Verdict}JSON; breakers →[{name,state}]按 name 排序 JSON (dashboard 轮询 diff 稳定). 空 snapshot 返[]非null让下游无需 null check.
11 test 全绿 (5 RingStore + 6 admin 端点, -race 通过). core baseline 212 不变. 端到端 consumer 示例 CHANGELOG 里写了.
消费层 L434/L435 现在 core + common (装配 + 观测) 全就绪, 剩 C4 gRPC 暴露给 C# logistics.
2026-04-24 platform/common 安全链 gRPC (C4) — 候选 A 端到端闭合¶
给 C# logistics (以及未来 Go 行业) 一条原生 gRPC 通路读安全链状态, 和 C3 admin HTTP 同源双面暴露. 沿用 HealthService 已经走的 proto + genpb + grpcapi 模式.
- proto:
platform/common/internal/api/grpc/proto/safetychain.proto, 2 RPC (ListVerdicts/ListBreakerStates), csharp_namespace 和 go_package 对齐 health. - gen: 一次性 install
protoc-gen-go+protoc-gen-go-grpc到$GOPATH/bin后 protoc 生成到gen/(共享package genpb). - server:
grpcapi.SafetyChainServer{Store, Registry}依赖注入, 与 admin.WithSafetyChain 消费同一对 VerdictStore + BreakerRegistry. - cmd/common wire: 默认构造
RingStore(1024) + NoOpScope registry, 同时挂 admin HTTP (若 --http-addr 非空) + gRPC. 默认启用让 C# stub 能即时对接.
设计决策: Verdict.Details 刻意省略 (proto3 无 map
6 test 全绿含 bufconn 端到端 gRPC round-trip 作为 C# stub 互操作代理证据. core baseline 212 不变.
候选 A 端到端闭合: 整条 "Agent → staging → Validator → ValidatedTool → CircuitBreaker → WMS API" 安全链 core + common (装配 + HTTP 观测 + gRPC 暴露) 全部就绪. 剩的工作落到 industry platform 侧: 选 LLM / ML backend, 装配 Tool 到 engine 消费层, 把真实 Verdict 流水填进 common 的 VerdictStore. L434/L435 P1 核心路径已清晰, 可落 platform 层实施时直接消费.
2026-04-25 L569 反事实子包引入 — 1 字段合法 tracked debt (与 shadowdb / staging 同形)¶
L569 缩水 6 commit 完成时, scanner 检出 1 条新 dead — tools.Metadata.RequiresReverseThinking. 该字段在 platform/common/safetychain/reverse_thinking_hook.go 的 Lookup 回调里被读 (hook 按工具名查 Metadata 看 RequiresReverseThinking 决定是否触发反向思维), 但 platform/common 是独立 module, scanner 视野不及.
1 条合法 tracked debt 终态分类: 与 shadowdb 4 + staging 4 + counterfactual Deliverable (本身经 Reflector test 读, 不入此 debt) 同模式 — core 内部无 reader, 外部 consumer (platform/common 装配层 + 行业 platform 自填 hook) 在 scanner 视野外.
tools.Metadata.RequiresReverseThinking — 与已有 RequiresCheckpoint 同形 (memory feedback_exported_field_delete_needs_review.md). Tool 自描述 opt-in flag, 让消费 hook 链 (platform/common/safetychain.ReverseThinkingHook 是 reference impl) 决定是否触发反向思维. Tool 作者声明 RequiresReverseThinking: true 即可在 opt-in hook 注册的 session 内启用. 由于 platform/common 是独立 module + 行业 platform 实现自己的 Lookup 回调, scanner 永不会从 core 内部看到 reader. 终态接受为 tracked debt, 与 staging Record 4 字段 / shadowdb Session 4 字段同分类.
baseline 219 → 220 (+1 合法 tracked debt), 不计入应 drain 指标.
2026-04-25 shadowdb 子包引入 — 4 字段合法 tracked debt (D-A 档同形)¶
shadowdb 子包 (core/pkg/shadowdb/) 实现 L437 影子表管理. 3-commit 落地后 (2c84209 / e140952 / 8951c6e), scanner 检出 Session struct 4 个 exported 字段 dead — 与 staging Record 4 字段 (TechVerdict/BizVerdict/ExecutionError/ExecutionProof) 同形, 是 "core 内部无 reader, 外部 consumer 在 scanner 视野外" 的合法 tracked debt, 不走 drain 路径.
4 条合法 tracked debt 终态分类 (按 memory feedback_exported_field_delete_needs_review.md 与 feedback_scanner_ignores_test_readers.md):
Session.ID— 外部 consumer 在自己 SQL 里作 session_id filter 值 (例WHERE session_id=?后绑定 sess.ID). core makeCloser 走 sessionID 闭包参数不读 sess.ID, 单源真理在 opener 注册表Session.CreatedAt— 外部 observability dashboard 读会话开启时刻. core Reap 走 trackedSession.createdAt 不读 sess.CreatedAtSession.ShadowTable— 外部 consumer 在 SQL 里引物理表名, decorator 与 EnforceSessionFilter 也可读取. core makeCloser 走 trackedSession.shadowTable 闭包不读 sess.ShadowTableSession.DB— 外部 consumer 经 sess.DB.ExecContext / QueryRowContext 跑 SQL. core 内部经 opener.db 走, 不通过 session 暴露
均为外部 SDK / 平台层 consumer 的 API surface, scanner 视野不覆盖. 无强行加 internal reader 路径 — 任何强加都是 "走捷径过 scanner" (memory feedback_scanner_pass_vs_intent_done.md), 设计本身就是 opener 持单源真理 + Session 是 immutable snapshot.
baseline 216 → 220 (+4 合法 tracked debt), 与 staging 引入时同模式 (212 → 216 +4 合法). 不计入应 drain 指标.
2026-04-24 staging 子包引入 (commit 1) — 后续 3 commit 内消除¶
staging 子包 (core/pkg/staging/) 实现 "Agent 决策 → staging → 审批 → 生产" 链路中 "staging" 一环的状态机与 Record 契约. commit 1 按 "设计意图先行 tracked debt" 模式 (memory feedback_design_intent_first_tracked_debt.md) 只落类型 + 状态机, reader 在 commit 2 (Store 接口 + InMemoryStore) 与 commit 3 (Engine 混合控制状态机) 里进来. baseline 212 → 223 (+11 字段).
| 字段 | 将在哪个 commit 被 reader 消费 |
|---|---|
Record.ID |
commit 2 ✅ (InMemoryStore.Stage 分配 + Get/List 返回) |
Record.SessionID |
commit 2 ✅ (Stage 校验, List/ListBySession 过滤) |
Record.State |
commit 2 ✅ (Update/Mark 方法读源状态 + 写新状态) |
Record.Diff |
commit 3 (Engine.ValidateTech/ValidateBiz 调 Validator.Validate(ctx, r.Diff)) |
Record.CreatedAt |
commit 2 ✅ (List SortFunc 按 CreatedAt 升序) |
Record.UpdatedAt |
commit 2 ✅ (ListStuck 过滤 + SetUpdatedAtForTest 写 + 所有 Update/Mark 写) |
Record.Metadata |
commit 2 (Store 透传存取), commit 3 (DependencyGuard 读 hint) |
Record.TechVerdict |
commit 3 (Engine.ValidateTech 写后 Engine test 断言 + platform 侧 audit dashboard 读) |
Record.BizVerdict |
commit 3 (Engine.ValidateBiz 写后 Engine test 断言 + platform 侧 audit dashboard 读) |
Record.ExecutionError |
commit 3 (Engine test 断言 MarkFailed 后 reason 保留) |
Record.ExecutionProof |
commit 3 (Engine test 断言 MarkExecuted 后 proof 保留 + 幂等 first-write-wins 验证) |
Query.SessionID / States / Since / Limit |
commit 2 ✅ (InMemoryStore.List 过滤实现) |
commit 2 后进度 (2026-04-24): 9/11 drain, baseline 223 → 218. Commit 2 新增 4 条 dead (TechVerdict / BizVerdict / ExecutionError / ExecutionProof), 预期在 commit 3 Engine test 断言写后字段值时收割. Commit 2 后 staging 包净 dead 6 条: Record.Diff (原 commit 1) + Record.Metadata (原 commit 1) + commit 2 新增 4 条.
commit 3 后最终进度 (2026-04-24): 2 条 drain (Record.Diff 由 Engine.ValidateTech/Biz 读, Record.Metadata 由新增 TenantDenyGuard 内置实现读), baseline 218 → 216. 4 条 (TechVerdict / BizVerdict / ExecutionError / ExecutionProof) 仍 dead — 最初预估 "Engine test 读字段值就能 drain" 错, scanner 只扫非 test 代码的 reader, _test 里 read 不算.
4 条合法 tracked debt 终态分类: 按 memory feedback_exported_field_delete_needs_review.md 模式, 这 4 条是"外部 audit dashboard 消费, core module 无内部 reader"合法形态:
- Record.TechVerdict / BizVerdict: 平台层审计 UI 读 Severity/Reason/ValidatorName 展示"哪一层拒绝/为何"
- Record.ExecutionError: 平台层 watchdog / 审计追溯读生产失败原因
- Record.ExecutionProof: 平台层审计链完整性验证 (核对 WMS 返单号与 staging 记录一致)
均无 core 内部消费路径. 走 D-A 档 路径 (不 drain, 保留 exported 字段 + 进 tracked 但不 drain 计划).
Exit criteria 达成 (调整: 原目标 ≤ 212 不现实): staging 包 core-level scanner-clean, 剩余 4 条是 exported 字段 cross-module 外部消费 (platform 审计侧), 符合 memory 所述 "exported 字段无 consumer 是 scanner 视角局限" 合法形态.
2026-04-20 baseline 386 sweep 结论 (D 档候选清单, 待路线决策)¶
alpha.7/8 drain 完 A/B/C 档 26 条 (baseline 438 → 386, 净 -52 含副作用激活). 本次 sweep 对 386 剩余按 tag + struct 归约的二次 triage 结果:
事实层:
- 193 / 386 条有 json tag: 按 feedback_exported_field_delete_needs_review 默认视作第 3 类 (parser-to-marshal-to-SDK/plugin downstream, scanner 视野不覆盖外部消费者). 不列入 drain, 不删.
- 193 / 386 条无 tag: 真候选池, 按 struct 归约约 20-25 个主题 (见下).
D-A 档 2026-04-20 重分类结论: 初版列 8 主题 / ~36 字段, 按 push / pull /
callback 三形态 verify 后 (见 docs/api-reference.md 新章节 "API 消费形态"),
7/8 条是合法外部 API 表面, 消费者在 scanner 视野外, 不是实现债务. 真
drain 对象仅 engine.SessionStats 一条 (已完成). 其余 7 条保留, 不再列入
"应 drain" 队列, 原因见每条后缀标注.
D-A 档 (已分类, 1 真债务 + 7 合法外部 API):
- [x]
engine.SessionStats(TurnCount/InputTokens/OutputTokens/CostUSD/MessageCount) — 真 wire 为 pull + push 双路径 (2026-04-20):Session.Stats()已有 pull API 保留 (消费者随时读快照), 新增 push 通道session_cost_threshold_crossedobserver 事件. trackEvents 尾部 30 行代码抽取为新方法applyTurn(方便测试, 也解耦 emit 逻辑). 引入包级常量costThresholdsUSD = []float64{1,5,10,50,100}和 helpercrossedCostThresholds(last, cost) → []float64(返回 half-open 区间(last, cost]内的升序档位, 支持单轮跨多档). Session 加lastCostThresholdEmitted float64guard 防同档重复 emit. 锁策略: 锁内构造 stats 快照 + 组 payload (字段经stats.CostUSD / TurnCount / ...SelectorExpr read, 这正是把 5 字段从 scanner "声明未读" 升为 "运行时真读" 的依据), 释放锁后再 emit (对齐 Close() 的 unlock-then-emit 模式, 避免持锁跨消费者回调). SessionStats struct godoc 升级双语, 新段落明确两条消费路径的各自定位 + 同源不变量 ("两路径不重叠: 要快照走 pull, 要成本告警走 push"). 5 条 regression test 一 sub-claim 一 test: Stats 5 字段多轮累加准确 / 首次跨档 payload 完整 (7 key 全 assert) / 已跨档同区间不重发 / 单轮跨多档升序每档一次 ($0→$15 发 $1/$5/$10) / 无跨越无事件 (0.9 累计不 emit). baseline 386 → 381. - [~]
engine.PlanApprovalEvent(SessionID/Plan/FilePath/Steps/Approve/Reject) — 同步回调 (callback) 形态, 合法外部 API 保留 (2026-04-20 重分类): 经ApprovalPolicy.RequestApproval(ctx, event)传递, Approve/Reject 是消费者调用的回调函数字段.ApprovalPolicy接口由 CLI 终端审批 / SaaS 企业审批工作流 / 测试 NoopApprovalPolicy 等外部消费端实现, scanner 视野不含外部 policy. 见docs/api-reference.md"API 消费形态" 章节形态三. - [~]
engine.CheckpointSuggestedEvent(Input/RiskPattern/RiskReason/ToolCallID/ToolName) — 订阅 (push) 形态, 合法外部 API 保留 (2026-04-20 重分类): 实现flyto.Event接口 (EventType() string方法), 走Engine.Run返回的<-chan flyto.Event流. 消费者for evt := range ch+ type-switchcase *CheckpointSuggestedEvent读字段. scanner 视野不含外部消费端. - [~]
permission.DenialStats(ConsecutiveDenials/LastDeniedInput/LastDeniedTool/TotalDenials) — 调取 (pull) 形态, 合法外部 API 保留 (2026-04-20 重分类): 由DenialTracker.Stats() DenialStats返回, 消费者 (CLI / SaaS / 测试 harness) 主动调读字段, 和 SessionStats 同构 pull API. scanner 视野不含外部 pull 调用. - [~]
permission.ClassifyResult(DurationMs/Stage/Thinking/Usage) — 调取 (pull) 形态 (2026-04-20 重分类):Classifier.Classify(ctx, req) (*ClassifyResult, error)返回值, 消费者主动调. 合法外部 API. - [~]
engine.InboxMessageEvent(Data/Meta/ToolUseID/Type) — 订阅 (push) 形态 (2026-04-20 重分类): 实现flyto.Event, 走 Engine.Run Event channel. 消费者经case *InboxMessageEvent读. 合法外部 API. - [~]
flyto.TeammateMessageReceivedEvent(From/To/Type/MessageID/PayloadSize) — 订阅 (push) 形态 (2026-04-20 重分类): Agent Teams peer-to-peer 事件, 实现flyto.Event. router consumer 走 channel + type-switch. 合法外部 API. - [~]
engine.ElicitationField(Description/Required/Title/Type) +ElicitationRequest(Fields/Message/ServerName) — 同步回调 (callback) 形态 (2026-04-20 重分类): 经ElicitationHandler接口 (NoopElicitationHandler 已实现, 生产 handler 由 CLI/SaaS 消费端提供) 消费. 合法外部 API.
D-A 档分类结论: 上述 [~] 标记条目不列为实现债务, 不计入应 drain 指标. 它们在 baseline 381 里占据 35 条, 保留于 scan-baseline.json 意为 "scanner 知道这些字段在本 module 无内部 consumer, ratchet 保证未来新加的类似位置字段不会悄悄漏掉", 不是"设计未连". 未来新增外部 API 载体时 baseline 会增长, 按 docs/api-reference.md "API 消费形态" 章节判据分类即可, 不走 drain 路径.
D-B 档 (特性框架 wire, ~12 主题 / ~70 字段) — evolve + 内部结构:
- [x] 缓存族 3 个 struct 真 drain / 归档 (2026-04-20): 按用户 4 问法则 (接口有消费? 必要? 外部? 内部加?) 分三条路径走完:
engine.FileCacheEntry6 字段真 drain: Path 消除"lruEntry.path 双重存"冗余 (RecentFiles 改读 entry.Path, 删 lruEntry 里那份, FileCacheEntry.Path 成 single source of truth); ContentHash/Size/LineCount/ReadAt/WasModified 通过新增FileStateCache.Info(path) (FileCacheEntry, bool)pull API (返回值副本, 外部消费安全) + reminders.go CheckFileModifications 升级消费元数据 (reminder 文本带 "at-read-time: N bytes / M lines / hash XX, read T ago" + WasModified 已标记提示), 从"声明未读"激活为真 consumer read. FileChangeChecker 接口同步加 Info 签名. godoc 双语解释 6 字段消费路径 (pull via Info/Get/Peek).engine.CacheStats3 字段 (Entries/MaxSize/Evictions)[~]归档: 已在 docs/api-reference.md 列为 pull API (和 SessionStats/DenialStats 同列), godoc 升级双语写清消费形态 "调取 pull, 消费者主动调 FileStateCache.Stats() 读字段, scanner 视野内无内部 reader 是期望状态, 不强加内部 reader 过扫描器". 不减 baseline.tools/builtin.FileStateCacheEntry5 字段[~]归档: form 3 callback (FileStateCacheRecorder.RecordState 由外部实现接收), 和 engine.PlanApprovalEvent/ElicitationField 同构. godoc 升级双语讲清字段给外部 Recorder 消费的契约 (ContentHash/Size/LineCount/ModTime/IsPartialView 各自用途). 不减 baseline. baseline 367 → 361 (-6, FileCacheEntry 全部 drain). 下次跑扫描器时 8 条保留 (CacheStats 3 + FileStateCacheEntry 5) 显示归档分类,不算债务.- [x]
pkg/evolve.FeedbackRecord(Entity/Metric/Value/Confidence/Timestamp/Meta) — 5 字段 drain 走类型合并路径 (2026-04-20): 按 4 问审判发现 evolve 包内同时存在两个字段完全相同、语义重合的 struct —FeedbackRecord(ParameterEvolver.Propose evidence) 和Feedback(FeedbackChannel.Query 返回的 KPI 反馈, reflector_impls.go 内部真消费fb.Entity/fb.Metric). "同一语义两份类型"是典型冗余设计, scanner 把 FeedbackRecord 5 字段报 dead 因为消费端早就并行用 Feedback 了. 合并: 删 FeedbackRecord,ParameterEvolver.Propose(ctx, key, []Feedback)签名直接收 Feedback, ProposerFunc / DefaultParameterEvolver / examples/evolve_closed_loop 全部链路改用 Feedback. 合并保留更短更 idiomatic 的 Feedback 名, 删掉 "Record" 累赘后缀. 所有 evolve test 继续通过. baseline 372 → 367. - [x]
internal/syslib/bash.HeredocInfo(Quoted/StripTabs/BodyStart/BodyEnd) — 4 字段真 drain 端到端 (2026-04-20): 按用户 4 问法则 (接口有消费? 必要? 外部? 内部加调用?) 重新审判, 这 4 字段不是一种债务: Quoted/StripTabs 是冗余 (parser 自己从源码 token op/parseHeredocDelimiter 算, 是 source of truth; PreprocessHeredocs 的副产物无人消费), 删字段 + 对应 test 切换到Parse(input)验证 AST 侧HeredocStripTabs/HeredocQuoted真语义. BodyStart/BodyEnd 是设计意图未 wire (之前存的是 result.Len() 即 processed text 近似偏移, 作者注释自己标"近似"): 修成真原文 byte offset + 端到端 wire HeredocInfo →ast.Node.HeredocBodyStart/End→RedirectionInfo.HeredocBodyStart/End→DangerInfo.HeredocBodyStart/End→checkpoint_suggestedobserver 事件 payload (heredoc_body_start/heredoc_body_endkey, 零值归因非 heredoc 场景时跳过). Reason clause 同时带 "source bytes N-M" 文本让人类可读 log 也承载位置. 回归 test 一主题一 sub-claim:TestPreprocessHeredocs_BodyStartEndAddressesOriginalSource4 case (单 heredoc / 空行 body / 多 heredoc 同行 / strip-tabs 变体) 锁source[Start:End] == Body不变量;TestAnalyzeDanger_HeredocBodyPos_LocatesSource端到端断言DangerInfo.HeredocBodyStart:HeredocBodyEnd切回 cmd 能命中 authorized_keys + Reason 含 "source bytes". advisor 审判发现 "快扫 vs 严谨"叙述错 (两侧都是完整词法分析, 只是历史独立编写), pin consumer 用 observer payload 是真 user-visible 面 (非 formal wire). baseline 376 → 372. - [x]
internal/syslib/bash.CommandInfo(InPipeline/InSubshell/Operator/PipePosition/Position) — 5 字段真 wire 端到端 (2026-04-20): 和 alpha.8Background字段同系 (bash 语法上下文标记), 同构走"安全决策面激活"路径. 先 verify extract.go ctx 传播语义 (Position 在 NodeSubshell 内 reset 从 0 算 / NodeList+NodePipeline 累加 outer+inner; PipePosition 必须配合 InPipeline 查因非管道命令零值冲突; Operator 第一个命令从父 ctx 继承最外层为空), 按实际语义升级 5 字段双语 godoc 消除"边界含糊"嫌疑.amplifyBackground扩展重命名为amplifySyntaxContext承接全部 6 字段 (含 Background), 一处集中构造 clause + pattern 前缀 (结构性字段 "(subshell) " / "| " / "& " 叠加, Position/Operator 走 Reason clause), 用 "; " 拼接, 避免各字段分散拼错. 所有 6 处调用点 (AnalyzeDanger) 从旧名更新, 语义向后兼容 (Background 行为不变). 5 sub-claim 一 test + 1 regression: InSubshell / InPipeline+PipePosition / Operator / Position / Multiple 组合 ((true && rm -rf /)同时触发 Operator/InSubshell 验证 "; " 连接和 "(subshell) " Pattern 前缀不互相覆盖). Counter case 全覆盖 (standalone 不得有对应标注防假阳性). advisor 明确要求 "verify from code not godoc" — ship 前核实 3 个关键问题代码答案才写 godoc 和 helper, 不脑补. baseline 381 → 376. - [x]
internal/syslib/git.Info5 字段 drain (2026-04-20): 按 4 问法则重审, 本包从 day 1 零消费者 — speculative engineering 残留 (上游 claude-code-mod 同步存在双实现, TS 原版 Claude Code 根本没 git metadata API). 真诚分层确立: syslib/git 作"引擎内部底层 git 工具 (裸 exec.Command)"定位, 不建 builtin/git tool (对模型冗余, bash tool 够), pkg/context 通过 import 直接消费. 删Info.Root/DefaultBranch/Dirty+FindGitRoot/GetDefaultBranch函数 (真无消费场景, Dirty 与 Status 语义冗余);pkg/context/context.godetectGitInfo替换为syslib/git.GetInfo调用, IsRepo/Branch/Status 从 dead 变真消费 (注入 system prompt- Git repo: yes / - Git branch: X / - Git status: clean|N file(s) changed).GetBranch改用git branch --show-current(detached HEAD 返回 "" 比 rev-parse 字面 "HEAD" 更易消费). DESIGN.md sandbox 白名单 + architecture.md 包描述同步. baseline 361 → 356. 后续纠正: 原 Commit A 同时加了Run(ctx, cwd, env, args...)通用原语期望 sync_git 下沉, 但读 sync_git 发现它走execenv.ExecutorDI 层 (ClassMemoryGit sandbox 路由), 用不了裸 Run — Run 撤回 (见 L695b). - [x]
internal/syslib/git.Run原语撤回 (2026-04-20): Commit A 的形式错误自我纠正. Run 本想作为 sync_git 4 runGit 变种的下沉目标, 但 sync_git.go:199-205,402-422 走的是g.executor.Command(ctx, execenv.Spec{Class: ClassMemoryGit, ...})— execenv.Executor DI 层, 不是裸 exec.Command. sync_git 走 ClassMemoryGit 让云端 sandbox backend 决策路由 (system pod 或 tenant VM), 下沉到裸 Run 会破坏 sandbox 路由抽象. 同时 context.detectGitInfo 只用 GetInfo 不用 Run. Run 零真实消费者, 未来 sandbox M2 "预留" 是 speculative — 和本轮全程反对的"存利息"一个模式. 撤回: 删Run+mapToEnv+ 4 个TestRun_*+"context"import; DESIGN.md 白名单移除 "Run 原语" 字样, architecture.md 包描述同步. baseline 不变 (Run 是函数非字段). 教训: 先枚举真消费者路径 (裸 exec vs DI 层) 再设计原语, 别凭命名相近就假设下盘. - [x]
syslib/git.ValidateRef贯通到pkg/memory.NewGitSyncAdapter构造期 (2026-04-20): 独立安全债务, 与 Run 原语撤回同一 session 清理. sync_git 的g.remote/g.branch两个用户配置值进入 11 处 git argv (fetch/push/rebase/reset/pull/init/log/ls-files/add/commit/diff), 原无构造期校验 — remote 以 "-" 开头即 flag injection (如--upload-pack=evil让 git 执行远端任意代码), branch 含 ".." 即路径遍历 (git 内部 ref 解析解到 .git/refs/../.. 越狱). 修复: exportvalidateRef→ValidateRef(GetDiff 内部调用点同步), NewGitSyncAdapter defaulting 块后一次调gitlib.ValidateRef(remote)+gitlib.ValidateRef(branch), bad 值 panic (风格对齐既有 nil Executor panic). 加 2 test:TestNewGitSyncAdapter_RejectsInjectedRemote(--upload-pack=evilremote) +TestNewGitSyncAdapter_RejectsPathTraversalBranch(feat/../etcbranch). baseline 不变 (纯参数校验, 无字段触及). - [x] turn 边界族 C1:
TurnStartEvent.ContextWindowTokens+TurnEndEvent.MaxTokens经 bridge serializer 透传 (2026-04-20): 按 4 问法则分类, 真消费路径是 engine emit → flyto.Event channel → bridge EventSerializer → SSE → 外部客户端 (TUI / Web UI). event_serializer.go 的 anonymous struct literal 是 choke point — 原 TurnStartEvent payload 只序列化{turn, model}丢 ContextWindowTokens, TurnEndEvent payload 只序列化{turn, input_tokens, output_tokens, cost_usd}丢 MaxTokens, 两个 engine 已 emit 的字段被 serializer 静默吞掉. 修复: 两 struct literal 加ContextWindow/MaxTokens字段 (JSON key 分别context_window/max_tokens, omitempty 省零值避免对旧消费者添噪声). 新建pkg/bridge/event_serializer_test.go锁 JSON shape: 4 test (shape 断言 + omitempty 验证) × 2 event. 语义: ContextWindow 透传模型完整 context window token 数 (由 provider.Models() 提供, 消费层可渲染预算条不硬编码模型表); MaxTokens 透传本轮发给 provider 的实际 output 上限 (FastMode / reasoning 降档后的值, 消费层据此判断回复截断是命中上限还是自然停止). 教训: 新增 event 字段必须同步修 serializer anonymous struct + shape test, 否则被 bridge choke point 吃掉. baseline 356 → 354. - [x] 子 agent 观测链路端到端 wire (2026-04-20 本 session 主题, 3 commit 端到端闭环): 父 agent 派出的子 agent 当前对引擎是黑盒 — worktree 模式挂牌不开工 (sa.Cwd 设了但 BashTool/FileEditTool 工具箱继承父 cwd), 子 agent 事件在 5 处 spawn 路径 (agent_executor sync/background/worktree, engine.go:1938 skill fork, engine.go:4682 记忆提取故意静默, team.go:378 worker, dream.go:456 dream) 全 drop 或只读少数事件类型, SubAgent.StartTime/EndTime/Description 从未 emit. 产品后果: TUI 树形展示中间节点空白 / 平台 session 成本漏计 / 审计流水缺失 / worktree 隔离是谎言. wire 方向 3 commit:
- commit A ✅ (ctx cwd 透传, 2026-04-20 commit 914df89): pkg/tools 新增
WithWorkdir(ctx, path)/WorkdirFromContext(ctx) string工具 ctx helper (type-hidden key 防外部构造污染); BashTool/BashToolBackground/FileEditTool/GitignoreTool 4 个 cwd-aware 工具 Execute 开头先读 ctx 覆盖, fallback 构造期 cwd; SubAgent.runLoop 每工具调用前注入 ctx = WithWorkdir(ctx, sa.Cwd); 4 sub-claim 测试全绿 (pwd 输出真落到 override, symlink guard 用新 cwd, Gitignore 三级 fallback, 空 ctx 回退不回归). baseline 352 → 351 (SubAgent.Cwd 从 dead 变 live wired). - commit B ✅ (事件回流 + 生命周期, 2026-04-20): pkg/engine 新增 SubAgentStartEvent (ID/Description/Cwd/Model/StartTime) + SubAgentEndEvent (ID/Duration/Status/Result/Error) +
event_emitter.go(WithEventEmitter/EventEmitterFromContext, 私有 key type 防外部伪造); engine 主工具派发前 WithEventEmitter 包 ctx 用非阻塞 select 丢弃兜底防死锁; sa.runLoop 读 ctx emitter 一次, defer emit End, for-select 头部 emit Start, 中间 13 处ch <- &SubAgentEvent{SubAgentID: sa.ID, Inner: X}统一替换成pushEvt(X)辅助 — pushEvt 把 bare X 送到 sa 自己 ch (RunSync/RunSyncWithCallback 本地消费者 type-switch 匹配 *TextEvent 等, 顺带修潜在 silent bug — 原包装后 RunSync 从没收过 TextEvent), 同时在 forward path active 时 emit 包装 SubAgentEvent 到父 Run channel. SubAgentConfig.SilentEvents 兜底 flag, runMemoryExtraction 显式设 true (后台静默任务不污染用户事件流). 7 sub-claim 测试全绿 (Start/End/Inner/Silent/NoEmitter/Concurrent/Truncate + EventEmitter 单元). baseline 351 → 358 临时上升 (+7: SubAgentStartEvent 5 + SubAgentEndEvent 5 - wire 掉的 Description/StartTime/EndTime 3), 这 11 条是 tracked transient debt 本 session Commit C 下一刀 wire 完. scan-baseline.json 已 regenerate 接纳. - commit C ✅ (bridge 序列化 + 文档, 2026-04-20): 重构 event_serializer.go 把 17 case switch 提取成
eventPayload(evt) (type, payload)helper, Serialize 方法调用 helper 再包上 id/timestamp/sessionID — 让 SubAgentEvent 能递归取 Inner 的 (type, payload) 做扁平合并. 新增 3 case: SubAgentStartEvent →subagent_start{subagent_id, description, cwd, model, start_time_ms}; SubAgentEndEvent →subagent_end{subagent_id, duration_ms, status, result, error}; SubAgentEvent →subagent_event{subagent_id, event_type, ...inner_payload} 扁平 shape (消费端一次 JSON.parse 即可读到归属 + 业务字段, 无 nested unwrap).mergePayloadhelper 处理 JSON object 键合并, 冲突时 extras 胜 (subagent_id / event_type 永远外层优先). 7 sub-claim 测试全绿: Start 五字段 shape + Start 空串 omitempty + End 五字段 shape + End error 非空保留 + Event 扁平 shape (TextEvent inner) + Event ToolUse inner (id/name/input 扁平) + Event 嵌套 SubAgent (外层 ID 胜). docs/api-reference.md push 形态清单加 SubAgentStart/Event/End 三条 + SSE 事件格式章节补 3 个事件 payload 示例; docs/tools.md worktree 模式澄清"真隔离" + 可观测性 cross-reference. baseline 358 → 347 (11 dead fields 全部 wire). 全主题净效果 baseline 352 → 347 (-5): SubAgent.Cwd (commit A 工具 cwd 透传) + SubAgent.Description/StartTime/EndTime (commit B 进 SubAgentStartEvent / SubAgentEndEvent payload, commit C bridge 消费) + SubAgentEvent.SubAgentID (commit C bridge 扁平合入). 端到端产品兑现: Agent 工具 worktree 模式真隔离 (BashToolpwd落在 wtInfo.Path, FileEdit symlink guard 用 worktree 根); 子 agent 活动对父 engine 可见 (TUI 树形 / SSE 子 agent 事件 / observer 审计 sink / session 成本统计按 subagent_id 归属). WorkerResult.Description 单独主题 "Team observability" 分离不在本次 scope (见本档 D-B 档 subagent 族条目下独立主题记录). - commit D ✅ (scope 补完, 2026-04-20): advisor sign-off 前检出的 3 个尾巴一并清: (1) 后台子 agent 观测路径: sa.runLoop ctx 无 emitter 时降级到
sa.ParentEngine.Observer().Event("subagent_*", ...)— RunBackground 的 bgCtx 从 engine.Context() 派生无 emitter, 之前后台子 agent 对审计 sink / 指标系统隐形, 现在经 observer 暴露 subagent_id + event_type + lifecycle 核心字段 (lossy 元数据, 非每内层业务字段 — 对齐 Observer 审计用法, 避免重复 pkg/bridge 已有的 17 case payload builder); (2) 5 个 observer fallback 测试全绿 (Start fields / End fields / InnerEvent metadata / Channel prefers over Observer 避免双发 / SilentEvents 两路都跳过); (3) Team.runWorker 集成测试 (TestRunWorkers_ForwardsSubAgentEventsToParentChannel) 证实 Team 路径也继承 ctx emitter, Worker 启动时 sa.runLoop 把 Start/End 转发到父 Run channel 且 SubAgentID 前后串联不乱 — Dream / skill fork 走同一 sa.runLoop 代码路径推导成立, 不单独加测; (4) sa.Run() channel 契约变更 (bare events, 不再 wrap SubAgentEvent) 写进 godoc + docs/api-reference.md push 形态清单, 标 "Breaking 2026-04-20" 给直接消费 sa.Run() 的外部 SDK 用户迁移指引. 一个未验证披露: commit B 声称"顺带修 RunSync 返回空串 silent bug" (原 wrapper 导致 type switch 匹配不到 TextEvent, resultTexts 永远空) 是基于代码读取 + Go switch 实验推断, 未跑真 LLM 端到端验证 — 两种可能性都让业务变好, 但这是推断而非验证, 下次跑真 Agent 工具时观察输出即可反推. baseline 不变 347. 2026-04-20 晚续 session 验证: scripted provider mock (emit 真 flyto.TextEvent block_stop + UsageEvent end_turn) 驱动 sa.RunSync 端到端, 断言 result 含 "hello" PASS — 推断升为 validated. 见core/pkg/engine/subagent_silentbug_test.go(commit 3edd2eb). - [x]
internal/syslib/bash.RedirectionInfo.SourceFD删除 (2026-04-20): 按 4 问法则审判走 internal/ 包例外删除 路径. 字段 godoc "源 fd(默认 1 for >, 0 for <)" 是描述性默认值, 非引擎行为承诺, struct 头 godoc (116-134) 只列 Heredoc 4 字段不背书 SourceFD. 三个剔除条件同时成立: (1) 包路径internal/syslib/bash, Go 内部规则禁止外部 import, scanner 视野完整; (2) 0 reader / 0 writer (grep 全局只命中定义 + scan-baseline); (3) 同语义冗余 — parser ASTbash.Node根本无 FD 字段,Operator已持 "2>&1" canonical 字符串, 消费者 (pkg/permission bash_security) 都读 Operator 不需要分解 FD 号. wire 路径需先补 parser + 再补消费者两层 speculative, 不走. advisor 复核通过. baseline 353 → 352. - [x]
Metadata.Destructive/ReadOnlygodoc 诚实化 (2026-04-20 晚续 session): 删"用于权限系统的快速判断"承诺 — 无 in-tree 消费者读本字段做权限判断, 权限路径由PermissionClass驱动. 改为 informational 元数据声明 (外部 SDK / TUI / audit 渲染标签 + evolve 工具生成器可用). 双语 godoc. 纯文档改动, baseline 不变. - [x] 大结果截断信号全链路补齐 (2026-04-20 晚续 session):
ToolCallResult.Truncated/StoredPath上游 orchestrator 写了, 下游两条 public surface 全漏 —ToolResultEvent(SSE 推给 HTTP 订阅者) 只 4 字段,OperationEntry(服务端操作日志给审计/rollback) 也没这 2 字段. UI 只能看截断摘要, 审计档案也缺"此次结果已截断"标记. 按 4 问 2 原则: 真 wire 缺口 (上游写下游漏) + exported SDK 可达默认保留. 修: (1)flyto.ToolResultEvent加 Truncated + StoredPath 带双语 SECURITY note (path 是消费层 ResultProcessor 决定, 可能带 sandbox 内部结构); (2)engine.go:4278构造 event 时填入 result.Truncated/StoredPath, 注释说明路径不脱敏 (不是工具输出, 是 ResultProcessor 落盘位置); (3)pkg/engine.OperationEntry加同名 2 字段 + engine.go:4328 Record 时填入; (4)ToolCallResultgodoc 重写 — 说明这 2 字段是 engine → Event/OperationEntry/Bridge → UI/audit 一条信任边界, 3 处 StoredPath 共享同一条安全约束; (5)bridge event_serializer.gotool_result 匿名 struct 加 truncated,omitempty + stored_path,omitempty 避免 L699 C2 同形的 choke-point 吞字段 bug. 3 sub-claim 测试: serializer TruncatedShape 断言 JSON 含 2 key + 值正确; serializer OmitsEmptyTruncation 断言 false/空串 omitempty 不加噪; OperationLog Record_PreservesTruncation 断言往返保真. baseline 净抵消 216 → 216: ToolCallResult 侧 -2 drain, OperationEntry 侧 +2 归档 pull API (外部审计 SDK/报表等激活消费者, rollback 不读). scope: 只补截断信号全链路, tools 族其他 11 字段 (ToolCapability 4 / DryRunResult 3 / Metadata 2 / Result.Data 1 / UndoInfo.Description 1 / OperationEntry 新 2) 各自独立审判不塞本 commit. - [x] Team observability (worker 可见性):
WorkerResult.Descriptionwire 进 task-notification XML (2026-04-20 晚续 session): 按 4 问 + 反向思考 审判. godoc "任务描述(用于追踪)" 意图两路消费 — (A) 调用方读[]WorkerResultSDK exported 默认合法, (B) Leader 读 task-notification XML 反向识别"这是哪个业务任务". 路径 B 原是上游 wire 缺口:runWorker(team.go:435) 填了Description: desc,RunWorkers构造 XML 时只用 WorkerID/status/summary/AgentType/duration (team.go:321-327), Leader 看到的 task-id 是 random hex — 三个并发跑不同 prompt 的 Explore Worker 在 Leader 收件箱完全同形, 无法分辨. 修复:taskNotificationTmpl加<description>%s</description>字段,RunWorkers注入时xmlEscape(r.Description)参数一并塞入. 2 sub-claim 测试:TestTaskNotificationTmpl_FormatOK扩断言<description>南路径探索</description>转义后出现; 新增TestRunWorkers_TaskNotification_CarriesDescription用 pre-canceled ctx 路径 (Worker 快速失败仍走 enqueue 分支) drain notifications 断言 2 条 XML 各含不同 description. 队列原说 "Worker Start/End 事件缺" 信息过期 — Worker 是 SubAgent, Start/End 已由 subagent_start/subagent_end 闭环 (commit D 集成测试证实 team_test.go:285 路径), Team 层无需重复 Worker 事件. baseline 217 → 216. scope 纪律: 只改 team.go + team_test.go + baseline, 不扩到 WorkerEvent 虚构需求. -
[x] turn 边界族 C2:
TokenWarningState.IsAtBlockingLimit严重优先分发 + godoc 诚实化 (2026-04-20): 按 advisor 3 问验证 — (1) blocking 可达但已过锋 (post-turn 时本轮已完成, 下轮 pre-turn maybeCompact + ShouldCompact 兜底, 下层 provider context_length_exceeded 归类为 ErrContextOverflow); (2) 原 emit else-if 链从最弱阈值判起, 新加 blocking elif 会被 critical 分支吞 — 正是 IsAtBlockingLimit 成 dead 字段的根因; (3) godoc 承诺"无法继续对话"是引擎行为, 实际引擎不在此拒绝下轮, 语义造假. 修复: 提取PickWarningCode(state) stringpure function 严重优先分发 (blocking → critical → warning → ""), engine.go:3944 warning emit 用 switch-on-code 替换原 else-if, 新增context_window_blockedcode 带 "上下文窗口已占满, 下轮 pre-compact 将被强制触发" 消息 (可观测信号, 非引擎行为承诺). godoc 重写 IsAtBlockingLimit: 从"无法继续对话" → "100% 占满, 仅 observability signal, 真正兜底是下轮 maybeCompact / forceCompact, 严格蕴含 Error 和 Warning 阈值 true". 加 2 test:TestCalculateWarningState_BlockingImpliesCriticalAndWarning锁 implication chain (blocking → Error + Warning 同 true),TestPickWarningCode_SeverityOrder5 case 穷举 nil / empty / warning-only / critical / blocking 各自返回值. scope 纪律: 不改引擎真拒下轮 (pre-compact 路径已有, 改 engine 行为算另一主题). baseline 354 → 353. -
[x] tools 族深审 (2026-04-21, 12 字段分档归位, 1 真 wire + 11 归档, baseline 213 → 212): 按 4 问 + 反向思考 审判 scanner 标 dead 的 12 字段. 原计划 1 commit 纯归档, 产品经理反向挑战"引擎该 gate 不该甩锅给外部 UI", 拆成 2 commit:
- commit 1 (
f814bd5) MinConfidence safety gate 真 wire: 从 "pull API 归档" 改分类为 "真实现债务". 预检发现ToolCapability.MinConfidencegodoc "最低置信度要求" 暗示引擎 gate 但零 gate site = 造假, 且 LLM 经 prompt 自报置信度是既有能力不需要模型新特性. 三层 wire: (1)capability.go新增 constConfidenceInputField = "_flyto_confidence"+ helperCheckConfidenceGate(cap, input)(MinConfidence=0 原样放行, >0 时解析/拒绝/剥除); MinConfidence godoc 双语 Wire 段明述 buildToolDefs 提示 + orchestrator gate 两层消费路径. (2)orchestrator.executeSingle在tool.Execute前调GetCapability + CheckConfidenceGate, gate fail → ToolCallResult IsError=true + 诊断消息, gate pass → stripped input 传给工具. (3)engine.buildToolDefs对 MinConfidence>0 工具追加 "[Safety] requires _flyto_confidence in input, min=N" 到 Description, 让 LLM 在工具定义层就看到契约. 10 sub-claim test (7 helper + 3 orchestrator 集成 + 1 engine Description 注入). 保留字段 vs schema 字段: 选前者 (下划线前缀表框架字段) 避免侵入工具 InputSchema. 非隐式 100: gate enabled 且字段缺失视为 fail 防 LLM 选择性不声明. builtin 工具不填 MinConfidence 保持零影响, 具体阈值是运营决策. - commit 2 (本轮) 11 字段 pull API 归档 + 2 字段 godoc 诚实化:
- B1 合法 pull API 归档 (9 字段):
ToolCapability.AffectedResources+DryRunResult3 (WouldAffect / Preview / EstimatedImpact) +UndoInfo.Description+OperationEntry.Output/TurnNumber+ImageResult.Width/Height. 消费者在 core 外: audit UI / preview UI / safety dashboard / 外部 rollback UI / 外部审计 SDK. tests 锁 forward (capability_test.go / fileedit_test.go / filewrite_test.go 等), UndoInfo.Description 话术明确"tests 构造不断言 -- exported 字段给外部 rollback UI, 无 internal assert-site" (feedback_verify_real_wire_before_test). struct/字段级 godoc 升级双语 + 写清 pull 消费路径. 和engine.CacheStats/FileStateCacheEntry/PlanApprovalEvent/CheckpointSuggestedEvent等[~]归档同列, 未来 session 不再重审. - B2 godoc 诚实化 (2 字段 UndoMethod/UndoToolName): 原 godoc
"tool"=调用撤销工具暗示引擎 dispatcher 读本字段选 undo 路径, 实际 rollback 走UndoInfo.ToolName(动态, GenerateUndo 捕获) 不读 ToolCapability 静态版. advisor 挑战后诚实化为 "informational 静态声明, 静态给 UI 执行前分类 / 动态给引擎执行时派发, 互补非冗余". 不是删字段 -- 静态和动态都有独立价值 (静态让 UI 不跑也能渲染 "此工具可撤销"). - B3 OperationEntry.Output/TurnNumber 两路径澄清: struct godoc 明述 "OperationLog.GetByMessage() 调取 vs observer 事件 opEventRecorded 里的 turn_number 推送是两个互不相交的 sink, 非冗余". 下次 reader 看到 audit_observer.go:167 也读 turn_number 不会误判为"已有消费者".
- B4 ImageResult.Width/Height 话术: 采纳 advisor 建议 "外部 type-assert 表面 (SDK consumer 经
if img, ok := res.Data.(*ImageResult); ok读)", 不写 "future log/validator" (speculative).
- B1 合法 pull API 归档 (9 字段):
-
baseline 213 → 212 (MinConfidence 从 dead 升 live, 归档 11 字段保留于 scan-baseline.json 意为 "scanner 知道这些在本 module 无 internal consumer, ratchet 保证未来新加的类似位置不悄悄漏掉", 不走 drain).
-
[x] evolve 族深审 (2026-04-21, 11 字段分档归位, baseline 不降): 按 4 问 + 反向思考 审判 scanner 标 dead 的 14 字段 (其中
LLMCallOpts.TemperatureC 档已独立归档,FeedbackRecord5 字段上 session 已合并到Feedback, 本 sweep 处理剩余 11 字段). 分两档结案: - A1 合法 pull API 归档 (7 字段):
AggregatedStats.Sum+ChangeEvent.Change+ChangeEvent.IsLock+ShadowResult.BaselineBreakdown+ShadowResult.CandidateBreakdown+ShadowResult.Meta+ReplayEvent.Meta. 消费者在 core 外 (watch-only 面板读 Stats() / 审计 dashboard 订阅 Watch / 灰度 UI 看 breakdown / 外部 LogReplayer 填 replay 上下文). tests 锁 forward propagation (reflector_impls_test.go/parameter_store_file_test.go/shadow_runner_default_test.go), 两个 Meta 是扩展槽不锁 test. 各 struct godoc 升级双语 + 写清 pull 消费路径 (commit22478e6). 未来 session 不再重审, 和engine.CacheStats/FileStateCacheEntry/PlanApprovalEvent/CheckpointSuggestedEvent等[~]归档同列. - A2 C 方案 evolve→engine adapter 缺口 (6 字段, 独立主题, 等业务场景触发):
RuntimeToolMetadata4 (ConcurrencySafe/ReadOnly/IsEvolved/Version) +ToolResult2 (Output/IsError). 整条 "Agent 自造工具 → Engine 工具注册表 → 模型可见" 能力在 core 内从未接.engine_integration.go:13原注释示范for _, t := range evolver.EngineTools()是造假 — Evolver 类型无 EngineTools() 方法, 无 engine.Tools().Register() 调用点. commit22478e6改顶注释陈述现状: subagent / skill / memory 三路已覆盖 "能力沉淀" 需求, C 方案独有价值是"让模型在工具面板直接看见自己积累的招式" (skill 在 prompt 层积累思路, tool 在注册层积累能力), 在行业 platform (logistics/erp) 遇到 RPA 形态反复任务时显现. 字段保留 exported 让未来 adapter 直接复用 shape. 不排期到当前 sweep, 等真实业务场景 (客户反复跑相同物流查询 / 报表流水) 触发再独立主题接入. LLMCallOpts.Temperature(C 档剩 1 条, 要扩 flyto.Request 跨 provider) 不触, 保持 open 等独立设计决策.- baseline 216 → 216 (全字段保留, 无 drain; 分类话术从 "placeholder" 升为 "已分档结案").
- 缓存族: 本 session 全部处理完毕 —
engine.FileCacheEntry6 字段真 drain,engine.CacheStats3 字段[~]pull API 归档,tools/builtin.FileStateCacheEntry5 字段[~]callback form 归档. - ~~subagent 族~~ 重分类: 非 drain 候选, 是上游消费 bug. 2026-04-20 审判发现 6 字段全部是"上游调用端该读不读": SubAgent.Cwd 被 set 但 BashTool/FileEditTool 继承父 cwd 导致 worktree 隔离失效; SubAgentID 被 set 但 3 处消费路径 (RunSync/RunBackground/记忆提取) 全 drop SubAgentEvent 导致子 agent 对父 engine 完全不可见; StartTime/EndTime 从没进 observer/session stats; Description 从没 emit. 下一主题 "子 agent 观测链路端到端 wire" 处理 (见下).
- ~~独立主题 Team observability~~:
WorkerResult.Description2026-04-20 晚续 session 已完成 (wire 进 task-notification XML, 见 L707 上方新增条目). Worker Start/End 事件不单独实现 — Worker 是 SubAgent, commit D 集成测试证实 team_test.go:285 路径下 subagent_start/subagent_end 已闭环, 重复加 Worker*Event 是虚构需求. - 计划进度族 (
PlanStep/StepProgress/PlanProgressEvent/PlanProgressSnapshot共 5 字段): 进度事件 subscribe 端未读. - bash 剩余: 全部处理完毕 — alpha.8 wire 主字段 (HeredocTag/Body/StripTabs/Quoted),
CommandInfo5 +HeredocInfo4 (2026-04-20 前半 session) drain,RedirectionInfo.SourceFD(2026-04-20 本 session) 经 internal/ 包例外删除 (0 消费者 + parser AST 无 FD 支持 +Operator已持 canonical 字符串 "2>&1", 冗余). - git (
git.Info5): 本 session 已 drain +Run原语落地 (详见 L695 下internal/syslib/git.Info条目). - tools 族: 全部处理完毕 — 2026-04-20
Metadata.Destructive/ReadOnlygodoc 诚实化 +ToolCallResult.Truncated/StoredPathdrain, 2026-04-21Result.Datavision wire drain +MinConfidencesafety gate 真 wire + 余 11 字段分档归档 (详见上方 "tools 族深审 (2026-04-21)" 条目). - cache (
ToolStabilityReport4): 工具稳定性报告未 surface. - permission 次要 (
Response2 +DenyRule1 +LearningStats1 +SedCheckResult1 +SuggestedRule1). - builtin 次要 (
ImageResult2[~]归档 +FileEditResultData2 +GrepResult2 +SkillEntryDesc2 +SedEditInfo1).ImageResult.MediaType/Base642026-04-21 vision wire drain,Width/Height2 字段同日[~]pull API 归档 (见 tools 族深审). - 杂项:
context.RestoreItem/CompactResult,plugin.Plugin/Skill/ValidationResult,execenv.Spec,engine.ProcessedInput/SessionInfo/OperationEntry/FileSnapshot/WorktreeInfo/AgentDefinition.
D-C 档 (注释标 LEGACY 但仍需真 wire, 4 主题 / ~17 字段) — 注释历史措辞不等于"可删". 字段一旦声明就是契约, 默认 wire 保留, 只在枚举完所有 external consumer (SDK/plugin/CLI/platform) 都确认不需要后才考虑 deprecate, 本 sweep 不走该路径:
transport.StreamEvent(9):client.go:14注释标 "LEGACY: StreamEvent/StreamEventType/UsageInfo 类型仍保留" + "StreamEvent 类型从公共 API 消失". public stream 已换 flyto.Event, 但内部 SSE 解析器产物仍是 StreamEvent — wire 方向: 内部 parser → flyto.Event 的 translator 读字段 (BlockID/BlockName/PartialJSON/Usage 等), 再发出 flyto.Event, 让 translator 真正读这些字段.transport.StreamStats(3) +transport.RetryInfo(1): 同 LEGACY 族, stream guard / retry 层诊断字段, 应接 observer 事件或错误消息 surface.query.StreamEvent(4):pkg/querySDK 类型, 即便 internal transport 已换 flyto.Event, query 层消费端应真读字段 (Block/Delta/Type/Usage).retry.OverflowInfo(1): retry 溢出信息, 错误消息或诊断事件 surface.
决策点 (flag, 未启动 drain):
剩 ~20 主题级真债务, 主题密度比 alpha.7 (26 条) 低一档, drain 走 alpha.8 节奏估 2-4 个 session. 选项:
- 启动 D 档 drain — 按 D-A → D-B → D-C 顺序一主题一 commit, 节奏同 alpha.8 (sub-claim checklist + 一 sub-claim 一 test). alpha.9+ 周期.
- 锁 386 切 TODO.md P1 消费层 7 条 (SQL 只读校验器 / DB Dry-run / ML 验证器 / CAS / 熔断 / Staging / 影子表) — 消费层是端到端产品价值点, 真债务是内部洁净度, 优先级由 user 判.
- 局部 drain D-A 档 3-5 高价值主题后切 P1 — 兼顾 (SessionStats/PlanApprovalEvent/DenialStats/ClassifyResult 这类 user-facing 信号先落地, 其余留档).
pkg/evolve.LLMCallOpts.Temperature (C 档剩 1 条) 设计决策 (扩 flyto.Request 跨 provider) 与本 sweep 正交, 保留 open 不强制打勾.
代码风格 / Lint¶
统计¶
最后更新: 2026-04-26 (grep 精确计数 ^[[:space:]]*- \[x\] / ^[[:space:]]*- \[ \], 包括嵌套子条目, 文件内口径可随时 grep -c 核验)
| 状态 | 数量 |
|---|---|
| ✅ 已完成 (文件内保留) | 53 项 |
| 🔴 P0 未完成 | 0 项 |
| 🟡 P1 未完成 | 2 项 (ML 验证 / 熔断, 全 platform 消费层; L407 文档自动化 + L693 SessionStore 2026-04-26 完成) |
| 🟢/⚪ P2/P3 未完成 | 10 项 |
| 总未完成 | 12 项 |
| 总计 | 65 项 (文件内) |
关键观察: 无 P0 阻塞, 核心引擎 22 模块 + 模块 23 SQL 工具链全部 ✅. v0.3.0 于 2026-04-26 发版 (见 CHANGELOG.md "v0.3.0 (2026-04-26)" 段; 上版 v0.2.0 于 2026-04-24, v0.1.0 于 2026-04-18). v0.3 周期含 L569 反事实缩水 + L437 shadowdb + L683 Temp/TopP + L692 业务 REST/SSE + L407 文档自动化三件套 + L693 SessionStore + Postgres 平台化奠基 + ADR-0001/ADR-0002/ADR-0003 立项. 剩 12 项不阻塞 v0.4 骨架, 待后续完成.
剩 12 项分布 (诚实分组):
- core 引擎内部 3 项:
- L488/489/490: CAP-4 自动化 × 3 (Flyto CLI 无头自消费 / CI 触发 / WebSearch 前置, 低优工具效率)
- ~~L569: 反事实工作流引擎级 enforcement~~ (2026-04-25 缩水做 6 commit, ADR-0001 归档原方案 A 否决理由)
- provider 扩展 1 项:
- L454: provider 静态模型表自动更新 (P2, 爬 Anthropic/MiniMax/OpenAI 文档)
- ~~L683: Temperature/TopP cross-provider passthrough~~ (2026-04-25 完成, 7 provider 全接通)
- platform 消费层 8 项:
- L434/435: P1 × 2 — ML 验证 / 熔断 (L436 Staging 2026-04-24 / L437 影子表 2026-04-25 / L692 业务 REST 通道 + L407 文档自动化三件套 + L693 SessionStore 2026-04-26 完成)
- L408: L952c 场景化编排 Go 教程 (P3)
- L438: AuditSink DB 实现 (P3)
- L439: WMS 波次建立参考实现 (P3)
- L571: 微信 ClawBot 接入 (P3)
- ~~L693: 业务 REST 多副本 SessionStore interface~~ (2026-04-26 完成, C1-C4 commit chain
eec48fe → beaff60 → 96e893a → C4. ADR-0003 立, 三层 pin + sticky routing 落档. staging Postgres 跳过待真消费者驱动) - L694: gRPC + REST cross-transport request-id / trace 串通 (P3, 2026-04-26 自 L692 ADR-0002 tracked debt)
- L695: SSE 1000 单/s 带宽监控 (P3, 2026-04-26 自 L692 质疑 agent Q1.3)
口径说明 (2026-04-23 统一):
2026-04-14 及之前用的 "累计 809 / 未完成 56" 口径包含已 archive 出文件的历史完成项, 每次 update 需手动维护易 drift. 2026-04-23 改用文件内 grep 精确口径 (grep -cE "^[[:space:]]*- \[x\]" core/TODO.md), 可随时 verify 永不 drift. CLAUDE.md 同步切换到文件内口径, 不再维护累计历史口径.
近期主要动作 (按 commit 顺序):
- 2026-04-26 L693 SessionStore + Postgres 平台化奠基 (4 commit): 3-agent 并行 review (调研 LangGraph/Vercel/Temporal/Express/Django 业界 prior art / 质疑 6 道击中 3 道含 permCh 物理不可移动 + YAGNI + dead-field-scanner debt / 设计 3 alternatives 选 typed Alt 2) reconcile 后 PM 三轮决策 (Postgres 肯定用 → 整个 platform psql → 拒绝迁移工具+sqlite 走 plain SQL+testcontainers → C3 staging Postgres 跳过待真消费者). commit 顺序:
eec48feC1 SessionStore 接口 (Create/Get/Delete 三方法) + InMemoryStore drop-in 替换 server.sessions map + 4 handler 改造 + TOCTOU race 折叠 (319 行 sessionstore + 改 server.go 182 行);beaff60C2 Postgres 后端 +internal/db/共享池 +--postgres-dsnflag + docker-compose pg + healthcheck + persistent volume + release.yml POSTGRES_PASSWORD secret + testcontainers-go 真 pg 测试 (~510 行 + main.go 53 行 + docker-compose 48 行);96e893aC3 ADR-0003 (387 行 8 节, 三层 pin 物理事实 + sticky routing phase 1 ip_hash + phase 2 X-Session-ID 升级路径 + cache miss 503 fallback) + Caddyfile 注释; 本 commit C4 TODO + CHANGELOG + CLAUDE.md 同步. 真相: 多副本真阻塞是三层进程内 pin (server.permCh + Session.pendingPermissions + engine.sessionState), 后两层在 core 引擎层平台层不能解, 必须 LB sticky routing; SessionStore 价值降级为"replica 重启不丢元数据 + 滚动部署 drain + Postgres audit". 关键决策: drop Redis 档 (元数据 payload 太薄, 共享 staging pg 池更经济); drop staging Postgres 后端 (PM 接受 YAGNI, ADR-0003 § 5.5 登记触发条件 = staging 真接入消费者); engine.SnapshotStore 接线 cache miss 自动恢复历史留 follow-up. 不引正式 migration 工具 (1 张表 plain CREATE IF NOT EXISTS 自检足够). 测试: 6 InMemoryStore + 5 testcontainers Postgres + 2 db pool, 全模块 -race 全绿; baseline 220 不变 (scanner 只扫 core/, 不扫 platform). PM 部署侧必做 (v0.4 release 前): Gitea secrets 配 POSTGRES_PASSWORD. - v0.3.3 发版 (2026-04-26): L407 follow-up 三件套 — A README 文档地图 (commit
fea0d27, 70 行 markdown 串 27+ markdown + 4 入口 + 7 读者分组) + B godoc.flytoex.net 子域 (pkgsite Go API HTML, 子域因 pkgsite href 绝对路径不能挂 sub-path; Dockerfile.godoc 多阶段拷整 monorepo 源 + go mod download all + ENTRYPOINT pkgsite -list=false; 不鉴权对齐 pkg.go.dev) + C docs.flytoex.net 子域 (mkdocs-material@9.5.31 整合站, Dockerfile.docs python:3.12-alpine + nginx:alpine 两阶段; mkdocs.yml docs_dir=/work + config /config/mkdocs.yml sibling 绕开 mkdocs "docs_dir 不能是 config 父目录" 约束; nav 12 分组串 README+CONSUMERS+CONTRIBUTING+FLYTO+ADR-0001/2+CHANGELOG+TODO+7 provider+architecture+writing-guide). DNS 加 2 条 A 记录 (godoc.flytoex.net + docs.flytoex.net → 45.145.229.197 DNS-only 灰云) 经 Cloudflare API token PUT /zones//dns_records, 不走 PM web UI. release.yml 加 godoc + docs 两个 build-push step. 本地 docker build 两 image 实测通 (godoc 61.8s + curl /git.flytoex.net/... 200; docs 5.83s mkdocs build + nginx serve / 200 中文 title 渲染). baseline 219 不变 (纯文档 + deploy infra). 上一变更 v0.3.0/0.3.1/0.3.2 发版 (2026-04-26): CHANGELOG Unreleased (v0.3-dev)→## v0.3.0 (2026-04-26)结构化重组对齐 v0.2.0 段 8 节格式; v0.3.1 hotfix go.sum tidy (golang.org/x/net v0.50.0 transitive missing, GOWORK=off Dockerfile build fail); v0.3.2 hotfix #2 (release.yml deploy script export ANTHROPIC_API_KEY + Gitea API PUT secret, 用 ~/.git-credentials 里 yuanwei token 自动配). 覆盖面: counterfactual + reverse_think + shadowdb + Temp/TopP + L692 业务 REST/SSE + L407 文档自动化三件套 + ADR-0001/ADR-0002 立项. push tag v0.3.0/0.3.1/0.3.2 触发 release.yml: dead-field-ratchet → docs drift gate (v0.3.0 新加) → buildx 4 image (含本版加的 godoc + docs) → SSH HK-133 deploy → caddy restart 让 /swagger/* + godoc.flytoex.net + docs.flytoex.net 立即生效. - 2026-04-26 L407 消费层文档自动化三件套 (7 commit, 含 1 path bug 顺手修): queued task 锁定 swag (注解式 OpenAPI 2.0) > huma (code-first 要重写 1263 行 server.go) 路线; SDK 自动生成 (Stainless 模式) 不做 rule of two 等 5+ 语言客户端. commit 顺序:
89c38d3C0 顺手修部署 path bug/v1/* → /api/v1/*(Caddyfilehandle /api/v1/*不剥前缀致 server.go 注册/v1/*经 hub.flytoex.net 全 404, 上一会话 commit 5 没真实经 Caddy 实测, 触发 memoryfeedback_validate_network_path_before_deploy);26bc732C1 server.go 8 handler swag 注解 + 3 named response type (HealthResponse/StatusResponse/ListToolsResponse) 替代 ad-hoc map + swag.go seed + docs/{swagger.json 22.5K 12 schema, swagger.yaml 12.3K, docs.go 23.1K Go embed} 首版;bce7670C2 cmd/common --swagger flag + Swagger UI endpoint (httpSwagger v2 包内嵌, side-effect import docs, authMiddleware/rateLimit allow-list 加 /swagger/);22b6388C3 core/Makefile docs-swag/grpc/consumers/all 4 target + tool install (swag@v1.16.6 + protoc-gen-doc@v1.5.1 pin 与 staticcheck@v0.7.0 同模式) + ROOT git rev-parse + 顶部 export PATH 含 GOPATH/bin + grpc-api.md 首版 278 行 + .gitea/release.yml docs drift gate (apt-get protoc + make docs-install + docs-swag/grpc + git diff --exit-code 4 产物);a9b04abC4 docs/CONSUMERS.md 顶层 wrapper 133 行 (端口拓扑/env/flag/OIDC auth 流程图含 allow-list/业务 REST 一次性+多轮会话 curl 例子/观测 gRPC SafetyChain 指引/进一步阅读链);bf5af1dC5 Caddyfile handle /swagger/ → common:8080 + docker-compose --swagger flag (HK-133 lab 默认开, 生产另份 compose 关); 本 commit C6 TODO/CHANGELOG/CLAUDE.md 同步. CI drift gate 与 dead-field-ratchet 平级在 build-push job 开头, 业界对照 Stripe/Anthropic/OpenAI 都对 OpenAPI spec 跑同等闸 (PR 必须 commit 生成产物). smoke: ANTHROPIC_API_KEY=fake go run ./cmd/common --rest-addr=:18080 --swagger → /api/v1/health 200 + /swagger/index.html 200 + /swagger/doc.json 200 返回 commit 1 嵌入 spec; build + -race 全绿. 三件套全产: 业务 REST swagger.json (12 schema) + 观测 gRPC grpc-api.md (HealthService + SafetyChainService 字段表) + CONSUMERS.md (端口/env/flag/auth 流程/curl 例子). 不做*: SDK 自动生成 (Stainless 模式 rule of two, 等 5+ 语言客户端); .proto 字段注释完善 (health.proto 部分字段 description 列空, 后续工作). - 2026-04-26 L692 platform/common 业务 REST/SSE 通道激活 (6 commit): 3-agent review reconcile (调研 11 LLM API + grpc-gateway 健康度 / 质疑 6 道含 raw bearer auth 与 OIDC 不兼容致命 + grpc-gateway 与 admin 重复致命 / 设计 4 备选 + 推荐 A 修正版), PM 拍板. commit 顺序:
01f08e7C1 server.go 拆 buildHandler/Serve/ListenAndServe-wrapper 让出 signal handling;8189d05C2 Verifier 替代 BearerToken 走 auth.HTTPMiddleware (raw shared-secret + ConstantTimeCompare 删除, dev 模式 Verifier=nil 与 admin 一致);694bd07C3 server.New 接受外部 engine 不再内嵌 anthropic provider 写死, 加 Attach + HandlePermission 两 API;e1db327C4 cmd/common 加--rest-addrflag, 装配 anthropic provider + engine + s.Attach + 第三 listener wire (signal handler 三路协调 grpc.GracefulStop / httpSrv.Shutdown / restCancel, errCh capacity 升 3);c35e761C5 docker-compose expose 8080 + command 加 --rest-addr=:8080 + ANTHROPIC_API_KEY 必填 environment, Caddyfile/api/v1/*→ common:8080 (flush_interval -1 + response_header_timeout 0 SSE 透传), README topology + curl 例子同步; 本 commit C6 ADR-0002 + 文档同步. 核心决策: REST/SSE 唯一业务通道 + gRPC 仅观测面 (SafetyChain / Health) + 不为 C# 单独加业务 RPC + 不加 grpc-gateway (admin 已有观测面 REST handler) + Tool 级 SafetyChain 装饰留给行业 platform (cmd/common 保持纯 transport, verdictStore 接线就绪等行业写数据). 业界对照: 11 LLM API 全 REST/SSE 单通道, 业界共识与 PM 方向对齐. 4 tracked debt 登记 (L693 多副本 SessionStore P2 / L694 cross-transport request-id P3 / L695 SSE 带宽监控 P3 / L407 Swagger 与 ADR-0002 关联). 测试: server_test.go 既有 546 行用 httptest 直接打 handler 不动, 删 4 raw bearer TestAuth_*, 加 1 ctx 测试. -race 全绿. cmd/common --help 验证 --rest-addr flag 出现. - v0.2.0 发版 (2026-04-24): CHANGELOG
Unreleased (v0.2-dev)→## v0.2.0 (2026-04-24)结构化重组对齐 v0.1.0 段格式 (核心新增 / platform/common 层 / 关键设计原则 / 已知限制 / 发布事实 / 详细变更); 新起## Unreleased (v0.3-dev)空段. 覆盖面: evolve 9/9 矩阵 + SQL 工具链 × 3 + validator/circuitbreaker/reflector/staging 4 新子包 + safety chain C1-C4 platform/common 装配+观测+gRPC. Baseline 212 → 216 (+4 合法 tracked debt). TODO 46 → 47 done / 15 → 14 open. - (2026-04-24, staging 子包):
pkg/staging/commit 3/3 完成 (L436 check off) —Engine混合控制状态机 (Stage / ValidateTech / ValidateBiz 内部主动推进, MarkExecuted / MarkFailed 外部推 arc 薄转发) + fail-closed 语义 (Validator error / DependencyGuard error 均合成 Block verdict 或 ErrDependencyDenied, 不静默放行) + 内置TenantDenyGuard示例 (metadata-driven guard 典型形态). ~530 行 (含 14 engine test + 内置 guard). baseline 218 → 216 (Record.Diff / Record.Metadata drain); 剩余 4 条 (TechVerdict/BizVerdict/ExecutionError/ExecutionProof) 合法 tracked debt — "外部 audit dashboard 消费, core 无内部 reader" 形态, 按 memoryfeedback_exported_field_delete_needs_review.md. 2c38e46(2026-04-24):pkg/staging/commit 2/3 —Store接口 (9 方法) +InMemoryStore参考实现. MarkExecuted 幂等 first-write-wins 保 proof, MarkFailed 幂等保 reason. 17 test 含 2 race 并发 (ID collision / CAS race). baseline 223 → 218 (9 drain + 4 新 dead).d9992d5(2026-04-24):pkg/staging/commit 1/3 — 7 状态机 + Record + DependencyGuard interface + AllowAlwaysGuard. 决策包级 record, 做法 I 整体打包. baseline 212 → 223 (tracked debt 登记 + exit criteria 声明).979a304(2026-04-24):pkg/reflector/umbrella 包 — 表达 "反射器" 产品抽象, 不引新接口, 4 adapter (ValidatorAsEvaluator / EvaluatorAsValidator / ValidatorAsReflector / EvaluatorAsReflector) 跨家族互转. 反向 Reflector → Validator/Evaluator 刻意不做. Option d 胜 Option a (Agent Teams 3 角色 review: 真合并违 Go 惯例 + sync/async 语义不可同一接口). tracked debt: GA 场景若需 "按 fitness 级别映射 Severity" 的连续分级, 需加WithSeverityFunc(func(fitness) Severity)option; 当前二值 (Warn/Block) 是 validator.Severity 的物理约束.1a08c47(2026-04-24): C4 platform/common 安全链 gRPC 暴露 —safetychain.proto(2 RPC: ListVerdicts / ListBreakerStates) +SafetyChainServer+ cmd/common wire. 候选 A 端到端闭合 (core + common 装配 + HTTP 观测 + gRPC). 工具链 install protoc-gen-go / protoc-gen-go-grpc 到 $GOPATH/bin (一次性).753ec03(2026-04-24): C3 platform/common admin 观测端点 —VerdictStore+RingStore+admin.WithSafetyChain+ 2 新 HTTP 端点 (verdicts / breakers). 鉴权和 /admin/tenant 同级, opt-in 才挂载默认 404.cb8cd2f(2026-04-24): C2 platform/common safetychain 装配层 —Assemble()一行装配 +BreakerScopePolicy三工厂 (NoOp/DestructiveOnly/PerTool) +BreakerRegistry. 无默认显式 opt-in, 行业 platform 自选 backend + 作用域.1b0a860(2026-04-24): C1 core 安全链 enforcement —validator.AlwaysApprove{}显式 opt-out +NewValidatedTool构造期 nil panic. 候选 A (platform 装配框架) 启动前的 core-level enforcement, 消灭 "以为开了审批实际没开" 的静默安全假象.981a2ea(2026-04-23): 模块 23 立项归档 + 消费层分类翻盘 (SQL 3 件套从 "不属于引擎层" 挪入核心)a935604(2026-04-23): SQL Dry-run 三路 (UPDATE/DELETE/INSERT, 方案 E before+after SELECT)bf31278(2026-04-23): SQL CAS 乐观锁 (StagingDB newtype + maxRetries=0 fail-fast,modernc.org/sqlitetest-only dep)79670c7(2026-04-23): SQL 只读校验器 (纯字符串 quote-aware 解析 0 DB 依赖)- 2026-04-23 doc drift 修复 (本 commit): CHANGELOG "已知限制" 移除 SQL 条 +
v0.2-dev段加 SQL 工具链纪念段; 本统计块切换文件内口径; CLAUDE.md 分层统计对齐 (引擎 4 / provider 2 / platform 9); memoryproject_version_roadmap.mdv0.1 发版事实更新.