Files
DevFlow/docs/待决策.md
绝尘 cb7e1fce82 新增: 小程序配置持久化与心跳闭环 + 文档同步
小程序(mobile client)三项改进:

一、配置持久化(分发前置)
- 运行时配置(relay 地址/设备 ID/token/心跳间隔)接入 storage
- 懒加载:首次读取从 storage 恢复,合并默认值兼容旧字段
- 新增重置函数:清除 storage + 回到默认占位值
- 读写失败降级不崩溃

二、心跳 pong 闭环(移动网络可靠性)
- 中继服务识别小程序心跳 ping,直接回 pong(不经桌面端透传)
- 小程序收到 pong 更新入站时间,半连接看门狗据此判活
- 治移动网络 TCP 半连接挂死(socket 仍开但无响应)

三、文档同步关闭已完成项
- 条件表达式引擎:求值器+执行器+前端编辑入口+翻译均已落地
- 流式状态按会话隔离:accessor 委派 per-conv Map 已落地
- 灵感录入增强:表单已含来源/标签/优先级字段
2026-06-28 23:55:51 +08:00

311 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 待决策队列
> **职责分离**:
> - **主会话**(汇总/巡检)→ 【写入】"当前队列",登记待人工决策项(背景 + 决策点 + 选项 a/b/c + 推荐)。
> - **用户**(人工)→ 【拍板】选选项或确认推荐,回填理由(可选)。
> - **主会话**(拍板后)→ 决策项回流 [todo.md](./todo.md) 推进 + 迁入"已决归档"。
>
> 这里**只放需人工决策项**(产品取舍 / 方向选型 / 排期 / 用户实测澄清)。不放可自主推进待办(见 [todo.md](./todo.md))、不放审查登记(见 [待审查.md](./待审查.md))。
>
> **已决策历史**按月归档,见 [07-项目管理/待决策归档/](./07-项目管理/待决策归档/)。拍板后的项迁入对应 `YYYY-MM.md`(随时间增长追加月份文件,防本文件膨胀;文件不存在则新建)。
> 来源:2026-06-16 从 todo.md 抽离③④C类(可自主批 AE-03/复核⑪/UX-04 留 todo 推进)。
## 决策规则
- 每条须:背景 + 决策点 + 选项 + 推荐 + 关联 todo。
- 用户回填:`✅ 决策:X`(选 + 理由可选)。
- 拍板后:主会话回流 todo 实施 + 迁入 [07-项目管理/待决策归档/YYYY-MM.md](./07-项目管理/待决策归档/)(按月文件)。
- 暂缓项标 ⏸️,不删(条件变化可重启)。
## 状态图例
🟡 待决 / ✅ 已决(回填决策) / ⏸️ 暂缓(待条件)
---
## 当前队列
### 🟡 待用户实测/澄清(需用户操作,主会话无法代办)
#### S-260614-02 审批可见性实测重评
- **待用户操作**:实测 tc 卡片是否渲染。B-01 修复后 pending_approvals 内存态不再被 switch 清空,前端查询有数据,但 state.pendingApprovals 在 AiChat.vue 是否有兜底渲染仍需实测。
- **选项**:A 加兜底渲染 / B 实测确认(去重:AR-3 修完已缓解,改实测重评)
- **状态**:🟡 待用户实测
#### T-260614-01 多项 tauri dev 实测
- **待用户操作**:Sprint 9/10/14/15/16/18 多项未 tauri dev 实测 — 评分 IPC 缩放 / update_full / promote_idea / Store getter / token 落库 / 知识库 Tier 1 全栈 / LLM 并发 Semaphore / 知识生命线(#54 跟踪)。
- **状态**:🟡 待用户实测
#### T-260614-02 切对话不中断路由实测
- **待用户操作**:部分场景运行时实测(A 路线场景 2/3)。
- **状态**:🟡 待用户实测
### 🟡 待设计/架构演进(有决策点,需方案设计或长期规划)
#### T-260614-11 条件表达式引擎升级(✅ 已完成)
- **背景**:df-workflow conditions 仅支持 true/false 字面量,升级为真表达式求值。
- **解决**:手写求值器(option a)已实现并集成。
- `ConditionEngine::evaluate()` 支持完整表达式:JSON Path(`$.status == 'completed'`)/ 嵌套属性 / 数组索引 / 数值比较 / 布尔字段
- executor 集成(`cfg!(feature = "conditions-eval")` 默认开)
- 前端 UI 已有边条件编辑入口(`WorkflowDagDisplay.vue`)
- 中英文翻译已补齐
- **状态**:✅ 已完成
#### ARC-260615-07 架构重构批(排期/优先级决策)
- **背景**:src-tauri IPC 编排层 5711 行成事实业务层,7 项架构债。df-core→df-types 已完成(CR-61),剩 6 项独立大改。
- **核验与推进(2026-06-28)**:
- a: df-app 抽取(IPC 编排层独立 crate) — ⏸️ 缓做(当前规模可控,lib.rs 415 行)
- b: AI agent loop 从 IPC 下沉 df-ai(逻辑与 IO 分离) — ⏸️ 缓做(agentic/mod.rs 2203 行,模块拆分充分)
- c: 类型契约 ts-rs 代码生成(替代手写 types.ts) — ⏸️ 缓做(波及大,ROI 中等)
- d: AiSession 多会话(B 路线前置) — ✅ 已完成(per_conv 隔离)
- e: AppState 分组(1411 行 state 拆分) — ✅ 已完成(2026-06-28:拆为 state/{allowed_dirs, knowledge_config, llm_concurrency} 三个独立文件)
- f: IPC 命名统一 — ⏸️ 缓做(破坏性变更,需同步前端 invoke 调用,风险高于收益)
- **状态**:✅ d+e 已完成,a/b/c/f 评估为缓做(低 ROI / 高风险)
#### UX-260617-01 aichat 消息全量重叠(✅ 已解决)
- **背景**:用户实测消息大量重叠堆叠。5 角度分析排除 CSS/scoped/DOM,核心嫌疑虚拟滚动 IO 半激活态不一致 + height=0 未设 minHeight → slot 塌 0 → 重叠。
- **根因**:虚拟滚动实现引入的 IO/RO 时序竞态(option a 确认)。
- **解决**:删除虚拟滚动实现(`useAiVirtualScroll.ts` 移除),`MessageList.vue` 消息恒渲染,重叠根治。
- **代价**:长对话性能下降(无虚拟化),正确性优先。
- **状态**:✅ 已解决(2026-06-18 删除虚拟滚动根治)
#### UX-260617-28 双监听器同通道(✅ 已解决)
- **背景**:useAiEvents + useAiContext 各自 listen('ai-chat-event'),靠手写 flag 协调防双重处理,非架构保证。
- **解决(2026-06-28)**:治本性重构——
- 5 类生命周期事件(AiCompressing/AiManualCompressed/AiAutoCompressed/AiContextCleared)加入 AiChatEvent 联合类型
- useAiEvents.handleLifecycleEvent 统一处理生命周期事件
- 删除 useAiContext 的独立第二监听器,改为注入回调到 useAiEvents 统一分发器
- 架构保证:一个事件源 → 一个监听器 → 一个分发器,无双重处理风险
- **状态**:✅ 已解决(2026-06-28 统一监听器重构)
#### ARC-260618-01 God 文件拆分批(架构重投入·需设计)
- **背景**:~~2026-06-18 架构坏味道扫描出 3 个 God 文件~~
- **核验结论(2026-06-28)**:三项拆分均已全部完成:
- **a `tool_registry.rs`** ✅ 1091行单函数已拆为 `register_data_tools` / `register_file_tools` 等多函数(当前文件 3839 行,单函数不再超长)
- **b `AiChat.vue`** ✅ 原 4026 行 → **767 行**(已抽 `ToolCard.vue`/`ToolCardList.vue` 等子组件到 `components/ai/`)
- **c `crud.rs`** ✅ 原 2212 行 → 已拆为 `crud/` 目录下 11 个独立 repo 文件(不复存在)
- **状态**:✅ **全部完成**,无需进一步拆分
#### SMELL-P1-6 String→newtype 强类型(纯重构)
- **背景**:execution_id/status/tool_type 等 5+ 处用裸 String,类型安全弱(混用/拼写错编译期不拦)。
- **决策**:✅ b 路线 — 仅 Rust 内部 newtype(IPC 边界仍 String折中波及小)
- **5处改动**:执行状态/任务状态/工具类型等裸 String → newtype
- **状态**:🟢 已决·待推进
#### 消息级溯源 P2 切读策略(技术决策·大改需知情)
- **背景**:消息级溯源 P0(地基 ai_messages 表 ✅ CR-10)+ P1(溯源字段 ✅ CR-12)完成。P2 切读是拆表实际启用(读写路径从 `ai_conversations.messages` JSON 切到 `ai_messages` 表)。
- **决策**:✅ **b 一次性切读**。读写路径直接切换,保留原 `ai_conversations.messages` 列数据不删(数据安全,可回退)。
- **状态**:🟢 已决·待推进
### df-miniapp 全功能审查(2026-06-23 workflow wll7qabgr + 主代补审)
> 6 区域并行审查(chat/会话页/useAiChat/连接层/组件/工程)。以下为仍待决策/暂缓项。
#### MINIDEC-260623-01 relay 配置层范围(F15·产品方向·分发卡点)
- **背景**:config.ts relayHost/deviceId/token 全硬编码(setConfig 零调用方,storage 未接,无设置页)。当前填测试服 wss + 本机 device_id(联调期)。分发后用户无法改连自托管中继 → 连不上。
- **决策点**:配置层做到什么程度?
- **选项**:
- a: 完整设置页(表单 + setConfig 接 storage 持久化 + getConfig 回退),用户可改 relay/device/token
- b: 仅接 storage 持久化(setConfig 真生效,无 UI,靠代码/build env 注入)
- c: MVP 接受硬编码(仅自用联调),设置页立项后续
- **推荐**:**b 至少接 storage**(成本极小让配置真生效);a 设置页 UI 视分发排期。依赖 S-260623-01「自托管」含义(c 自托管后端 → 必须 a)。
- **关联**:S-260623-01 / memory cross-end-rust-backend
- **状态**:⏸️ **暂缓(2026-06-23)** —— 用户决策:当前自用,硬编码够;分发阶段(产品终态)再做设置页。过渡期多机靠改 device_id。
#### MINIDEC-260623-02 配对绑定流程(F16·跨端大改)
- **背景**:ControlMessage.pair 类型已定义但从不发送,deviceId/token 靠用户手抄(查桌面端 KV)。无二维码配对/绑定校验链路。
- **决策点**:配对流程是否本轮做?
- **选项**:
- a: 完整配对(桌面端生成 QR → relay 校验绑定 → miniapp 扫码获 device_id/token)
- b: MVP 过渡(设置页手填 + UI 提示去哪找 device_id/token)
- c: 不做(手抄够用)
- **推荐**:**⏸️ b MVP 过渡**(a 跨端协作工作量大,依赖 MINIDEC-260623-01 设置页先落)
- **关联**:MINIDEC-260623-01
- **用户已定未来愿景(2026-06-23)**:分发阶段做完整配对授权,三步:① 设备端弹二维码 ② 小程序扫码识别并授权,双方来回点击确认 ③ 授权管理(设定授权的权限范围等)。本轮不做,留专项。
- **状态**:⏸️ **暂缓(2026-06-23)** —— 当前自用靠手抄 device_id;分发阶段按上述愿景做完整 QR 配对 + 权限范围管理(跨端 df-miniapp/df-relay/桌面端协同,专项立项)。
#### MINIDEC-260623-06 心跳/历史替换协议(F8/F20·跨模块·低优先)
- **背景**:(F8)心跳活性检测依赖「任意入站消息」,低活跃场景每 ~60s 误判半开死连接触发无谓重连(relay 无 pong);(F20)AiMessageHistory 整体替换会丢弃正在进行的乐观气泡(device 主动推历史路径难区分 load 响应)。
- **决策点**:是否本轮改 relay 协议?
- **选项**:
- a: relay 加 pong + 历史事件加 load_id/sync_source flag(跨模块改 df-relay + 后端 events)
- b: 前端缓解(放宽 DEAD_FACTOR / 「仅本地空才替换历史」启发式,语义脆弱)
- c: 暂缓(MVP 低频空闲场景可忍)
- **推荐**:**⏸️ c 暂缓**(跨模块改动 ROI 低)
- **状态**:⏸️ 暂缓
---
## workspace_root 分发适配(✅ 已解决)
**背景**:workspace_root_path() 用 env!("CARGO_MANIFEST_DIR") 编译期写死开发机路径,分发到其他机器后失效。
**解决(2026-06-28)**:治本方案①——去默认白名单。
- `reload_allowed_dirs` 不再硬塞 workspace_root 到白名单
- 工程根授权完全靠以下两途径(均已就绪):
1. projects.bind_directory:用户绑定项目时自动授权
2. Settings 页 allowed_dirs:用户手动添加持久化白名单
- workspace_root_path() 函数保留:旧 .trash 迁移(init 中一次性)仍需读取
- dev 自用场景:开发机运行时 projects.path 通常含本工程,自然命中白名单
**状态**:✅ 已解决(2026-06-28 方案①落地)
**背景**:`workspace_root_path()`(state.rs)/ `workspace_root()`(tool_registry.rs)/ `workspace_root_str()`(mod.rs)三处同源用 `env!("CARGO_MANIFEST_DIR")`(编译期写死编译机源码路径)。DevFlow 打包分发后:
- 用户机器无编译机路径(如 `E:\wk-lab\devflow`)→ workspace_root 失效
- 跨平台(Windows/Linux 各发行版)各自编译机路径写死,分发到不同机器/平台均失效
- 影响:相对路径锚点(check_path_authorization / resolve_workspace_path_impl)+ 默认白名单(default_with_root)+ run_command 默认 working_dir 均依赖此值,分发后指向不存在路径 → AI 文件工具全部失效
**当前(开发机自用)**:CARGO_MANIFEST_DIR = 开发机 DevFlow 源码,AI 访问源码合理。仅开发期有效。
**根因**:workspace_root 语义错位 — 当前 = DevFlow 自身源码目录(开发 DevFlow 的语义);但 DevFlow 分发后是"用户用它开发自己项目的工具",workspace_root 应 = 用户项目(动态,非编译期)。
**方向(运行期动态 workspace_root)**:
- **a current_exe 安装目录**:`std::env::current_exe().parent()`。分发后 = 安装目录。但安装目录非用户工作空间(AI 应访问用户项目,非 DevFlow 安装目录)。语义仍错。
- **b 用户项目绑定(推荐方向)**:workspace_root 概念淡化,默认白名单 = 用户绑定项目(projects.path,reload_allowed_dirs 已读),相对路径锚 = 当前活跃项目目录。无固定编译期 root。最贴合"用户用 DevFlow 开发自己项目"语义。需改 check_path_authorization / resolve 锚活跃项目(当前锚固定 workspace_root)。
- **c 用户配置工作空间**:KV workspace_path,用户首启配置。灵活但需 UI + 首启引导。
- **d 混合**:debug 开发期 CARGO_MANIFEST_DIR(源码)/ release 分发期 current_exe 或用户项目(`cfg!(debug_assertions)` 区分)。过渡方案。
**决策点**:
- workspace_root 语义(DevFlow 安装目录 vs 用户项目 vs 用户配置工作空间)
- 相对路径锚点(固定 root vs 活跃项目)
- 是否区分开发期/分发期(cfg!(debug_assertions))
- docs/kms 开发机暴露(随 b/c 自然解决:无固定 root 则 docs/kms 不在默认白名单)
**关联**:F-260619-03 去固定根(已删 is_authorized 硬编码放行)/ projects.path 自动授权(reload_allowed_dirs)/ memory [[devflow-project-path-binding]]
**状态**:🟡 待决策(workspace_root 运行期动态方案 a/b/c/d)。**分发前必须解决**(否则分发后 AI 文件工具全部失效)。
**注**:授权弹窗侧三档(once 本次单次 / session 当前会话 / always 始终)已于 2026-06-24 落地(F-260619-03 Phase B 演进,AllowedDirs 加 once 层 + 弹窗加"当前会话"按钮,详见 todo + 待审查 CR-260624-01)——**授权机制侧就绪**。本节待决策的是**相对路径锚点**(固定编译期 root vs 活跃项目),非授权机制。
**2026-06-25 弱化决策(用户)**:方向**去掉"活跃项目/根据地"概念抽象**——active_workspace 全局缓存动态锚曾试加(state.rs OnceLock+SyncRwLock + reload_active_workspace KV active_project_id)后撤回,用户明确不要此层。workspace_root 变量**暂留**(不删,resolve 相对锚/trust_key/run_command working_dir 仍引用),**弱化其默认依赖**。实质方案二选一分发前定:① 去默认白名单(default_with_root 不硬塞 workspace_root,工程根靠 projects.path 自动授权)② 去相对锚(AI 改绝对路径,相对路径不 join)。当前:逻辑不动,变量保留。
**2026-06-23 进展(BUG-260623-01)**:实测会话 6acb7f9b 暴露 write_file/append_file/rename_file 父目录校验**误用 workspace_root**(tool_registry.rs:1112/1418/1555 原用 `starts_with(workspace_root())`)→ 用户授权的其他项目目录(ai-news 等)parent 不 starts_with devflow 源码目录 → 误拒「禁止在项目目录之外创建目录」(用户授权了仍拒)。**已修**:三处改用 `allowed_dirs.is_authorized(parent)` 脱离 workspace_root。**仍写死残留**(待本决策 a/b/c/d 根治):delete_file:1482 trash 目录 / resolve_workspace_path_impl:380 相对路径 join / run_command:1791 working_dir 默认。
---
## F-260619-03 路径授权政策:工程内默认免授权(用户 2026-06-20 指令)
**用户政策指令**:"默认直接访问,明确知道无权限才申请"。
**实现现状(2026-06-28 核验)**:✅ 全部已落地——
- **层1 工程内默认免授权**:`reload_allowed_dirs` 无条件保留 workspace_root(`state.rs:839`)。
- **层2 workspace_root 外**:白名单制(不翻转黑名单),三种授权途径:
- **persistent**:Settings 页 `AllowedDirsPanel.vue` 添加(永久持久化)
- **session**:授权弹窗「未来都允许」(会话级)
- **once**:授权弹窗「仅本次」(单次)
- **黑名单兜底**:系统敏感目录(System32 / .ssh / .aws 等)硬拒,即便误入白名单也拒。
- **未授权非黑名单**:弹窗询问用户(PathAuthDecision::NeedsAuthorization)。
**决策(2026-06-28 用户确认)**:workspace_root 外通过授权弹窗访问或 Settings 界面配置白名单 —— 即当前白名单制,不翻转黑名单。
**状态**:✅ 已决·已实施
---
## F-09 streaming/currentText 改 per-conv(✅ 已完成)
**背景**:`streaming`/`currentText` 原为 store 全局单例,F-09 多会话并发下 A 后台生成 + 切 B 会话会串扰。
**解决(2026-06-28 核验)**:✅ option a 已落地——
- `stores/ai.ts``Object.defineProperty` 定义 streaming/currentText accessor
- 委派 `aiShared.convStreamStates` per-conv Map,按 `activeConversationId` 索引读写
- 单会话回归零变化(accessor 透明继承),多会话切会话不串扰
**状态**:✅ 已完成
---
## 已决归档
按月归档(随时间增长追加月份文件,防主文件膨胀):
- [2026-06.md](./07-项目管理/待决策归档/2026-06.md) — 2026-06 已决策/已实施/已排期/已解决历史(③类产品取舍 12 项 / ④类设计方向 6 项 / 重投入排期 8 项 / ④类续 5 项 / C类已解决 2 项)
### 2026-06-27 讨论已决
#### DEC-260627-01 F-09 B 路线(多会话真并发)
- **决策**:✅ 需要实施
- **记录**:用户确认需要推进多会话并发架构
- **状态**:✅ 已决
#### DEC-260627-02 Conditions 条件引擎
- **决策**:✅ 需要接入使用(开启 feature flag + 可视化)
- **记录**:用户确认需要启用条件引擎并接入工作流执行器
- **核验(2026-06-28)**:✅ 全部已完成——
- 引擎代码完备(`df-workflow/conditions.rs`)
- feature flag `conditions-eval`(默认开,cfg! 门控)
- 执行器集成(`executor.rs` 按入边 condition 过滤)
- 前端 UI(`WorkflowDagDisplay.vue` 可编辑边条件、保存、显示)
- i18n 中英文补齐(workflowCondPlaceholder 等)
- **状态**:✅ 已决·已实施
#### DEC-260627-03 @项目展开摘要(⑥.4 Phase4 前端)
- **决策**:✅ C 方案展开摘要
- **记录**:@[项目] 发送前可展开查看 enrichment 内容
- **状态**:✅ 已决
#### DEC-260627-04 历史消息渲染
- **决策**:✅ C 暂缓
- **记录**:长对话渲染卡顿暂不处理
- **状态**:✅ 已决
### 2026-06-27 讨论待定
#### 对话透明化 L1(目标钉扎可见)
- **背景**:G1 目标钉扎已落地,但用户完全看不见自己设了哪些目标
- **选项**:
- A: 不做
- B: 对话顶部显示目标列表
- C: 显示 + 可删除过时目标 + 持久化
- **决策**:✅ C 方案。对话顶部 🎯 显示目标列表(✅/🔄/⏳ 状态),可清除/编辑,持久化到 ai_conversations 表
- **配套**:模型选择器折叠缩小腾空间
- **状态**:✅ 已决
#### 灵感来源采集
灵感来源采集
- **背景**:灵感捕捉时没有自动记录来源
- **选项**:
- A: 对话自动采集
- B: 手动录入增强
- C: 暂缓
- **决策**:✅ C 暂缓。与知识库抽取共用一次 AI 调用,但灵感需用户确认后才创建(非自动写入)。需前端通知机制,当前不做
- **状态**:✅ 已决 — 暂缓
---
## 已决归档
### 2026-06-28 核验已决
#### DEC-260628-01 安全 8 项
- **核验**:全数已修(代码核验 2026-06-28)
- **详情**:① relay.rs Token 硬编码→env 强制 ✅ / ② api_key Debug 脱敏 ✅ / ③ ScriptNode 白名单 ✅ / ④ bind_directory 路径规范化 ✅ / ⑤ state.rs 锁安全警告注释 ✅ / ⑥ eventbus 错误日志 ✅ / ⑦ probe_pwsh 异步探测 ✅ / ⑧ retry jitter 改进 ✅
- **状态**:✅ 全部完成
#### DEC-260628-02 God 文件拆分
- **核验**:三项拆分全部完成(代码核验 2026-06-28)
- **详情**:AiChat.vue 4026→767行 / tool_registry 单函数已拆 / crud.rs 拆为11文件
- **扩展核验**:ToolCard.vue 拆分也已完成(1527→373行,useToolApproval/useToolCardHeader/useToolCardRender 全部独立)
- **状态**:✅ 全部完成
#### DEC-260628-03 审批 pending 超时兜底
- **决策**:✅ 后端 15min 超时自动取消,超时时长在 Setting 可配置
- **记录**:pending 超 15min→自动 cancel(status=cancelled)+LLM 收到回执
- **状态**:✅ 已实施(2026-06-28):后端 `agentic/approval_timeout.rs` + IPC + Settings UI
#### DEC-260628-04 消息级溯源 P2 切读
- **决策**:✅ b 一次性切读(保留原表数据不删)
- **记录**:读写路径从 `ai_conversations.messages` 切到 `ai_messages` 表,原列保留
- **核验(2026-06-28)**:✅ 全部已完成——
- 写路径:`save_conversation` 已全量重写 ai_messages
- 读路径:`ai_conversation_switch`/`ai_conversation_export`/`remote_bridge::route_load_messages` 优先读 ai_messages,表空时 fallback 旧 JSON(老库兼容)
- 最后一处补全:`knowledge_inject::extract_knowledge_from_conversation` 也切到 ai_messages
- **状态**:✅ 已决·已实施
#### DEC-260628-05 SMELL-P1-6 String→newtype
- **决策**:✅ b 路线(仅 Rust 内部 newtype)
- **记录**:5 处裸 String 改强类型,纯重构
- **评估**:5 处分散在 df-storage(df-types 已有 TaskStatus enum 覆盖)/df-ai/df-ai-core,IPC 边界仍 String 波及中等。属纯重构(无行为变化),优先级低于功能项,后续技术债窗口一并处理。
- **状态**:🟢 已决·优先级低(重构窗口处理)
按月归档(随时间增长追加月份文件,防主文件膨胀):