# Flyto Agent - 细节补齐清单 > **归档**: 已完成的 815 项见 [TODO_DONE.md](./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, 引擎层仅 import `database/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`) - `StagingDB` newtype + `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/sqlite` test-only dep (core 第一条非图像处理第三方依赖, 仅 `_test.go` import) ### 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) - `DryRunResult` 3 字段首次 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: `89c38d3` C0 path bug fix `/v1/* → /api/v1/*` (Caddyfile + ADR-0002 + server.go 8 mux 路由 + server_test.go ~25 处 + main.go 注释); `26bc732` C1 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} 首版; `bce7670` C2 cmd/common --swagger flag + Swagger UI endpoint (httpSwagger v2 + side-effect import docs, authMiddleware/rateLimit allow-list 加 /swagger/); `22b6388` C3 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); `a9b04ab` C4 docs/CONSUMERS.md 顶层 wrapper 133 行 (端口拓扑/env/flag/OIDC auth 流程图/业务 REST 一次性+多轮会话 curl 例子/观测 gRPC SafetyChain 指引/进一步阅读链); `bf5af1d` C5 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`) Caddyfile `handle /api/v1/*` 不剥前缀, server.go mux 注册 `/v1/*` 不匹配, 经 hub.flytoex.net 全 404, L407 之前先打通真实部署链 (memory `feedback_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 天前 memory `feedback_architecture_principle_over_rule_of_two.md` 的 "gRPC 优 HTTP" 是分层不是反悔). **commit 顺序**: `01f08e7` C1 server.go 拆 Serve+wrapper 让出 signal handling; `8189d05` C2 Verifier 替代 BearerToken 走 auth.HTTPMiddleware (raw shared-secret + ConstantTimeCompare 删除, OIDC 与 admin 一致); `694bd07` C3 Attach + HandlePermission 拆 anthropic provider 写死, server 不再读 ANTHROPIC_API_KEY 不再 hard-code 模型; `e1db327` C4 cmd/common 加 `--rest-addr` flag 装配 anthropic provider + engine + s.Attach + 第三 listener wire (signal handler 三路协调: grpc.GracefulStop / httpSrv.Shutdown / restCancel); `c35e761` C5 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_RespectsCtx` ctx 取消干净返回. -race 全绿. cmd/common binary 集成验证 `--help` 显示 `--rest-addr`. 实测 (docker exec curl + SSE chunk timing) 留 push tag 前按 memory `feedback_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 顺序**: `eec48fe` C1 SessionStore 接口 (Create/Get/Delete 三方法, 不要 Touch/List 投机) + InMemoryStore drop-in 替换 server.sessions map + 4 handler 改造 + TOCTOU race 折叠 (`319 行 + 改 server.go 182 行`); `beaff60` C2 Postgres 后端 + `internal/db/` 共享池 (中央 schema 权威 platformMigrations + Migrate 启动期 idempotent) + `--postgres-dsn` flag + docker-compose pg service + healthcheck + persistent volume + release.yml POSTGRES_PASSWORD secret + testcontainers-go 真 pg 测试 (`~510 行 + 改 main.go 53 行 + docker-compose 48 行`); `96e893a` C3 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_second` metrics, 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 顺序**: `248253e` C1 `core/pkg/counterfactual/` Deliverable schema (五步反向思维标准化数据结构, MetadataKey "flyto.counterfactual.deliverable" 跨包 Record.Metadata 落点); `0385efd` C2 `core/pkg/skills/reverse_think/` MiniMax Anthropic 兼容端点 Go 化 client (替代 `~/.claude/skills/reverse-think/SKILL.md` 软性 markdown 在生产 Agent 不可调的 gap); `c4b755f` C3 `tools.Metadata.RequiresReverseThinking` opt-in flag (与 RequiresCheckpoint 同源 rule of two); `4618b79` C4 `Deliverable.AsReplayEvent` → `evolve.LogReplayer` 跨包 adapter (counterfactual import evolve 单向, evolve schema-agnostic 不感知 counterfactual; 关上 PM 担心的 "各行业自写 skill 进化结果停在哪里" 循环); `40aae31` C5 `platform/common/safetychain/ReverseThinkingHook` reference 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)` + **真设计意图达成**: compactor `truncateAndRetryCompact` 接 `WithTokenGap` option, 从 API 精确溢出值一步跳步 (字段 godoc 承诺的"让压缩模块一步跳过 N token 的消息组"兑现), 带 `TestTruncateAndRetryCompact_TokenGapStride` 锁定 (2026-04-19) - [x] `engine.Config.Verbose` — engine.New 尾 `verbose_startup` + runLoop 尾 `verbose_run_loop_started` trace (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 parseList `op=="&" → list.Background=true` + 尾部孤立 `&` wrap 单 child NodeList (Bash 语义: `cmd &` 把 cmd 放后台). (b) extract.go extractContext 加 `background bool`, 两处 NodeList 分支 (extractFromNode + extractAllFromNode) 实现 "left 继承 / right 清掉" 传播: `cmd1 & cmd2` cmd1 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 新 helper `amplifyBackground(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 包新增公共 helper `ResolveHeredocBody(redir)`: `<<-` 形式返回 strip 行首 tab 后的 body (匹配 bash 运行时), 普通 `<<` 原样返回, nil/非 heredoc 返回 "". bash_security.go `IsDangerousCommand` + `AnalyzeDanger` 用 ResolveHeredocBody 拼 checkStr, 对 body 做 dangerous-file 字面检测 (过去 `cat > out < 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) `Evolver` struct 加 `autoApproveReadOnly bool` + `New()` 赋值. (2) `Propose()` 审批逻辑前置 short-circuit: `autoApproveReadOnly=true && isReadOnlyEvolution(proposal) → approved=true` 绕过 approvalFunc. (3) `isReadOnlyEvolution` helper 刻意收窄, 当前**仅** `EvolveNewSkill` 符合 (只写 markdown, 不执行代码); `EvolveNewTool`/`EvolveOptimize`/`EvolveSelfAdjust` 即便标称 read-only 也不 auto-approve, 因其内容会执行代码或改运行时. (4) 新 `evolution_auto_approved` observer 事件与 `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_overridden` WarningEvent). **不**加 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` 加 `dangerousEnvVarPrefixes` map (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 / 审计渲染. 顺带 drop `CommandInfo.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` 方法, 返回 `"/"` 用于日志 / 错误消息 / 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_stride` observer 事件扩 `dropped_group_indices []int` payload, 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 + `parseLLMVerdict` normalise 读 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() []string` sorted). - **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` 可直接作为 `Assemble` sink 不需 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 等价); Severity / State 用 string 不用 enum (第三方 Validator 前向兼容); nil Store / Registry 返空列表不报错 (观测端点不把"没东西"和"服务挂"混淆). 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.CreatedAt - `Session.ShadowTable` — 外部 consumer 在 SQL 里引物理表名, decorator 与 EnforceSessionFilter 也可读取. core makeCloser 走 trackedSession.shadowTable 闭包不读 sess.ShadowTable - `Session.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_crossed` observer 事件. trackEvents 尾部 30 行代码抽取为新方法 `applyTurn` (方便测试, 也解耦 emit 逻辑). 引入包级常量 `costThresholdsUSD = []float64{1,5,10,50,100}` 和 helper `crossedCostThresholds(last, cost) → []float64` (返回 half-open 区间 `(last, cost]` 内的升序档位, 支持单轮跨多档). Session 加 `lastCostThresholdEmitted float64` guard 防同档重复 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-switch `case *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.FileCacheEntry` 6 字段真 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.CacheStats` 3 字段 (Entries/MaxSize/Evictions) `[~]` 归档**: 已在 docs/api-reference.md 列为 pull API (和 SessionStats/DenialStats 同列), godoc 升级双语写清消费形态 "调取 pull, 消费者主动调 FileStateCache.Stats() 读字段, scanner 视野内无内部 reader 是期望状态, 不强加内部 reader 过扫描器". 不减 baseline. - **`tools/builtin.FileStateCacheEntry` 5 字段 `[~]` 归档**: 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_suggested` observer 事件 payload (`heredoc_body_start` / `heredoc_body_end` key, 零值归因非 heredoc 场景时跳过). Reason clause 同时带 "source bytes N-M" 文本让人类可读 log 也承载位置. 回归 test 一主题一 sub-claim: `TestPreprocessHeredocs_BodyStartEndAddressesOriginalSource` 4 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.8 `Background` 字段同系 (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.Info` 5 字段 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.go` `detectGitInfo` 替换为 `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.Executor` DI 层 (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/../.. 越狱). 修复: export `validateRef` → `ValidateRef` (GetDiff 内部调用点同步), NewGitSyncAdapter defaulting 块后一次调 `gitlib.ValidateRef(remote)` + `gitlib.ValidateRef(branch)`, bad 值 panic (风格对齐既有 nil Executor panic). 加 2 test: `TestNewGitSyncAdapter_RejectsInjectedRemote` (`--upload-pack=evil` remote) + `TestNewGitSyncAdapter_RejectsPathTraversalBranch` (`feat/../etc` branch). 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). `mergePayload` helper 处理 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 模式真隔离 (BashTool `pwd` 落在 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 AST `bash.Node` 根本无 FD 字段, `Operator` 已持 "2>&1" canonical 字符串, 消费者 (pkg/permission bash_security) 都读 Operator 不需要分解 FD 号. wire 路径需先补 parser + 再补消费者两层 speculative, 不走. advisor 复核通过. baseline 353 → 352. - [x] `Metadata.Destructive/ReadOnly` godoc 诚实化 (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) `ToolCallResult` godoc 重写 — 说明这 2 字段是 engine → Event/OperationEntry/Bridge → UI/audit 一条信任边界, 3 处 StoredPath 共享同一条安全约束; (5) `bridge event_serializer.go` tool_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.Description` wire 进 task-notification XML (2026-04-20 晚续 session): 按 4 问 + 反向思考 审判. godoc "任务描述(用于追踪)" 意图两路消费 — (A) 调用方读 `[]WorkerResult` SDK 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` 加 `%s` 字段, `RunWorkers` 注入时 `xmlEscape(r.Description)` 参数一并塞入. 2 sub-claim 测试: `TestTaskNotificationTmpl_FormatOK` 扩断言 `南路径探索` 转义后出现; 新增 `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, 不扩到 Worker*Event 虚构需求. - [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) string` pure function 严重优先分发 (blocking → critical → warning → ""), engine.go:3944 warning emit 用 switch-on-code 替换原 else-if, 新增 `context_window_blocked` code 带 "上下文窗口已占满, 下轮 pre-compact 将被强制触发" 消息 (可观测信号, 非引擎行为承诺). godoc 重写 IsAtBlockingLimit: 从"无法继续对话" → "100% 占满, 仅 observability signal, 真正兜底是下轮 maybeCompact / forceCompact, 严格蕴含 Error 和 Warning 阈值 true". 加 2 test: `TestCalculateWarningState_BlockingImpliesCriticalAndWarning` 锁 implication chain (blocking → Error + Warning 同 true), `TestPickWarningCode_SeverityOrder` 5 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.MinConfidence` godoc "最低置信度要求" 暗示引擎 gate 但零 gate site = 造假, 且 LLM 经 prompt 自报置信度是既有能力不需要模型新特性. 三层 wire: (1) `capability.go` 新增 const `ConfidenceInputField = "_flyto_confidence"` + helper `CheckConfidenceGate(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` + `DryRunResult` 3 (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). - 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.Temperature` C 档已独立归档, `FeedbackRecord` 5 字段上 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 消费路径 (commit `22478e6`). **未来 session 不再重审**, 和 `engine.CacheStats`/`FileStateCacheEntry`/`PlanApprovalEvent`/`CheckpointSuggestedEvent` 等 `[~]` 归档同列. - **A2 C 方案 evolve→engine adapter 缺口 (6 字段, 独立主题, 等业务场景触发)**: `RuntimeToolMetadata` 4 (ConcurrencySafe/ReadOnly/IsEvolved/Version) + `ToolResult` 2 (Output/IsError). 整条 "Agent 自造工具 → Engine 工具注册表 → 模型可见" 能力在 core 内从未接. `engine_integration.go:13` 原注释示范 `for _, t := range evolver.EngineTools()` 是造假 — Evolver 类型无 EngineTools() 方法, 无 engine.Tools().Register() 调用点. commit `22478e6` 改顶注释陈述现状: 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.FileCacheEntry` 6 字段真 drain, `engine.CacheStats` 3 字段 `[~]` pull API 归档, `tools/builtin.FileStateCacheEntry` 5 字段 `[~]` 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.Description` 2026-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), `CommandInfo` 5 + `HeredocInfo` 4 (2026-04-20 前半 session) drain, `RedirectionInfo.SourceFD` (2026-04-20 本 session) 经 internal/ 包例外删除 (0 消费者 + parser AST 无 FD 支持 + `Operator` 已持 canonical 字符串 "2>&1", 冗余). - git (`git.Info` 5): 本 session 已 drain + `Run` 原语落地 (详见 L695 下 `internal/syslib/git.Info` 条目). - tools 族: 全部处理完毕 — 2026-04-20 `Metadata.Destructive/ReadOnly` godoc 诚实化 + `ToolCallResult.Truncated/StoredPath` drain, 2026-04-21 `Result.Data` vision wire drain + `MinConfidence` safety gate 真 wire + 余 11 字段分档归档 (详见上方 "tools 族深审 (2026-04-21)" 条目). - cache (`ToolStabilityReport` 4): 工具稳定性报告未 surface. - permission 次要 (`Response` 2 + `DenyRule` 1 + `LearningStats` 1 + `SedCheckResult` 1 + `SuggestedRule` 1). - builtin 次要 (`ImageResult` 2 `[~]` 归档 + `FileEditResultData` 2 + `GrepResult` 2 + `SkillEntryDesc` 2 + `SedEditInfo` 1). `ImageResult.MediaType/Base64` 2026-04-21 vision wire drain, `Width/Height` 2 字段同日 `[~]` 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/query` SDK 类型, 即便 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. 选项: 1. **启动 D 档 drain** — 按 D-A → D-B → D-C 顺序一主题一 commit, 节奏同 alpha.8 (sub-claim checklist + 一 sub-claim 一 test). alpha.9+ 周期. 2. **锁 386 切 TODO.md P1 消费层 7 条** (SQL 只读校验器 / DB Dry-run / ML 验证器 / CAS / 熔断 / Staging / 影子表) — 消费层是端到端产品价值点, 真债务是内部洁净度, 优先级由 user 判. 3. **局部 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 顺序**: `eec48fe` C1 SessionStore 接口 (Create/Get/Delete 三方法) + InMemoryStore drop-in 替换 server.sessions map + 4 handler 改造 + TOCTOU race 折叠 (319 行 sessionstore + 改 server.go 182 行); `beaff60` C2 Postgres 后端 + `internal/db/` 共享池 + `--postgres-dsn` flag + docker-compose pg + healthcheck + persistent volume + release.yml POSTGRES_PASSWORD secret + testcontainers-go 真 pg 测试 (~510 行 + main.go 53 行 + docker-compose 48 行); `96e893a` C3 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 顺序**: `89c38d3` C0 顺手修部署 path bug `/v1/* → /api/v1/*` (Caddyfile `handle /api/v1/*` 不剥前缀致 server.go 注册 `/v1/*` 经 hub.flytoex.net 全 404, 上一会话 commit 5 没真实经 Caddy 实测, 触发 memory `feedback_validate_network_path_before_deploy`); `26bc732` C1 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} 首版; `bce7670` C2 cmd/common --swagger flag + Swagger UI endpoint (httpSwagger v2 包内嵌, side-effect import docs, authMiddleware/rateLimit allow-list 加 /swagger/); `22b6388` C3 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 产物); `a9b04ab` C4 docs/CONSUMERS.md 顶层 wrapper 133 行 (端口拓扑/env/flag/OIDC auth 流程图含 allow-list/业务 REST 一次性+多轮会话 curl 例子/观测 gRPC SafetyChain 指引/进一步阅读链); `bf5af1d` C5 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 顺序**: `01f08e7` C1 server.go 拆 buildHandler/Serve/ListenAndServe-wrapper 让出 signal handling; `8189d05` C2 Verifier 替代 BearerToken 走 auth.HTTPMiddleware (raw shared-secret + ConstantTimeCompare 删除, dev 模式 Verifier=nil 与 admin 一致); `694bd07` C3 server.New 接受外部 engine 不再内嵌 anthropic provider 写死, 加 Attach + HandlePermission 两 API; `e1db327` C4 cmd/common 加 `--rest-addr` flag, 装配 anthropic provider + engine + s.Attach + 第三 listener wire (signal handler 三路协调 grpc.GracefulStop / httpSrv.Shutdown / restCancel, errCh capacity 升 3); `c35e761` C5 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" 形态, 按 memory `feedback_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/sqlite` test-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); memory `project_version_roadmap.md` v0.1 发版事实更新.