重构:删 5 零引用 crate(df-evolve/plugin/stages/task/traceability)+ 清死模块、ai.rs 拆 11 子 module、ai.ts 拆 6 composable、i18n 拆目录 功能:知识库全栈(df-project/scan + CRUD + 时间线 + 前端)、Settings 拆分、appSettings KV 迁移、模型池、LLM 并发 Semaphore 修复:审批持久化根治、ConditionEngine 默认拒绝、NodeRegistry unimplemented 清除、promote 补偿删除、工具结果截断 50KB、路径校验防 symlink 逃逸 文档:B-03 人工审批设计、决策记录三分档、规格契约自检、经验记录、todo 看板、PROGRESS 更新 详见 PROGRESS.md。src-tauri/儿童每日打卡应用/ 与本项目无关,已排除。
473 lines
66 KiB
Markdown
473 lines
66 KiB
Markdown
# 功能决策记录
|
||
|
||
> 日常开发中对各功能做的**需求规格 + 设计决策规格**(功能粒度,补 [Phase 1 架构决策](./Phase1架构决策.md) 之下的实现层选择)。聚焦「要做什么 / 为什么这么定」,便于日后回溯。
|
||
>
|
||
> 创建:2026-06-12 | 范围:Sprint 5–10 | 维护:随开发追加
|
||
|
||
## 约定
|
||
|
||
**判断标准**:3 个月后回看,这条是否仍影响对系统/功能设计的理解?是 → 留本文档;否 → 分流。
|
||
|
||
**本文档只记两类**:
|
||
- **设计决策规格**(✅ 已落地 / 🚧 待实测 / 📐 设计未实施)——「为什么这么定」。三要素:决策 → 原因/取舍 → 状态。来源标 `[Sprint N]` 或 `[日期]`。
|
||
- **需求规格 / 待办**(📋)——「要做什么 / 为什么需要」。与 PROGRESS 流水区分:这里记「要做什么 / 为什么需要」,PROGRESS 记「做了啥」。
|
||
|
||
**经验性内容**(踩坑 / 约定 / 技巧 / bug 排查教训)→ [经验记录.md](./经验记录.md)。
|
||
**老条 / 纯流水 / UX 微调 / 已被取代** → [功能决策记录-归档.md](./功能决策记录-归档.md)。
|
||
|
||
记录规则见 [文档记录规范](./文档记录规范.md)。
|
||
|
||
## 人机协同设计基准
|
||
|
||
### AI coding 下的「过度设计」判断基准 [2026-06-13]
|
||
- **决策**:项目为一人开发 + 全程 AI coding(人定方向/审查,AI 实现),代码被 AI 反复读写。权衡设计时采用新基准——**AI 反复读写的代码,「结构清晰」和「隐性耦合显式化」权重高于传统判断**;但「过度抽象」(多层 trait/Builder/工厂)仍不做,因 AI 读简单直白代码 > 读层层抽象。
|
||
- **原因/取舍**:① AI 每次理解代码靠注释和结构(比人更依赖),1600 行单文件(如 AiChat.vue)消耗大量 context,拆分反而降低 AI 理解成本;② 隐性依赖(如分离窗口 localStorage 跨 webview)人凭经验避开、AI 易踩坑。故:组件拆分从「不做」升为「值得做」;隐性耦合早修或显式标注。③ 规模没到的优化(list_all LIMIT、白名单拆表)仍按数据量客观判断,不因 AI coding 而变。
|
||
- **状态**:📐 基准原则(指导后续取舍)
|
||
|
||
## AI Chat 可靠性
|
||
|
||
### 流式可靠性三重保险 [Sprint 6 + 2026-06-13]
|
||
- **决策**:① reqwest Client 加 `connect_timeout(30s)`,**不设请求总 timeout**;② `stream_llm` 用 `tokio::time::timeout(120s)` 包**单个** `stream.next()`(idle 间隔),不包整个流;③ 前端 stores/ai.ts 加 streaming watchdog——发送启动 60s 计时,收到 AiTextDelta/工具事件/审批结果重置,AiApprovalRequired 暂停(审批等待不计),AiCompleted/AiError 清除;60s 无活跃事件则置 streaming=false + push 错误「响应中断」。
|
||
- **原因/取舍**:连接阶段防无限 hang;总 timeout 会误砍流式长生成任务(流式可持续数分钟)。idle 120s 防「连上后中途静默」无限 hang;只卡单 chunk 间隔,不卡总时长。前端 60s 独立计时(短于后端 120s)双保险——后端任何路径漏发收尾(崩溃/事件丢失/agent loop 异常退出)前端永久 streaming=true 卡死。审批等待暂停(不计超时)避免误判用户思考。
|
||
- **边界**:审批组件未渲染(见「需求与待办·审批可见性缺口」)时,AiApprovalRequired 暂停后永久卡,watchdog 救不了,需审批可见性兜底。
|
||
- **状态**:✅ Sprint 6 + 2026-06-13
|
||
|
||
### 断连丢弃残缺响应
|
||
- **决策**:维护 `finished_received` 标志;流尽未收到 finished 信号 → emit AiError 并**丢弃残缺响应,不当完整入库**。
|
||
- **原因**:防脏历史污染对话记录(半截回复入库后无法续接)。
|
||
- **状态**:✅ Sprint 6
|
||
|
||
### 停止生成:保留已生成文本
|
||
- **决策**:`AiSession.stop_flag: Arc<AtomicBool>` + 多检查点响应;停止后**保留已生成文本**。
|
||
- **原因**:用户主动停止 ≠ 丢弃成果,已输出内容有价值。idle(无输出)时最多等 120s(P2 可用 `tokio::sync::Notify` 优化为绝对即时)。
|
||
- **状态**:✅ Sprint 6(运行时待实测)
|
||
|
||
### 切对话:从「拒绝切换」演进到「不中断路由」
|
||
- **决策**:Sprint 6 生成中**拒绝切换**(防 `active_conversation_id` 被改致旧 loop 串台写库)→ Sprint 8 改为**后台对话按 `conversation_id` 路由,生成中可切换不打断**。
|
||
- **原因**:拒绝切换体验差;后端给所有 event 加 `conversation_id` + spawn 前快照 conv_id + 前端按 id 路由(后台对话事件不污染当前视图),既不串台又不打断。
|
||
- **状态**:✅ Sprint 8(部分场景待实测)
|
||
|
||
## AI Chat 工具调用与审批
|
||
|
||
### Agentic Loop 最多 10 轮
|
||
- **决策**:`run_agentic_loop` 上限 10 轮(`MAX_AGENT_ITERATIONS`)。
|
||
- **原因**:防失控循环;单链 ReAct 10 轮覆盖绝大多数任务。超出需规划式(B 路线)。
|
||
- **状态**:✅ Sprint 5
|
||
|
||
### 风险门控:Low 自动 / Medium+High 审批
|
||
- **决策**:工具按 `RiskLevel` 分级,Low 自动执行,Medium/High 暂停等人工审批。
|
||
- **原因**:读操作放行,写/删操作把关——可靠性 vs 效率的平衡点。
|
||
- **状态**:✅ Sprint 5
|
||
|
||
### `tool_calls` 按 index 排序
|
||
- **决策**:assistant 消息与 tool_result 两处均按 `index` 排序。
|
||
- **原因**:消除 HashMap 迭代乱序致多工具结果错位。
|
||
- **状态**:✅ Sprint 6
|
||
|
||
### 路径校验:拒 `..` 遍历 + 扩敏感目录
|
||
- **决策**:正斜杠→反斜杠规范化 + 拒 `..` 路径遍历 + 扩 `.aws`/`.gnupg`。
|
||
- **原因**:最小加固防越权读写;根治级(workspace 白名单 + canonicalize)待边界明确后再做。
|
||
- **状态**:✅ Sprint 6(边界加固待续)
|
||
|
||
### list_directory 递归防爆:噪音目录剪枝 + 条目上限 + skip_noise_dirs 开关 [2026-06-14]
|
||
- **决策**:`list_dir_recursive` 递归时跳过噪音目录(`.git`/`node_modules`/`target`/`dist`/`build`/`.next`/`.cache`/`__pycache__`/`.venv`/`venv`/`.idea`)——**列出但不深入内部**;硬上限 1000 条 + `truncated` 标志;默认 `max_depth` 3→2;加 `skip_noise_dirs` 参数(默认 `true`)。
|
||
- **原因**:AI 广扫项目根传 `recursive:true` 时,`.git`/`node_modules`/`target` 铺平致 13782 项塞进对话 message(UI 卡 + token 爆)。剪枝防爆炸,但保留访问能力:① 噪音目录仍列出(看得见存在 + 大小);② 想看内部时 `list_directory` 直接指向该目录(depth=0 起算),或传 `skip_noise_dirs:false` 强制递归进去(仍受 1000 上限 + truncated 保护,适合看编译产物 dist / 运行结果 target 做比对)。1000 上限 + truncated 让"想全扫"退化为"分层定点查",不丢信息。
|
||
- **状态**:✅ 2026-06-14 落地(cargo check 通过)
|
||
|
||
### `max_tokens` 8192 + `length` 算 finished
|
||
- **决策**:max_tokens 4096→8192;`finish_reason="length"`(截断)纳入 finished。
|
||
- **原因**:大任务输出撞 4096 上限被误判断连、丢弃整段响应;8192 贴合实际,截断视为正常完成。
|
||
- **状态**:✅ Sprint 6
|
||
|
||
### 审批:删全屏 Modal 保留行内卡片 [Sprint 8]
|
||
- **决策**:移除全屏 Tool Approval Modal,保留工具卡片内联审批按钮。
|
||
- **原因**:全屏 Modal 打断对话流,行内审批更轻量。
|
||
- **状态**:✅ Sprint 8
|
||
|
||
## AI Chat Provider 协议
|
||
|
||
### 按 `provider_type` 路由 OpenAI / Anthropic
|
||
- **决策**:新增 `anthropic_compat.rs` 实现 Anthropic Messages API,按 `provider_type` 分发到 OpenAICompat 或 AnthropicCompat;分发处用 `Box<dyn LlmProvider>` trait object。
|
||
- **原因**:GLM 等订阅端点走 Anthropic 协议(`x-api-key` + 顶层 `system` + 必填 `max_tokens` + SSE content_block);统一 Provider trait 屏蔽差异,上层 Agentic Loop / AiNode 零改动(不感知协议)。
|
||
- **状态**:✅ Sprint 8(用户实测对话流式 OK)
|
||
|
||
### 端点 URL 三段智能拼接
|
||
- **决策**:`messages_url()` 按 base_url 末段判断——已含 `/v1/messages` 直用;以 `/v1` 结尾补 `/messages`;仅域名(如 `…/api/anthropic`、`api.anthropic.com`)补 `/v1/messages`。
|
||
- **原因**:GLM 订阅端点 `open.bigmodel.cn/api/anthropic` 与 Claude 官方 `api.anthropic.com` 约定不同(前者无 `/v1`,后者需补);不强制用户填全路径,降低配置门槛。GLM 端点已实测。
|
||
- **状态**:✅ Sprint 8
|
||
|
||
### `max_tokens` 必填兜底 4096 / tool_result 连续合并为一条 user
|
||
- **决策**:① Anthropic 协议 `max_tokens` 必填(协议无默认),`DEFAULT_MAX_TOKENS=4096` 兜底(OpenAI 协议 max_tokens 可选,缺则报错);② 连续多条 `role=Tool`(tool_result)累积,遇非 Tool 消息 flush 为单条 user 消息含多个 `tool_result` 块。
|
||
- **原因**:① 统一兜底避免上层每个调用点都要传值(与 OpenAI Provider 的 8192 上限独立,此处仅缺省兜底)。② Anthropic 要求 tool_result 必须在 user 角色内;多工具并发结果合并为一条 user 而非一对一,贴合协议「一回合一组结果」语义,减少消息碎片。
|
||
- **状态**:✅ Sprint 8
|
||
|
||
### 默认标识:is_default 落库为真相源 [Sprint 10 → 2026-06-13]
|
||
- **决策**:`ai_set_provider` 互斥写 DB(目标 `is_default=true`、其余 `false`,仅写变化记录);`ai_save_provider` 新建时若全表尚无默认则自动设为默认(首个);`ai_list_providers` 直接返 DB 值。`session.active_provider_id` 降为运行时缓存,由 `set_provider` 同步,重启清零不影响——`get_active_provider` 兜底取 DB `is_default`。
|
||
- **原因/取舍**:Sprint 10 原 active 作真相源 → 致「重启默认丢失」bug:active 是内存态重启清零,而 `is_default` 字段恒写 false,重启后无默认可恢复。`is_default` 字段本为持久化默认而存在,回归本职最自然;session 持久化需额外存储,重复造轮子。互斥写库保证「唯一默认」语义。
|
||
- **边界**:互斥写库逐条 `update_full` **不加事务**——repo 未暴露事务接口;桌面单用户无并发触发,失败即报错、重试自愈。多用户/高并发场景需给 repo 补 `execute_transaction`。
|
||
- **状态**:✅ 2026-06-13 落地(重启保默认 / 互斥写库 / 首个自动默认实测待补)
|
||
|
||
### 📋 delete_provider IPC 缺失(前端假删除)[Sprint 10]
|
||
- **需求**:Settings 删 Provider 当前只前端 filter 移除,不调后端(无 `ai_provider_delete` 命令),重启后配置回归。
|
||
- **原因**:交互欺骗——用户以为删除成功,DB 实际未动。需补 `ai_provider_delete` IPC(`lib.rs` 注册 + `ai.rs` 实现 + 前端真调),并加二次确认。
|
||
- **状态**:📐 待实施 → ✅ Sprint 10 已实现(`ai_delete_provider` 命令 + 删默认清 active + 自建 `confirmDialog` 二次确认)
|
||
|
||
## 模型能力与路由(Model Capability & Auto-Routing)
|
||
|
||
### 能力声明:复用 `ai_providers.models` JSON 字段,不建新表 [2026-06-13]
|
||
- **决策**:每个 Provider 下可选模型的能力声明(模态/功能/成本等级)存入已有 `ai_providers.models` 列(JSON 数组),**不新建独立表**。新增 `crates/df-ai/src/model_capability.rs` 定义 `ModelCapability`(name / modalities / functions / max_tokens / cost_tier)+ `TaskRequirements` + `Modality` / `CostTier` 枚举。
|
||
- **原因/取舍**:模型能力是 Provider 配置的内在属性,非独立实体——无生命周期管理、无跨表 JOIN 需求,JSON 嵌入单行足够(Provider 通常 1-5 个);`models` 列已在 V9 建表且全链路预留,复用零 schema 变更;独立表需外键/级联/JOIN,对桌面应用过度工程;备份迁移友好(配置自包含一行)。代价:无法 SQL 查询「所有有 vision 的模型」,但此查询当前和近期均不需要。
|
||
- **状态**:📐 设计未实施(Phase 1:数据模型 + 场景级路由)
|
||
|
||
### 路由层:纯函数 ModelRouter,重写现有骨架 [2026-06-13]
|
||
- **决策**:重写 `crates/df-ai/src/router.rs` 已有但空的 `ModelRouter`——从 `TaskRequirements` + Provider model_pool → 按硬性要求筛选候选 → 按 cost_tier 升序取最便宜。路由是同步纯函数(无 I/O、无全局可变态),可单测。7 个 LLM 调用点统一接入。`override_model` 字段支持用户显式指定(聊天手动切)和工作流节点 config.model(节点作者指定)两种覆盖,优先级最高。
|
||
- **原因**:路由是确定性计算(静态配置→模型名),无需 async/service 化;纯函数可单测;统一入口避免散装 if-else。
|
||
- **各调用点路由策略**:主对话 `chat(has_image)`→Standard/Premium;标题生成 `title_generation()`→Economy 最便宜;知识提炼 `knowledge_extraction()`→Economy/Standard;工作流 AiNode `workflow_node()` + override=config.model→节点指定优先;**Embedding (×2) 不走路由器**(独立路径,不同模型类)。
|
||
- **向后兼容**:`models=None`(老记录)→ model_pool 空 → 所有 route 返回 default_model → 行为不变。
|
||
- **状态**:📐 设计未实施(Phase 1)
|
||
|
||
### Embedding 不进通用路由器 [2026-06-13]
|
||
- **决策**:Embedding 模型不走 ModelRouter,继续走独立路径(`KnowledgeConfig.embedding_model` + `embedding_provider_id`)。
|
||
- **原因**:Embedding 是完全不同的模型类——API 不同(`/v1/embeddings` vs `/v1/chat/completions`)、用途不同(向量化 vs 生成)、通常更小更专用。混入通用模型池会混淆用户并增加路由分支复杂度。
|
||
- **状态**:📐 设计未实施(Phase 1 确认不动 embedding 路径)
|
||
|
||
### 分阶段实施路线 [2026-06-13]
|
||
- **Phase 1**(本次):数据模型 + ModelRouter 重写 + 7 调用点接入 + Settings 模型池编辑 UI + AiChat 模型下拉。ChatMessage.content 保持 String 不改。
|
||
- **Phase 2**(后续):多模态消息——ChatMessage.content: String → Vec<ContentPart>(Text/Image);前端粘贴/拖拽图片;vision 模型自动路由。
|
||
- **Phase 3**(后续):Agent 内智能路由——Agentic Loop 每轮按子任务构造不同 TaskRequirements;成本预算控制;模型级联降级;跨 Provider 搜索。
|
||
- **状态**:📐 设计未实施
|
||
|
||
### 📋 模型能力系统 — 完整改动文件清单 [2026-06-13]
|
||
- **后端 Rust**:`crates/df-ai/src/model_capability.rs`(**新增** ModelCapability / TaskRequirements / Modality / CostTier)/ `router.rs`(**重写** ModelRouter 匹配逻辑)/ `lib.rs`(re-export)/ `df-storage/src/migrations.rs`(V10 版本号推进,无需 ALTER)/ `src-tauri/src/commands/ai.rs`(7 调用点加 router;ai_save_provider 加 models 参数;新增 ai_set_chat_model_override)
|
||
- **前端 TS/Vue**:`src/api/types.ts`(新增 ModelCapability / Modality / FunctionCapabilities / CostTier 类型)/ `src/api/ai.ts`(saveProvider 加 models 参数;新增 setChatModelOverride())/ `src/stores/ai.ts`(availableModels / activeModelOverride 状态 + setModelOverride action)/ `src/views/Settings.vue`(Provider 表单增加模型池编辑区)
|
||
- **状态**:📐 待实施(Phase 1 全量清单)
|
||
|
||
## 灵感模块(评估闭环)
|
||
|
||
### 启发式评分维度
|
||
- **决策**:三维固定 5.0 → 内容启发式(priority / 描述充实度 / tags / 中英关键词),clamp 0-10。
|
||
- **原因**:固定值无区分度;启发式基于 idea 内容给差异化评分。
|
||
- **状态**:✅ Sprint 9(启发式,未接 LLM)
|
||
|
||
### 对抗评估:启发式 fallback 待接 LLM
|
||
- **决策**:正反方论点/evidence 基于真实 idea 内容生成,confidence 由评分驱动;未接 df-ai LlmProvider。UI 诚实标注——评估区标题加「启发式」黄标(`.eval-mode-tag`),对齐实现深度避免名实不符,接 LLM 后摘除。
|
||
- **原因**:先打通评估闭环;LLM 生成论点 + 启发式 fallback 为后续增强。
|
||
- **→ 接入方式已定**:走全局 AI trait 下沉(见 [crate 治理 — AI trait 下沉拆 df-ai-core](#ai-trait-下沉拆-df-ai-core-轻层确立全局-ai-接入标准-2026-06-14-))。`evaluate()` 加 `LlmProvider` 注入参数,启发式降级为 fallback;F-03 原 A/B/C 选型据此收敛为「全局统一 trait」。
|
||
- **状态**:📐 设计未实施(LLM 接入)
|
||
|
||
### 前后端标签对齐
|
||
- **决策**:`recommendation` 全小写空格(后端原 "With Resources" 不匹配前端 map key);`assessmentClass` 映射到 CSS 类名(`.immediate`/`.soon`/...)。
|
||
- **原因**:大小写/类名不一致致中文标签不显示、badge 无色。
|
||
- **状态**:✅ Sprint 9
|
||
|
||
### 评分 0-10(crate)→ 0-100(前端)IPC 缩放 + 多字段写回用单事务 [Sprint 9/10]
|
||
- **决策**:① crate 内 IdeaScores 维持 0-10;IPC 层 evaluate_idea 组装 scores JSON 时 *10 缩放为 0-100,并用中文维度键(可行性/影响力/紧急度/综合)。② evaluate_idea / promote_idea 写回想法用 `update_full`(单事务覆盖整条记录),放弃多次 `update_field`。
|
||
- **原因**:① 前端雷达图直接当百分比渲染、零前端改动;crate 内 0-10 符合评分直觉,IPC 层做单位适配。② 多次 update_field 各自独立连接,中途失败致数据半成品;update_full 原子。
|
||
- **状态**:🚧 Sprint 9/10(编译/构建通过,未 tauri dev 实测)
|
||
|
||
## 想法立项(promotion)
|
||
|
||
### 复用 df-project 领域层,crate do_promote 留纯决策 TODO [Sprint 10]
|
||
- **决策**:`promote_idea` IPC 复用 `df_project::manager::ProjectManager::create_from_idea` 构造项目实体 + 映射 ProjectRecord 持久化 + update_full 回写想法;df-ideas crate 内 `IdeaPromoter/do_promote` 保留纯决策 TODO,不真正创建项目。
|
||
- **原因**:crate 不依赖 df-storage/df-project(避免循环依赖、保持可单测);手动立项无需 Auto/Manual/SemiAuto 策略判断(用户点即确认),副作用放 IPC 组合,与 evaluate_idea 同模式;crate 纯决策留待自动/半自动晋升场景复用。
|
||
- **状态**:🚧 Sprint 10(编译/构建通过,未 tauri dev 实测)
|
||
|
||
### promoted_to 非空拒绝重复立项 [Sprint 10]
|
||
- **决策**:promote_idea 取想法后校验 promoted_to 已存在则返回错误,不创建新项目。
|
||
- **原因**:防同一想法多次点「立项」生成多个项目;幂等保护。
|
||
- **状态**:🚧 Sprint 10
|
||
|
||
## 项目管理(删除 / 回收站)
|
||
|
||
### 项目删除:软删回收站(deleted_at + 应用层级联),非物理删 [2026-06-13]
|
||
- **决策**:删项目改为**软删**——`projects` 加 `deleted_at TEXT` 列(V11 迁移),`delete_project` 置 `deleted_at`(进回收站,可恢复);`list_projects` 过滤 `deleted_at IS NULL`;回收站(`list_deleted_projects`)可「恢复」(清 deleted_at)或「彻底删除」(`purge_project` 事务级联物理删 branches→releases→tasks→projects,不可逆)。子表软删时不动,FK 仍满足,项目数据完整保留待恢复。
|
||
- **原因/取舍**:① 用户要求「可恢复」——纯 CASCADE 物理删不可逆,误删难挽回;软删 + 回收站给反悔余地。② SQLite `ALTER TABLE` 改不了已有表 FK 约束,给老库 projects 加 `ON DELETE CASCADE` 须重建表(高风险),故不走 DDL 级联,改**应用层级联**(purge 时事务内顺序删子表),语义等价且可测、不依赖 `PRAGMA foreign_keys`。③ 软删只标记 projects 行、子表不动——恢复时项目连同历史任务/分支/发布完整还原。④ 两级风险分级:日常软删可逆 / 回收站 purge 二次确认后物理删不可逆。
|
||
- **边界**:`ProjectRecord` 不带 `deleted_at` 字段,纯靠 SQL `WHERE deleted_at IS NULL` 过滤,models/types 零变更。`ai.rs build_system_prompt` 同步改用 `list_active`(防软删项目泄漏进 AI 上下文)。`soft_delete`/`restore` 守卫对称,重复操作幂等。
|
||
- **状态**:✅ 2026-06-13 落地(V11 迁移 + ProjectRepo 5 方法 + 3 IPC 命令 + 回收站 modal + 删除入口;cargo check + vue-tsc + 11 integration test 全绿)
|
||
|
||
## 项目管理(目录绑定 / 技术栈探测)
|
||
|
||
### 项目绑定真实代码目录:扩 ProjectRecord + df-project scan [2026-06-13]
|
||
- **决策**:`ProjectRecord` 加 `path`(绑定目录绝对路径)+ `stack`(技术栈 JSON 数组字符串)两字段(V12 迁移,nullable);技术栈探测逻辑放**新建 `df-project/src/scan.rs::detect_stack`**(纯函数,浅读根目录标志文件识别 rust/go/python/java/csharp/vue/react/angular/svelte/next/vite/typescript/node/tauri);commands 层薄封装 4 命令(`scan_project_stack`/`check_path_binding`/`relocate_project_path`/`check_path_exists`),`check/relocate` 前 `canonicalize` 规范化路径防绕过重复检查。新建项目可选绑定目录→自动探测栈,详情页支持重定位 + 目录失联检测 + 防重复绑定。
|
||
- **原因/取舍**:① **扩 df-storage ProjectRecord 而非激活 df-project ProjectContext 空壳**——`ProjectContext` 虽早设计 `root_path`/`tech_stack`/`repo_url`/`ai_context` 字段,但 `manager.rs` 标注 TODO 从未接存储/运行时;激活需新建 `project_contexts` 表 + 填充暂不需要字段,第一步过重,守 YAGNI。ProjectRecord 是实际运行链路,直接扩最快见效。② **scan 放 df-project 而非 commands 层**——`ProjectContext.tech_stack` 本就是 df-project 职责字段,scan 是其天然能力且可被 df-ai/df-workflow 复用,放 commands 变一次性代码。③ **migration nullable**——老项目 path/stack=NULL 零影响。④ **一致性原则**:先在「新建流」验证,第二步「导入历史项目」复用同一套 scan/relocate/checkBinding。
|
||
- **边界**:`path` 规范化(canonicalize)仅用于比较,存库保留用户输入的原始可读路径。程序化创建项目(想法晋升、AI 工具)path/stack = None(不绑定目录)。`df-project` 的 `ProjectContext` 刻意未激活(ai_context/repo_url 等暂留空)。
|
||
- **状态**:✅ 2026-06-13 落地(V12 迁移 + detect_stack + 4 IPC 命令 + 选目录/查重/卡片栈 + 重定位/目录状态;cargo build + scan 4 单测 + vue-tsc 全绿)。📋 导入历史项目(第二步):复用 scan/relocate/checkBinding,加 monorepo 子目录识别 + README 首段抽 description + 批量。
|
||
|
||
### 导入/绑定项目 AI 扫描填信息:规则探测兜底 + LLM 增强,采样与 LLM 调用分层 [2026-06-14]
|
||
- **决策**:导入/绑定项目时规则 `detect_stack`(快/免费/准)必跑兜底 + LLM 分析采样(README+目录树+清单,不读源码)产出 description 摘要与 stack 细化;LLM 失败降级纯规则。采样逻辑放 df-project(纯 IO),LLM 调用放 commands 层。
|
||
- **原因/取舍**:① 规则兜底保证 LLM 不稳定时仍有基础信息,LLM 只补规则搞不定的摘要。② 采样与 LLM 分层——采样纯 IO 属 df-project 职责可复用,LLM 调用依赖 df-ai,放 commands 使 df-project 保持无 LLM 依赖(防循环)。③ 不读源码控 token+隐私。④ 结果预览让用户把关防 LLM 瞎编。
|
||
- **状态**:✅ 2026-06-14 落地(scan_project_with_ai 命令 + 前端 AI 扫描预览;编译/单测/类型全绿)。
|
||
|
||
### AI 工具绑定目录:bind_directory 专用工具 + 工具层白名单同步 + prompt 禁冒充 [2026-06-14]
|
||
- **决策**:① update_project 工具白名单补 path/stack(同步 db 新字段);② 新增 bind_directory 专用工具(绑定目录不走通用 update);③ 系统 prompt 加约束:工具失败须明说,禁用替代操作冒充原意图成功。
|
||
- **原因/取舍**:① review AI 对话发现 update_project(path) 被工具层白名单拒(db 字段加了但工具层漏同步),AI 转而改写 description 却回复「已记录」冒充绑定成功误导用户。② 专用工具语义清晰,防 AI 走通用 update 捷径冒充。③ prompt 约束防单链 ReAct「自我圆场」幻觉(失败时用替代谎报成功)。
|
||
- **状态**:✅ 2026-06-14 落地(白名单同步 / bind_directory / prompt 中英约束;编译全绿)。📋 待清:工具层白名单与 crud 白名单双份去重(详见经验记录)。
|
||
|
||
## 知识库(df-evolve / 共享记忆层)
|
||
|
||
> 核心定位与设计决策。详细字段/参数级决策见各条目。
|
||
|
||
### 定位 + 被动 Service 退化 [2026-06-13]
|
||
- **决策**:知识库(df-evolve)定位为**整个 DevFlow 的共享记忆层**——每个模块(idea/task/workflow/review/chat)既是知识生产者也是消费者,而非孤立展示功能页。df-evolve 褫夺「自动进化引擎」角色(Sprint 2 对抗论证已砍,自用阶段 ROI 低/过度工程),**退化为被动 Service 层**,只暴露 `search/retrieve/record_reuse/feedback/save` 供各模块调用;被动 Service 复用 df-ai 检索做消费侧,EventBus 做事件驱动提示(非自动抓取)。
|
||
- **原因**:手脑(各业务模块)分离无学习能力;知识库做「肌肉记忆」中枢系统才越用越懂你。砍的是自动挖矿,非知识库本身。
|
||
- **状态**:📐 设计未实施(用户拍板定位)
|
||
|
||
### 沉淀审核机制:知识状态机,AI 只产草稿 [2026-06-13]
|
||
- **决策**:知识加 `status` 字段,状态机 `candidate → pending_review → published → archived`;**AI 提炼的知识一律进 candidate,绝不直接入正式库**;草稿进「待审核收件箱」,人工逐条编辑(内容/分类/标签)→ 发布或丢弃。`verified` = 发布审核时一次性人工标(intake 决断动作,非 ongoing 评分)。沿用 IdeaRecord 的 `pending_review` 状态机模式。
|
||
- **原因**:沉淀必须有人工把关(用户要求「人工能够编辑或调整,必须有这些过程」)——AI 提议、人裁决、系统如实记,非黑箱自动学习。
|
||
- **状态**:📐 设计未实施(用户明确要求加审核机制)
|
||
|
||
### AI 提炼产出:字段集 + 置信度(唯一指标)+ 查重 [2026-06-13]
|
||
- **决策**:AI 提炼一条 candidate 时产出——**内容字段**:`kind`(分类,AI 判定 7 类之一)、`title`、`content`、`tags`、`source_ref`(原始证据片段);**质量指标**:`confidence`(High/Medium/Low,AI 自评,**唯一质量指标**);提炼时另做**查重**(比对 published 库,重复则不产/标合并,非存储字段)。**克制边界**:质量指标只留 confidence——不加 generality/specificity/novelty 等维度(过工程化 + 多耗 token),适用范围并入 `tags` 不单列 scope 字段。
|
||
- **原因**:`kind` 和 `source_ref` 是 AI 必填但易漏的两项;confidence 服务降噪 + 审核分诊 + 透明,但**不绕过人审门**(high 也不自动发布)。
|
||
- **状态**:📐 设计未实施
|
||
|
||
### 透明化:provenance 溯源 + 收件箱 + 注入告知 [2026-06-13]
|
||
- **决策**:① 每条知识标来源(哪次 Chat/task/review 产出 + 原始片段),可跳回——复用现有 `source_project` + `source_ref` 字段;② 「待审核收件箱」作明确信息渠道;③ 复用时显式告知本次注入了哪几条、为什么命中。
|
||
- **原因**:用户要求「透明化让人们有很好的信息获取渠道」——不黑箱。provenance 字段现有模型已有,零新增成本。
|
||
- **状态**:📐 设计未实施
|
||
|
||
### 克制原则:宁缺毋滥,小步迭代 [2026-06-13]
|
||
- **决策**:① **检索注入保守**——精确匹配(标签/关键词)优先,语义模糊匹配**后做**,top-N 限 1-3 条,置信不够一条都不塞;② **关联不自动推断**——IdeaGraph 自动聚类/关联发现**先不做**,只支持人工标注;③ **沉淀不主动监听全量事件**——仅「一键沉淀」或事件提示后「确认」才产 candidate;④ **从小到大**——先 AI Chat 单点双向跑通验证手感,再串 review/idea。
|
||
- **原因**:用户要求「尽可能克制,不要做大胆的连接,从小到大」——贯彻 Sprint 2「scope 砍 60%」精神到知识库,避免重蹈「自动进化」过度工程覆辙。
|
||
- **状态**:📐 设计未实施(用户明确要求克制)
|
||
|
||
### 指标客观化:reuse_count 唯一信号,撤销 effectiveness 人工评分 [2026-06-13]
|
||
- **决策**:知识排名/淘汰**只用 `reuse_count` 一个客观信号**(检索注入自动 +1);**撤销 `effectiveness` 的人工 👍/👎 评分**(主观、有摩擦、信号不准);淘汰改客观——reuse_count=0 且超 N 天未用 → 提示归档。
|
||
- **演进**:初版三指标(reuse_count + effectiveness + verified)共同排序权重 → 同日修正:用户指出 👍/👎 是「人为、主观、非准确」的非必要干预,撤销。「用过 ≠ 有用」的质量顾虑改由两层客观兜底——① intake 审核门(一次性决断)② 发现噪音直接删。召回不准根因在标签/搜索质量,靠 intake 打准标签解决。
|
||
- **状态**:📐 设计未实施
|
||
|
||
### 📋 分层落地 Tier 1/2/3 + 来源/去向审查 [2026-06-13]
|
||
- **需求**:知识库联动分三层——**Tier 1(必做)**:AI Chat ↔ 知识库双向 + 手动录入(沉淀 + 检索注入 + reuse_count + 审核收件箱 + 状态机,**无人工评分**);**Tier 2(串创作流,带前置)**:ai_node 检索 prompt_template、工作流 NodeFailed → pitfall(**仅失败时**)、决策记录 → architecture_pattern(**前置:先补 df-traceability 持久化**);**Tier 3(砍)**:evolve_engine 自动挖事件。
|
||
- **审查(来源)**:① **/review 源移出**——devflow 无代码审查功能(df-stages/coding.rs 审查节点是 TODO 空壳);② **想法评估源存疑**——对抗论点是「一次性结论」非可复用知识;③ **决策记录源标前置**——`DecisionJournal` 所有 SQLite 查询 TODO 未持久化;④ **工作流源限定失败时**——运行日志≠提炼知识。
|
||
- **审查(去向)**:**Chat 轴是唯一 Tier 1 就绪消费端**(检索→注入对话/提示词);ai_node prompt 注入属 Tier 2;工作流无主动消费(仅被动产 pitfall);决策溯源消费半残。→ 来源/去向双收敛到 Chat 轴。
|
||
- **状态**:📐 待实施(先做 Tier 1:Chat + 手动录入)
|
||
|
||
### 对外暴露:MCP Server 双向协议 [2026-06-13]
|
||
- **决策**:知识库对外 API 采用 **MCP Server** 形式暴露,**双向**(读+写)。Tier 1 先做 DevFlow 内部闭环(Tauri IPC),**命令层设计完全对齐 MCP 语义**;Tier 1+ 套 MCP server(封装已有 command)。MCP 暴露:① **Resource (读)**:list/search/get;② **Tool (写)**:create_candidate;③ **Tool (计数)**:record_reuse。
|
||
- **原因**:① Claude Code 原生吃 MCP——本机主力工具零集成成本;② Cursor 也支持 MCP;③ **双向价值**:外部工具(尤其 Claude Code 做代码审查/重构时)是高质量知识来源——审查结论→review_rule、踩坑经历→pitfall,接 MCP 自动回流知识库等于开「第二来源入口」。克制:Tier 1 不实现 MCP 本身,但 6 个核心命令(search/list/get/create/update_status/record_reuse)全部按可暴露设计。
|
||
- **状态**:📐 设计未实施(Tier 1+ 事项)
|
||
|
||
### 矛盾知识处理:纯标签+内容自述,source_project 仅溯源 [2026-06-13]
|
||
- **决策**:矛盾知识**不建冲突关系表、不加 scope 字段、不做 access control**。消歧靠 tags(如 `["Go","微服务"]` vs `["Go","单体"]`)+ content 自述适用范围 + source_project 仅作来源溯源展示(不参与检索过滤)。AI 提炼 prompt 加约束:「适用范围有限制必须在 content 或 tags 中标注」。零数据结构变更。
|
||
- **原因/取舍**:矛盾是少数场景,为 minority 建关系系统是过度工程;source_project 若做绑定/过滤会提高维护门槛 + 降低通用知识复用率;检索 top-N≤3 返回时内容本身场景描述足够消费者判断。
|
||
- **状态**:📐 设计未实施
|
||
|
||
### AI 提炼触发 + 知识注入:可配置 [2026-06-13]
|
||
- **决策**:① AI 提炼**默认自动触发**(后台 detached task),4 个配置项:`auto_extract`(default true)/ `trigger_mode`(on_complete|on_idle|manual_only,default on_complete)/ `min_messages`(default 4)/ `idle_timeout_ms`(default 30000)。② Chat system prompt 知识注入**加开关**(`auto_inject: bool`,default true,关闭时首行返回空字符串零开销)。
|
||
- **原因/取舍**:手动按钮依赖用户记得点→遗忘→空库死循环;自动触发保证持续流入候选。但用户控制欲不同——4 配置项覆盖从「全自动」到「全手动」。每次 complete() <500 input/<200 output token,可关零成本。注入开关给用户「先积累再开启 / 调试不被干扰」的控制权。
|
||
- **状态**:📐 提炼设计未实施 / ✅ 注入已实施(Tier 1)
|
||
|
||
### 检索方案:LIKE + top-N,向量检索提前到 Tier 1(Phase 5.5)[2026-06-13]
|
||
- **决策**:Tier 1 检索用 SQLite `title/content LIKE '%query%'` + `ORDER BY reuse_count DESC LIMIT 3`;收件箱排序用 `CASE WHEN confidence 'high'→3/'medium'→2/'low'→1`(非纯 TEXT 字典序)。**向量检索从 Tier 2 提前到 Tier 1 同步实施**(Phase 5.5),加 **Settings 开关**(`vector_enabled`,默认 false)。
|
||
- **原因/取舍**:知识库核心消费场景是 AI 自动注入(拿用户自然语言 query 检索),非关键词精确搜索——「部署后白屏」匹配不到「Nginx SPA 路由」,纯 LIKE 语义盲区从第一天就存在。开关化解「本地优先/零依赖」哲学冲突:默认关闭纯 LIKE 零外部调用,开启后才走 embed API。
|
||
- **实施细节**:① `LlmProvider` trait 加 `embed()`(OpenAICompat 实现,Anthropic 不支持);② V8 幂等补 `embedding BLOB` 列(f32 小端序列化,NULL=未嵌入走 LIKE);③ **嵌入时机=发布时**(candidate 不浪费 embed,published 才参与检索);④ 纯 Rust 余弦(<50k 条暴力遍历够用,不引 sqlite-vec 避免 Windows C 扩展编译风险);⑤ 三层降级链:开关关→LIKE;开但 provider 缺/embed 失败→自动回 LIKE;正常→混合检索(双信号>LIKE 单>向量单,cos≥0.3 滤噪)。
|
||
- **状态**:✅ Tier 1 LIKE + 向量混合检索(Phase 5.5)均已实施,编译通过待实测
|
||
|
||
### 知识生命线:独立 knowledge_events 表(非 JSON 嵌主表)[2026-06-13]
|
||
- **决策**:知识产生/审核/引用/归档四类审计事件存**独立 `knowledge_events` 表**(V10 迁移),而非塞进 `knowledges.context_json` 字段。
|
||
- **原因/取舍**:事件是追加型(只增不改删),语义与主表 CRUD 完全不同;一条知识可被引用数百次,JSON 嵌主表致行膨胀 + 写更新竞争(每次引用都重写整行)。独立表可建 `(knowledge_id,event_type)` 复合索引;事件表写失败只丢审计、不影响知识本身(fire-and-forget 隔离)。未来加新事件类型只加一行 insert,不动主表 schema。
|
||
- **状态**:✅ 已实施(V10 迁移 + KnowledgeEventsRepo + 前端生命线时间线)
|
||
|
||
### 📋 知识详情页 + 编辑能力(candidate 审核闭环)[2026-06-13]
|
||
- **需求**:卡片点不开详情、不能编辑、看不到「为什么产生」。详情页需呈现完整生命线 + candidate 可编辑修正后发布。
|
||
- **决策**:Knowledge.vue 重构为 Ideas 式左右分栏(左卡片列表 @click 选中 / 右详情面板四分区:①基本信息 ②溯源 ③引用记录 ④生命周期时间线);可编辑字段 title/content/tags/confidence/reasoning 走 `knowledge_update`(部分更新)。
|
||
- **原因/取舍**:candidate 编辑是审核闭环刚需——AI 提炼必有水分/措辞瑕疵,只能原样发布或整条拒绝会让审核空转。详情复用 Ideas 已验证的 master-detail 模式。published 编辑不做(有归档+重提炼替代)。
|
||
- **状态**:✅ 已实施(编译+vue-tsc+df-storage 21 单测全绿,GUI 实测待 #54)
|
||
|
||
## AI Chat 上下文窗口与并发控制(架构结论)
|
||
|
||
> 实现细节见 [归档文档](./功能决策记录-归档.md)「AI Chat 上下文窗口与并发控制」。
|
||
|
||
### 设计决策 [2026-06-13]
|
||
- **ContextManager 类型替换为 messages 真相源**:`AiSession.messages` 从 `Vec<ChatMessage>` 改为 `ContextManager`(非 wrapper 包装层),消息真相源唯一,避免 Vec + ContextManager 双存导致状态分裂。裁剪仅影响发送视图(`build_for_request` 返回裁剪版,`all_messages_clone` 返全量落库)。
|
||
- **淘汰算法:分组滑动窗口 + 三元组保护**:`Assistant(tool_calls) + Tool(result)* + Assistant(final_text)` 工具调用三元组作为原子整体;最后 6 条(≈2 个完整用户轮次)设为保护区永不淘汰。
|
||
- **Token 计数零依赖**:`chars_count × 0.35` 粗估(误差 ±15% 可接受),不引入 tiktoken-rs(5MB BPE 数据文件对 Tauri 打包不友好)。
|
||
- **双层 Semaphore 并发控制**:AppState `LlmConcurrency`——全局并发默认 3 / 单对话默认 2;permit 在 3 个叶子 LLM 调用点 acquire(`run_agentic_loop` stream_llm 前、`generate_title_via_llm`、`extract_knowledge_from_conversation`),工具执行不受控。`per_conv` 实为应用级单一信号量(因 AiSession 单例 + generating 互斥,命名宽泛但当前语义正确,多对话路线时改 HashMap)。Semaphore 重建用「软收敛」策略(替换内层 Arc,旧 permit 不受影响)。
|
||
- **裁剪策略与模型选择正交**:ContextConfig 不含 mode/模型选择字段;「高精度/低精度对话」属 LLM 调用层参数,与裁剪策略是正交维度。
|
||
- **状态**:✅ 已落地(2026-06-13,cargo check + vue-tsc 通过,待 tauri dev 实测)
|
||
|
||
## i18n
|
||
|
||
### legacy:false + zh-CN 默认 + locale 拆分 + glob 聚合 [Sprint 7 + 2026-06-13]
|
||
- **决策**:① `legacy:false` / `globalInjection` / zh-CN 默认 + en fallback / `localStorage df-language` 持久化。② `zh-CN.ts`/`en.ts` 单文件 → `zh-CN/*.ts` + `en/*.ts` 按模块拆分(nav/dashboard/ai/common/settings/ideas/knowledge/projects/projectDetail/tasks/aiChat/aiTool),`index.ts` 用 `import.meta.glob('./*.ts', { eager, import: 'default' })` 自动聚合(排除 index 自身)。新增模块文件即生效,不改 index。
|
||
- **原因**:① Composition API 模式;默认中文贴合自用,英文兜底。② 全量 i18n 接入(8 view ~640 处中文)用多代理并行,模块隔离零冲突(每代理建自己模块 + 改自己 view,不动共享 index);比单文件扩 key(多代理改同一 `zh-CN.ts` 冲突)更适合并行。glob eager 运行时聚合,动态新增模块即拾取。
|
||
- **状态**:✅ Sprint 7 + 2026-06-13(curl 验证 vite 正确展开 glob,vue-tsc PASS)
|
||
|
||
### 状态枚举 i18n:constants 存 key,view 包 $t
|
||
- **决策**:`constants/project.ts` 的 `PROJECT_STATUS_LABELS`/`TASK_STATUS_LABELS` 值从中文文案改存 i18n key(`planning: 'projects.status.planning'`);`projectStatusLabel`/`taskStatusLabel` 返回 key;view 显示处包 `$t(projectStatusLabel(x))`。`PRIORITY_LABELS`(P0/P1)是代号非文案,不动。
|
||
- **原因**:constants 是纯数据/结构层,不应含展示文案(违反分层);文案归 locale,constants 管映射结构。
|
||
- **状态**:✅ 已落地
|
||
|
||
### 📋 项目 status 字段语义混乱(生命周期 vs 开发阶段)
|
||
- **现象**:后端 `projects.status DEFAULT 'active'` + `list_active`/软删除(active/deleted 生命周期),但前端 `PROJECT_STATUS_LABELS` 是 planning/in_progress/paused/completed/cancelled(开发阶段),两套塞一个 status 字段。DB 实际只有 `status='active'`(新建默认,阶段值从没产生),前端 map 不认 → 显示英文 "active"。
|
||
- **治标**:补 `projects.status.active`(🚀进行中),不再显示英文。→ 根本未除。
|
||
- **治理方向**:① 后端支持阶段流转(planning→in_progress…);② 前端 map 对齐后端真实值(active/deleted/archived);③ 拆双字段(status 生命周期 + stage 开发阶段)。
|
||
- **状态**:📐 待治理(治标已落地,根本病根未除)
|
||
|
||
## 状态持久化
|
||
|
||
### 窗口位置/大小:用 tauri-plugin-window-state(纯 Rust 层)
|
||
- **决策**:窗口位置/大小/最大化用 `tauri-plugin-window-state` 插件(Rust 层自动接管),而非前端 localStorage + setPosition/restore 方案。
|
||
- **原因**:插件自动覆盖主窗口 + 动态创建的 `ai-detached` 子窗口,零前端代码、零竞态;前端方案需手动同步且对子窗口生命周期处理复杂。需配套 `window-state:default` capability 权限。
|
||
- **状态**:✅ Sprint 10
|
||
|
||
### detached/docked 不持久化
|
||
- **决策**:UI 布局持久化,但 `detached`/`docked` 重启后强制回 `false`,不随 `df-ai-ui` 落盘。
|
||
- **原因**:重启后分离窗口必然不存在,若恢复为 `true` 会让 UI 状态指向不存在的窗口(按钮失灵、panelOpen 错乱)。这两个态是运行时临时态,不属可恢复布局。
|
||
- **状态**:✅ Sprint 10
|
||
|
||
> 注:UI 布局 localStorage + 模块级恢复的细节见 [归档文档](./功能决策记录-归档.md)。
|
||
|
||
## 应用启动 / 数据库配置
|
||
|
||
### Dev 与 Build 拆分独立数据库 [2026-06-13]
|
||
- **决策**:`lib.rs` 启动时按 `cfg!(debug_assertions)` 选 DB 文件名——debug(Dev 模式)用 `devflow-dev.db`,release(Build 模式)用 `devflow.db`,两库同处 `app_data_dir()`(`top.1216.devflow`)下,靠文件名区分。
|
||
- **原因/取舍**:原启动代码无编译模式分支,Dev 与 Build 共用一个 `devflow.db`——Dev 频繁改动/清空会污染 Build 侧真实运行数据。拆分后 Dev 库可随意折腾,Build 库长期保留作运行效果基线。**文件名区分而非子目录**——改动最小(lib.rs 一行 if),两库平铺同目录便于备份/查看。**现有 `devflow.db` 文件名未变归 Build**,零迁移零数据丢失;Dev 首次启动自动建空库。
|
||
- **边界**:`app_data_dir()` 由 `tauri.conf.json` 的 `identifier` 决定、与编译模式无关,故拆分前两种模式确读同一文件。docs/使用手册备份命令 `cp devflow.db` 仍正确(备份 Build 真实数据)。
|
||
- **状态**:✅ 2026-06-13 落地(`lib.rs:24`)
|
||
|
||
## UI 反馈与弹层
|
||
|
||
### toast/confirm 自建,不引 Arco / 不用 window.confirm [Sprint 10]
|
||
- **决策**:Settings 页轻量提示与删除确认用自建 `toast`(顶部 fixed,3s 自动消失)+ `confirmDialog`(遮罩 + 卡片,Promise 化),而非引入 Arco Message/Modal 或原生 `window.confirm`。
|
||
- **原因**:① `@arco-design/web-vue` 虽在依赖但 `main.ts` 未 `app.use` 注册,引 Message/Modal 要补全局注册 + 样式加载,过重违反做减法;② `window.confirm` 在 Tauri webview2 带「来自 localhost:端口」来源信息,无法去除,体验差。自建零依赖、样式可控(主题色)、`await confirmDialog()` 语义贴近原生 confirm。
|
||
- **演进** [2026-06-13]:AiChat 删对话需确认 → 第二处复用落地。抽成 `src/components/ConfirmDialog.vue`(`visible`/`msg`/`dangerLabel` props + `@result` emit)。按钮样式内联自包含,不依赖外部 `.btn-*`——因 Settings 是 `scoped`,组件拿不到其内定义的 `.btn-danger`。选 SFC 组件而非 `useConfirm()` composable:模板/遮罩/Transition 动画/CSS 才是真正重复主体,Promise 封装留在调用方(~8 行)。
|
||
- **状态**:✅ Sprint 10
|
||
|
||
## 技能 / 联想
|
||
|
||
### 首批 Claude 3 类 + path 去重
|
||
- **决策**:技能联想首批数据源 = Claude skills / commands / plugins 三类(SKILL.md frontmatter),按 path 去重(`cache/` 与 `marketplaces/` 重复)。
|
||
- **原因**:frontmatter 格式统一(`name`/`description`/`user_invocable`),可统一解析;Codex frontmatter 一致后续可扩展,openclaw 属 agent 选择层不纳入。
|
||
- **状态**:✅ Sprint 8(待实测)
|
||
|
||
## 决策治理产品化评估(2026-06-13)
|
||
|
||
> 审视 DevFlow 是否应把决策治理(记录/锚点/完成度/自检/漂移)做成产品功能。机制设计详见 [规格契约自检机制.md](./规格契约自检机制.md)。
|
||
|
||
### 5 痛点产品内未覆盖,真实运转的寄生 Claude Code 层 [2026-06-13]
|
||
- **决策**:DevFlow 产品内对决策治理 5 痛点「设计满格、代码两极」——df-traceability 死代码(无表/无 IPC/无前端);契约锚点/AI 自检/漂移检测=规格契约自检机制.md 纯设计稿(0 行代码);完成度无聚合视图。唯一真实运转的(功能决策记录.md + decision-record skill + dr-check hook)寄生在 Claude Code 协作层,未沉淀进产品。
|
||
- **原因/取舍**:没用 Claude Code 的用户,DevFlow 给不了任何决策治理能力。这套能力寄生在协作工具上,核心价值未进产品。
|
||
- **状态**:📐 待产品定位决策
|
||
|
||
### df-traceability 是锚点雏形,Sprint 2 被砍(死代码可复活)[2026-06-13]
|
||
- **决策**:`crates/df-traceability/` 的 `Annotation.location`(文件路径+行号)= 规格契约自检机制设计的「代码锚点」雏形,`Decision` struct 精确对应决策记录痛点。但 Sprint 2 对抗论证时被砍/降级,此后无表、无 IPC,query 方法全 `vec![]`。
|
||
- **原因/取舍**:非显然关联——文档层设计的活契约+锚点机制,本质是产品外部用更轻方式重发明被砍的 df-traceability 轮子。是否复活取决于产品定位抉择;Sprint 2 砍的理由(优先级低/过度设计)现需重新评估。
|
||
- **状态**:📐 待评估
|
||
|
||
### 产品化推荐路径 C 混合,完成度驾驶舱起步 [2026-06-13]
|
||
- **决策**:三路径——A 全产品化(复活 df-traceability 全栈+spec 自检 AI,成本大/重蹈 Sprint 2 覆辙风险);B 纯寄生(承认是 Claude Code 协作层,只优化 skill/hook,产品核心价值存疑);**C 混合(推荐)——产品做数据底座(decisions 表+完成度聚合+视图),AI 验证/漂移留协作层**。最小起步:只做完成度驾驶舱(痛点 3)。
|
||
- **原因/取舍**:C 分离「确定的数据层」与「不确定的智能层」,先做确定的低风险项。完成度驾驶舱起步:①最痛(记不住做了/没做)②技术已存在(tasks/ideas 有 status,缺聚合 IPC+Dashboard 视图)③立刻可见④验证真会用再扩(避免 Sprint 2 式膨胀)。
|
||
- **状态**:📐 待用户拍板(DevFlow 要否成为「决策治理/完成度驾驶舱」产品)
|
||
|
||
## crate 治理 / 模块结构(2026-06-14)
|
||
|
||
> 跨 crate 的删留与拆分决策。涉及 df-evolve 领域保留决策的推翻、coordinator 空壳的去留、ai.rs god file 的拆分方式。
|
||
|
||
### 删除 5 个零引用 crate(推翻 df-evolve 领域保留决策)[2026-06-14]
|
||
- **决策**:整删 5 个 crate——`df-evolve` / `df-plugin` / `df-stages` / `df-task` / `df-traceability`。**推翻既有「df-evolve 领域类型保留」决策**:连同 `Knowledge`/`PromptTemplate`/`ReviewRule` 领域类型一起整删,知识库领域统一走 `df_storage::models::KnowledgeRecord`,不再维护独立领域模型层。
|
||
- **原因/取舍**:
|
||
- **零引用铁证**:全仓跨 crate 引用为 0——`src-tauri/src` 下 0 处 `use`,其他 crate `Cargo.toml` 不依赖,仅 `src-tauri/Cargo.toml` 声明 `df-evolve` 但源码零用。整坨孤立骨架。
|
||
- **推翻归档决策**:`功能决策记录-归档.md:355` 原记「`Knowledge`/`PromptTemplate`/`ReviewRule` 领域类型有意保留待 Tier 1 Service 复用」——本次决定**放弃 Tier 1 独立领域模型路线**。理由:① 知识库 Tier 1 已在 `KnowledgeRecord`(df-storage)上落地 LIKE + 向量混合检索 + 状态机,实际运转的领域模型就是 `KnowledgeRecord`,df-evolve 的领域类型成为「理想但悬空」的另一套定义,重复且误导;② 维护两套领域类型是「未来可能复用」的预期成本 vs 「现在重复定义 + 误导性地雷」的实际危害,用户选消灭后者。
|
||
- **df-task::Task 一并删**:`Task`(含 `branch_id`/`tags`/`estimate_hours` 等比 `TaskRecord` 更丰富的字段)作为「理想任务领域模型」长期悬空零引用,任务领域统一用 `df_storage::models::TaskRecord`。
|
||
- **df-traceability 整删**:原被记为「锚点雏形可复活」(见上方「决策治理产品化评估」)。本次决定删除——如未来真需锚点机制,重新评估而非保留死码。死码「可复活」是一种伪期权,实际价值是误导后续维护者以为它在运转。
|
||
- **df-plugin / df-stages 属过早设计**:df-plugin(WASM/动态库)、df-stages(11 阶段节点 `execute()` 全空壳)未启动即删,与「人机协同设计基准」中「AI 反复读写的代码不养空壳」一致。
|
||
- **影响**:① `src-tauri/Cargo.toml` 需移除 `df-evolve` 依赖声明;② 「决策治理产品化评估」中 df-traceability 相关条目(锚点雏形 / 完成度驾驶舱数据底座)状态需重新标注为「无现存代码可复用」;③ 知识库功能域(`## 知识库`)所有决策继续适用,但实现载体明确为 `KnowledgeRecord` 而非 df-evolve 领域类型。
|
||
- **状态**:✅ 2026-06-14 落地(用户拍板删 5 crate + 领域类型)
|
||
|
||
### coordinator.rs 保留(B 路线占位空壳,不删)[2026-06-14]
|
||
- **决策**:`crates/df-ai/src/coordinator.rs` 的 `AgentCoordinator`(多 agent 协作占位空壳,`run()` 返回硬编码 TODO)**保留不删**,加注释标注「B 路线待立项」。
|
||
- **原因/取舍**:与 aichat 升级 A/B 路线拆分一致——A 路线先做 UX 快赢(已进行),B 路线单独立项补多 agent 协作决策能力。coordinator 是 B 路线的入口锚点,**有意保留占位**而非删除:① B 路线立项时有现成挂载点(trait + 结构骨架),不必从零设计;② 与上述 5 crate 删除不矛盾——5 crate 是「无路线图占位的纯死码」,coordinator 是「有明确后续路线(B 路线)的占位」,二者判断标准不同。区别在「是否绑定明确的演进路线」。
|
||
- **状态**:📐 B 路线待立项(保留空壳 + 加注释)
|
||
|
||
### ai.rs 拆分:低风险子 module 而非下沉 crate [2026-06-14]
|
||
- **决策**:`src-tauri/src/commands/ai.rs`(2663 行 god file)拆成 `commands/ai/` 子 module 目录(11 个文件:mod + commands + agentic + stream_recv + conversation + title + audit + skills + prompt + tool_registry + knowledge_inject),用 `pub use` 保持 `state.rs`/`lib.rs`/`knowledge.rs` 引用路径零改动。**采用低风险子 module 方案而非下沉到 df-ai crate**。
|
||
- **原因/取舍**:① 2663 行单文件消耗大量 AI context(每次理解靠结构),与「人机协同设计基准」中「组件拆分从『不做』升为『值得做』」一致。② **选子 module 不选下沉 crate**——下沉到 df-ai 需动 crate 依赖图(df-ai 反向依赖 src-tauri 的 state/types),引入循环依赖风险 + 跨 crate 重构成本;子 module 仅在同 crate 内切目录,`pub use` 保持对外 API 不变,零引用路径改动,重构面最小。③ 子 module 仍能达成「职责单一」的 AI 可读性目标,与下沉 crate 收益相当但风险低一个数量级。
|
||
- **实施验证(2026-06-14 落地)**:
|
||
- 11 文件合计 2833 行,最大 knowledge_inject.rs 557 行(含测试),commands.rs 529 行(17 个 IPC 命令),其余均 < 400 行。
|
||
- 路径契约全保:`commands::ai::{AiSession, build_ai_tool_registry, restore_pending_approvals, spawn_embedding_for_knowledge, trigger_extraction_now}` + 17 个 invoke 命令,state.rs/lib.rs/knowledge.rs/commands/mod.rs **零改动**。
|
||
- `cargo check` 0 error,`cargo test ai::` 19 passed。剩 3 warning 全为预存非本次引入。
|
||
- 顺带修 bug:`ai_conversation_list` 的 `models` 字段从 JSON 字符串直塞改为解析为 `Vec<String>` 数组下发(前端期望数组,原代码传字符串)。
|
||
- **状态**:✅ 2026-06-14 落地(11 子 module + glob 重导出 + models bug 修复,cargo check/test 通过)
|
||
|
||
### 前端 ai.ts 拆分:路线A(store 留 state 单例 + composable),不引入 Pinia [2026-06-14]
|
||
- **决策**:`src/stores/ai.ts`(758 行 god store)拆成 store 骨架(留 reactive state 单例 + 模块级私有变量)+ `src/composables/ai/` 下 6 个 composable(`useAiEvents`/`useAiStream`/`useAiSend`/`useAiConversations`/`useAiWindow`/`useAiPanel`)。`useAiStore()` 统一入口展开所有 composable 方法,**返回 shape 不变,组件零改动**。
|
||
- **原因/取舍**:
|
||
1. **与项目既有 store 风格一致**——project/knowledge/settings 全是「手写 reactive + 工厂函数」模式,引入 Pinia 会破坏一致性、增加心智负担。
|
||
2. **组件零改动**——AiChat.vue/AiDetached.vue 等用 `const { state, sendMessage } = useAiStore()` 解构,保持 `useAiStore` 返回 shape 不变即可。
|
||
3. **选路线 A(composable 挪逻辑、store 留 state)而非路线 B(Pinia 多 store)**——后者要改 19 个 state 字段归属和所有组件 import,风险远大于收益。
|
||
4. **与后端 ai.rs 子 module 拆分配对**——前后端 god file/god store 同步拆解,采用各自生态的惯用拆法(Rust 子 module / Vue composable),不强求统一模式。
|
||
- **影响**:确立项目 store 架构约定(手写 reactive + composable,不用 Pinia),影响所有未来 store 设计。
|
||
- **状态**:🚧 执行中(workflow w20yb6n6b 编排,vue-tsc 自验证)
|
||
|
||
### AI trait 下沉:拆 df-ai-core 轻层,确立全局 AI 接入标准 [2026-06-14 📐]
|
||
|
||
- **决策**:将 `LlmProvider` trait + AI 数据类型(`ChatMessage` / `CompletionRequest` / `ToolDefinition` 等)从 `df-ai` 拆出,下沉到新轻量 crate `df-ai-core`(零 http 依赖);`df-ai` 保留为「实现 + `ModelRouter` + provider 工厂」hub(持有 `reqwest`/`openai_compat`/`anthropic_compat`);所有消费 crate(`df-ideas` 接对抗评估、未来 `df-knowledge`/`df-workflow` 等)**只依赖 `df-ai-core` 的 trait,不直接依赖 `df-ai`**;真实 provider 由 `src-tauri` 最上层装配注入。**F-260614-03 及后续所有 AI 接入点统一照此,不再 per-module 自定义 trait。**
|
||
- **原因/取舍**(纯 ai-coding 工作模式下重算 F-03 原 A/B/C 选型):
|
||
1. **砍「人审查的契约面」而非「打字量」**——一份全局 trait = 一份契约给人过目 + 规格契约 self-check 锚一点;per-module 自定义 trait(原 A)= N 份发散契约,审查负担与漂移风险同涨。纯 ai-coding 下接线/mock 全由 AI 吸收,故 A 的「适配器成本」、B 的「mock 成本」论点作废。
|
||
2. **保住纯逻辑 crate 零摩擦自检**——`df-ideas`/`df-storage` 只依赖 trait 不拖 `reqwest`,规格契约机制 A/B 测试自动跑无 http 依赖;裸 B(df-ideas 直接依赖 df-ai)会污染纯逻辑 crate、自检摩擦上升。
|
||
3. **与现有 roadmap 对齐**——`ModelRouter`(F-260614-01)、多 Provider 负载均衡池(F-260614-04)、provider 工厂(已落地)本就在 df-ai 内走「gateway」方向,消费方选型应顺此而非另起 N 个 trait。
|
||
4. **无环且与 ai.rs 拆分不冲突**:`df-ai-core`(叶,trait+类型)← `df-ai`(impl) / `df-ideas`(use trait),`src-tauri` 装配。「ai.rs 子 module 不下沉 crate」规避的是 src-tauri→df-ai 反向依赖;本决策是 df-ai→df-ai-core 正向拆分,方向相反、互不矛盾。
|
||
- **否决项**:纯 A(per-module trait)= 全局 N 份发散契约,反模式;裸 B(df-ideas 直接依赖 df-ai)= 纯逻辑 crate 被 reqwest 污染、自检摩擦上升。
|
||
- **退路**:若不愿加新 crate,trait 可放 `df-core`(语义稍糙——LLM 非领域类型,但零新 crate,可接受)。
|
||
- **状态**:📐 设计决策已定(2026-06-14),未实施。落地链:① 新建 `df-ai-core` + 迁 trait/类型;② `df-ai` 改依赖 `df-ai-core` + 留实现;③ `df-ideas` 加 `df-ai-core` 依赖、`AdversarialEngine::evaluate` 加 provider 注入参数;④ src-tauri 装配真实 provider。
|
||
|
||
## 工作流人工审批节点(B-03)
|
||
|
||
### HumanNode 审批响应机制:subscribe→send→select! 广播过滤等待 [2026-06-14 📐]
|
||
- **决策**:df-workflow `HumanNode.execute` 改为「先 `subscribe()` → 发 `HumanApprovalRequest` → `tokio::select!` 循环等 `HumanApprovalResponse`」,按 `execution_id + node_id` 双键过滤命中后返回 NodeOutput;`select!` 三分支 = 响应 / 超时(配置 `timeout_secs` 默认 3600s)/ 取消(500ms 轮询 `is_cancelled`)。复用既有 `EventBus`(broadcast) / `HumanApprovalResponse` 事件 / `approve_human_approval` IPC / 前端 store——零新增基础设施,仅改 HumanNode 一处。
|
||
- **原因/取舍**:
|
||
1. **订阅时序铁律**:tokio broadcast 不回放历史,必须 `subscribe()` 先于 `send(Request)`,否则 receiver 错过 Response 死等超时。
|
||
2. **双键过滤**:node_id 单键不够(跨工作流可能重复)、execution_id 单键不够(同层多 HumanNode),双键才完备。
|
||
3. **Lagged 容忍**:capacity 256 + 审批低频,漏自身 Response 概率极低;`continue` 优于丢弃(丢弃误判超时更糟)。
|
||
4. **decision 强制校验**:options 非空时强制 `decision ∈ options`,非法值报错而非静默放行——审批门控不能被脏输入绕过;options 空时允许自由文本。
|
||
5. **B-06/B-07 是并发隔离/取消的前置,非单流功能前置**:单工作流 B-03 照常工作;并发安全等 B-06(execution_id 下沉);取消机制需 B-07 + `set_cancelled` + cancel IPC,单列 **B-03b**。B-03a(响应等待 + 超时)不依赖 B-07。
|
||
- **边界**:取消分支在 B-07 + `set_cancelled` 补齐前恒 false(等价无取消,功能不残);跨工作流并发 HumanNode 在 B-06 修前有 Response 错配风险。
|
||
- **状态**:📐 设计完成(2026-06-14),未实施。详见 [B-03-人工审批响应机制.md](./B-03-人工审批响应机制.md)。
|
||
|
||
## 需求与待办
|
||
|
||
> 汇集散落于各决策条目状态(📐/🚧)的待办 + 新增需求细节 + 需求澄清。单一清单,避免遗漏。
|
||
|
||
### 📋 待做需求
|
||
|
||
| 需求 | 功能域 | 来源 | 优先级 |
|
||
|---|---|---|---|
|
||
| Sprint 9/10 多项编译过未 tauri dev 实测(评分 IPC 缩放 / update_full / promote_idea / Store getter) | 灵感/立项/Store | Sprint 9–10 🚧 | P1 |
|
||
| 切对话不中断路由:部分场景运行时实测 | AI Chat 可靠性 | Sprint 8 🚧 | P1 |
|
||
| 技能联想「使用」:首批 3 类联想已做,联想后实际触发/执行技能未实现 | 技能/联想 | Sprint 8 | P2 |
|
||
| 灵感对抗评估接 LLM:论点/evidence 由 df-ai LlmProvider 生成(现启发式 fallback) | 灵感模块 | Sprint 9 📐 | P2 |
|
||
| 知识库 Tier 1:AI Chat ↔ 知识库双向闭环(沉淀+检索注入+reuse_count+审核收件箱+状态机+provenance 溯源+克制检索,无人工评分) | 知识库 | 2026-06-13 ✅ 已实施(Sprint 15) | P1 |
|
||
| 路径校验根治:workspace 白名单 + canonicalize(现仅拒 `..` + 敏感目录) | 工具调用 | Sprint 6 | P2 |
|
||
| 停止生成 idle 即时优化:`tokio::sync::Notify` 替代 120s 轮询 | AI Chat 可靠性 | Sprint 6 | P3 |
|
||
| 多 Provider 负载均衡池(备用模型/多账号聚合,全局容量=min(各 provider 上限之和, global_cap)) | AI Chat 并发控制 | 2026-06-13 📐 | P2 |
|
||
| 裁剪/压缩消息按需召回(Query Function + 分层存储: TrimRecord 追踪被移除范围 → DB 全量归档按需检索 → 精准注入 build_for_request;触发方式待定:自动/手动/语义检索) | 上下文窗口管理 | 2026-06-13 📐 | P3 |
|
||
| ✅ IPC参数驼峰/蛇形不对齐(误报澄清):Tauri v2 自动将前端 camelCase 参数名转后端 snake_case,`approve({toolCallId})` / `setConcurrencyConfig({globalLimit})` 实际正确、功能正常——无需修 | AI Chat | 2026-06-13 审查误报 | — |
|
||
| 🔴 df-workflow ConditionEngine 默认 true:所有未识别条件表达式均通过,工作流条件分支形同虚设,改 `Ok(false)` 或 `Err` 一行可修 | 工作流引擎 | 2026-06-13 代码审查 | P0 |
|
||
| 🔴 df-workflow DagExecutor execution_id 硬编码 "dummy-execution-id":所有执行 ID 相同,追踪/审计失效 | 工作流引擎 | 2026-06-13 代码审查 | P1 |
|
||
| 📐 df-workflow HumanNode 假实现:execute 注释"等待审批"但首次迭代直接 return "同意" — **设计完成 [B-03-人工审批响应机制.md](./B-03-人工审批响应机制.md),待实施**(依赖 B-06 并发隔离 / B-07 取消前置) | 工作流引擎 | 2026-06-13 多代理探索 → 2026-06-14 设计 | P0 |
|
||
| 🔴 df-workflow NodeRegistry::default() 的 script 工厂 unimplemented! panic:用 default() 构建注册表 + 跑 script 节点即崩溃进程(非优雅 Err) | 工作流引擎 | 2026-06-13 多代理探索 | P0 |
|
||
| 🔴 df-workflow executor 每节点拿全新空 StateMachine:self.state_machine 从不传入 NodeContext,HumanNode is_cancelled 恒 false,取消机制失效 | 工作流引擎 | 2026-06-13 多代理探索 | P1 |
|
||
| 🟡 promote_idea 两步写非事务:INSERT project 成功后若 UPDATE idea 失败,项目存在但想法状态未变,补偿删除可修 | 灵感/立项 | 2026-06-13 代码审查 | P1 |
|
||
| 🔴 分离窗口(detached)跨窗口状态失效:用 localStorage 传递生成态快照(df-ai-gen/text),Tauri 多 webview 不共享 localStorage 致静默失效;用户点 X 关闭(非 closeDetachedWindow)后主窗口 `detached` 永真卡死(reattachPanel 死代码未接线)。需改 Tauri 全局 emit/listen 同步 + 窗口销毁事件复位 | AI Chat 分离窗口 | 2026-06-13 代码审查 | P1 |
|
||
| 模型能力声明与自动路由系统 Phase 1:ModelCapability 数据模型 + ModelRouter 重写 + 7 调用点接入 + Settings 模型池编辑 UI + AiChat 模型下拉。核心:按任务需求(模态/功能/成本)自动匹配合适模型,不再所有场景共用 default_model | 模型能力与路由 | 2026-06-13 📐 设计完成 | P1 |
|
||
| 模型能力系统 Phase 2:多模态消息支持——ChatMessage.content: String → Vec<ContentPart>(Text/Image);前端粘贴/拖拽图片;vision 模型自动路由 | 模型能力与路由 | 2026-06-13 📐 | P2 |
|
||
| 模型能力系统 Phase 3:Agent 内智能路由——Agentic Loop 每轮按子任务构造不同 TaskRequirements;成本预算控制;模型级联降级;跨 Provider 搜索 | 模型能力与路由 | 2026-06-13 📐 | P3 |
|
||
| 📋 待澄清「显示多开」:用户报"设置里勾选'显示多开'但 AiChat 未显示"。全 src grep `多开\|多窗口\|multi\|multiInstance` 零命中;Settings.vue `settings` 对象仅 8 字段无此项。AiChat 唯一相关的是常驻「分离窗口」按钮(不受设置控制)。疑似:① 用户指分离窗口按钮(本就常驻不需设置);② 看的是打包旧版本界面;③ 想新增"允许分离窗口"设置开关。待用户截图/确认位置再定 | AI Chat | 2026-06-13 需求澄清 | — |
|
||
| 🔴 待审批持久化根治(重启恢复)未生效——两处逻辑断裂致恢复链路跑不通:① `ai_conversation_switch` 无条件 `pending_approvals.clear()` 清空 `restore_pending_approvals`(init)重建的内存 HashMap,而 `ai_pending_tool_calls`/`ai_approve` 均依赖内存态 → 重启后前端 `switchConversation` 触发 clear → 审批卡片查空永不显示、审批报"未找到挂起的审批";② `ai_approve` 的 recovered 守卫跳过 `save_conversation`(注释称"防空 messages 污染老对话")前提不成立——switch 时 `restore_from_messages` 已载完整历史,审批时 messages 非空 → 执行的工具结果不落库,重启后 toolCard 显示 completed 但 result 仍是占位"需要用户审批,等待确认"。修复方向:pending 恢复链路改查 DB(`ai_tool_executions` WHERE status='pending' 持久化真相源)绕过内存 clear;`ai_approve` 内存 miss 时 fallback DB 单条重建再执行;recovered 审批通过后正常 save。可顺带删 `restore_pending_approvals`(DB 即真相源)。阻断用户"功能逻辑层面解决"诉求——现"根治"实为表面修复 | AI Chat 审批持久化 | 2026-06-13 /review 审查①② | P0 |
|
||
| 📋 审批可见性缺口:pendingApprovals 无兜底渲染→卡死 [2026-06-13]:AI 发起 Med/High 工具审批(AiApprovalRequired)后暂停等审批不发 delta;前端审批唯一出口是 ToolCard 的 pending_approval 内联卡片(靠 findToolCall 置 tc.status),但 state.pendingApprovals 数组有数据却零渲染(AiChat.vue 仅 @approve 转发,无 pendingApprovals 模板)。若 tc 卡片未显示审批,用户看不到审批按钮 → AI 永久等 → 文字停卡死。待修:A. AiChat.vue 加 pendingApprovals 醒目渲染(顶部条/浮层)兜底审批可见性;或 B. 运行时确认 tc 卡片是否渲染。配套:watchdog 在 AiApprovalRequired 暂停,审批没弹则 watchdog 盲点,需加"审批超时未响应"提示 | AI Chat 审批 | 2026-06-13 | 📋 A/B 待定 |
|
||
| 📋 node_executions 全表 list:当前只写不读,若未来前端要看某次工作流执行的节点明细,需**新增** `list_node_executions(execution_id)` 命令 | 工作流引擎 | 2026-06-13 代码审查 | 📐 待需求驱动 |
|
||
|
||
### 📋 需求澄清
|
||
|
||
- **「决策」术语边界**(2026-06-12):devflow 语境「决策/决策需求点」= 日常开发功能细节取舍(为什么这么定),**非** aichat 决策能力升级(B 路线 coordinator/conditions)。后者属架构层,记 Phase2计划/模块文档,不混入本文档。
|
||
- **代码审查甄别原则**(2026-06-13):审查发现问题时,按「运行时失败/数据损坏 → 简单清理 → 记录不动 → 不做」四档甄别。当前项目规模下,list_all 无 LIMIT、ALLOWED_COLUMNS 不分表、bool→int 重复等属「记录不动」——个人工具表不超千行,加分页/拆白名单是过度设计,维护成本 >> 收益。原则:**真实 bug 修、简单清理做、规模不到位的优化先不动**,保持全局简洁和扩展容易。
|
||
|
||
**相关文档**:
|
||
- [Phase 1 架构决策](./Phase1架构决策.md) — 架构级决策(ADR)
|
||
- [经验记录](./经验记录.md) — 踩坑/约定/技巧/bug 排查教训
|
||
- [功能决策记录-归档](./功能决策记录-归档.md) — 纯流水/老 Sprint/UX 微调/已被取代
|
||
- `PROGRESS.md` — 各 Sprint 工作流水与遗留
|
||
- [Phase 2 计划](../07-项目管理/Phase2计划.md)
|