baa-conductor

git clone 

commit
8fe3836
parent
3283b54
author
im_wower
date
2026-03-27 22:25:11 +0800 CST
docs(claude): BAA instruction system review — BUG-018/019/020, MISSING-001/002/003, OPT-002~006
12 files changed,  +258, -9
M bugs/BUG-018-preflight-batch-fail-closed.md
+28, -3
 1@@ -1,8 +1,11 @@
 2 # BUG-018: preflight 整批失败 — 一条坏指令杀死所有并行指令
 3 
 4+> 提交者:Claude(代码审查)
 5+> 日期:2026-03-27
 6+
 7 ## 现象
 8 
 9-AI 发 3 个 baa 代码块,其中 1 个 target 不支持,preflight 对第一个不支持的指令 throw,导致整批 3 条指令全部失败。
10+AI 发 3 个 baa 代码块,其中 1 个 target 不支持(比如 `@browser.chatgpt::send`),preflight 对第一个不支持的指令 throw BaaInstructionCenterError,导致整批 3 条指令全部失败,包括 2 条完全合法的 `@conductor::exec`。
11 
12 ## 文件
13 
14@@ -14,8 +17,30 @@ preflight 用 `.map()` + throw,一个失败整个 map 中断。
15 
16 ## 修复
17 
18-改为 filter-and-collect:合法指令继续执行,不合法的收集到 denied 数组。processAssistantMessage 结果中包含 denied 信息。
19+改为 filter-and-collect 模式——合法指令继续执行,不合法的收集到 denied 数组:
20+
21+```typescript
22+private preflight(instructions) {
23+  const routed = [];
24+  const denied = [];
25+  for (const inst of instructions) {
26+    const decision = evaluateBaaInstructionPolicy(inst);
27+    if (!decision.ok) {
28+      denied.push({ instruction: inst, reason: decision.message });
29+      continue;
30+    }
31+    try {
32+      routed.push({ instruction: inst, route: routeBaaInstruction(inst) });
33+    } catch (error) {
34+      denied.push({ instruction: inst, reason: error.message });
35+    }
36+  }
37+  return { routed, denied };
38+}
39+```
40+
41+processAssistantMessage 结果中包含 denied 信息,让调用方知道哪些被拒了。
42 
43 ## 严重度
44 
45-High
46+High — 直接影响并行执行的核心场景
M bugs/BUG-019-unterminated-baa-block-throws.md
+14, -3
 1@@ -1,8 +1,11 @@
 2 # BUG-019: 未关闭的 baa 代码块导致整条消息处理失败
 3 
 4+> 提交者:Claude(代码审查)
 5+> 日期:2026-03-27
 6+
 7 ## 现象
 8 
 9-AI 回复中有一个未关闭的 ` ```baa ` 块时,extractBaaInstructionBlocks throw,已关闭的合法 baa 块也不会被处理。
10+AI 回复中有一个未关闭的 ` ```baa ` 块(比如 AI 在写示例时忘了关闭),extractBaaInstructionBlocks throw BaaInstructionExtractError,已关闭的合法 baa 块也不会被处理。
11 
12 ## 文件
13 
14@@ -18,8 +21,16 @@ if (pending?.isBaa) {
15 
16 ## 修复
17 
18-未关闭的块忽略(warn log),不 throw。已关闭的合法块正常返回。
19+未关闭的块忽略(warn log),不 throw。已关闭的合法块正常返回:
20+
21+```javascript
22+if (pending?.isBaa) {
23+  // 未关闭的 baa 块 → 忽略,不 throw
24+  // 可选:记录 warning
25+}
26+return blocks;
27+```
28 
29 ## 严重度
30 
31-Medium
32+Medium — AI 偶尔会输出未关闭的代码块
M bugs/BUG-020-inmemory-deduper-unbounded.md
+24, -2
 1@@ -1,8 +1,11 @@
 2 # BUG-020: InMemory 去重器无上限,长期运行内存泄漏
 3 
 4+> 提交者:Claude(代码审查)
 5+> 日期:2026-03-27
 6+
 7 ## 现象
 8 
 9-InMemoryBaaInstructionDeduper 和 InMemoryBaaLiveInstructionMessageDeduper 的 Set 只 add 不清理,没有 TTL 或 maxSize。
10+InMemoryBaaInstructionDeduper 和 InMemoryBaaLiveInstructionMessageDeduper 的 Set 只 add 不清理,没有 TTL 或 maxSize。长时间运行后 Set 无限增长。
11 
12 ## 文件
13 
14@@ -11,7 +14,26 @@ InMemoryBaaInstructionDeduper 和 InMemoryBaaLiveInstructionMessageDeduper 的 S
15 
16 ## 修复
17 
18-加 maxSize 限制(默认 10000),超出时清理最旧的 20%。或用 Map<string, number> 记录时间戳做 LRU。
19+加 maxSize 限制(默认 10000),超出时清理最旧的 20%。或改用 Map<string, number> 记录时间戳做 LRU:
20+
21+```typescript
22+class InMemoryBaaInstructionDeduper {
23+  private readonly keys = new Map<string, number>();
24+  private readonly maxSize = 10000;
25+
26+  add(instruction) {
27+    if (this.keys.size >= this.maxSize) {
28+      const entries = [...this.keys.entries()].sort((a, b) => a[1] - b[1]);
29+      for (let i = 0; i < entries.length * 0.2; i++) {
30+        this.keys.delete(entries[i][0]);
31+      }
32+    }
33+    this.keys.set(instruction.dedupeKey, Date.now());
34+  }
35+
36+  has(dedupeKey) { return this.keys.has(dedupeKey); }
37+}
38+```
39 
40 ## 严重度
41 
A bugs/MISSING-001-result-not-delivered-to-ai.md
+47, -0
 1@@ -0,0 +1,47 @@
 2+# MISSING-001: 执行结果没有回注到 AI 对话
 3+
 4+> 提交者:Claude(代码审查)
 5+> 日期:2026-03-27
 6+
 7+## 优先级
 8+
 9+**最高** — 端到端闭环的最后一环
10+
11+## 现状
12+
13+instructions/ 模块完成了 提取 → 解析 → 去重 → 权限 → 路由 → 执行 的完整链路。
14+artifacts/ 模块有 materialize、manifest、delivery-plan、upload-session 的完整代码。
15+
16+但**从执行结果到实际注入 AI 对话框**没有接通:
17+
18+- `upload-session.ts` 有 `this.bridge.injectMessage()` 和 `this.bridge.uploadFile()` 调用
19+- 但 `this.bridge` 是抽象接口,没有和 firefox-bridge 的实际 wiring
20+- conductor 执行完指令后,结果停留在 `BaaInstructionProcessResult` 中
21+- firefox-ws.ts 的 `handleBrowserFinalMessage` 调用了 `instructionIngest.ingestAssistantFinalMessage()`,但拿到结果后没有后续动作
22+
23+## 需要补的链路
24+
25+```
26+firefox-ws.ts 收到 browser.final_message
27+→ instructionIngest.ingestAssistantFinalMessage() 执行指令
28+→ 拿到 BaaInstructionProcessResult
29+→ 调 artifact materializer(根据结果大小决定 inline/artifact/artifact_only)
30+→ 生成 delivery plan
31+→ 通过 WS 下发 delivery plan 给插件
32+→ 插件执行上传(如有 artifact)
33+→ 插件返回 upload receipt
34+→ conductor 确认后生成索引文本
35+→ 通过 WS 让插件注入索引文本并发送
36+```
37+
38+## 涉及文件
39+
40+- `apps/conductor-daemon/src/firefox-ws.ts`:handleBrowserFinalMessage 需要加后续流程
41+- `apps/conductor-daemon/src/artifacts/upload-session.ts`:bridge 接口需要和 firefox-bridge 对接
42+- `plugins/baa-firefox/controller.js`:需要加处理 delivery_plan 消息的分支
43+
44+## 验收
45+
46+1. Claude 对话中 AI 回复包含 `@conductor::exec::pwd` → conductor 自动执行 → 结果回注到 Claude 对话框
47+2. 大结果走文件上传 + 索引文本
48+3. 小结果直接文本注入
A bugs/MISSING-002-plugin-delivery-plan-executor.md
+37, -0
 1@@ -0,0 +1,37 @@
 2+# MISSING-002: 插件侧没有 delivery plan 执行器
 3+
 4+> 提交者:Claude(代码审查)
 5+> 日期:2026-03-27
 6+
 7+## 优先级
 8+
 9+**最高** — 和 MISSING-001 配合,缺一不可
10+
11+## 现状
12+
13+controller.js 有 `relayObservedFinalMessage` 把最终消息发给 conductor,但没有处理 conductor 返回的 delivery plan。
14+
15+## 需要补
16+
17+controller.js 中加处理 WS 消息的新分支:
18+
19+```javascript
20+case "delivery_plan":
21+  await handleDeliveryPlan(message);
22+  break;
23+```
24+
25+handleDeliveryPlan 需要:
26+1. 按 plan.uploads 逐个上传文件(模拟拖拽到 AI 输入框的文件区域)
27+2. 每个上传完成后发 upload_receipt 回 conductor
28+3. 全部上传完成后,注入 plan.messageText 到 AI 输入框
29+4. 点击发送按钮
30+
31+## 涉及文件
32+
33+- `plugins/baa-firefox/controller.js`
34+
35+## 验收
36+
37+1. conductor 下发 delivery plan → 插件成功上传文件 + 注入文本 + 发送
38+2. 上传失败时返回失败 receipt,conductor 降级为文本注入
A bugs/MISSING-003-browser-target-blocked-in-phase1.md
+25, -0
 1@@ -0,0 +1,25 @@
 2+# MISSING-003: browser.* target 在 Phase 1 被完全拒绝
 3+
 4+> 提交者:Claude(代码审查)
 5+> 日期:2026-03-27
 6+
 7+## 优先级
 8+
 9+Medium
10+
11+## 现状
12+
13+`instructions/policy.ts` 的 SUPPORTED_TARGETS 只有 `conductor` 和 `system`。
14+
15+根据 BAA_INSTRUCTION_SYSTEM.md 的设计,Phase 1 应该包含 `browser.claude` 的 send/current 能力——这是能力互补的核心场景。
16+
17+## 修复
18+
19+1. policy.ts:SUPPORTED_TARGETS 加 `browser.claude`
20+2. router.ts:加 `browser.claude` → `POST /v1/browser/request` 的路由
21+3. send 工具:把 params 映射为 browser/request 的 body
22+
23+## 涉及文件
24+
25+- `apps/conductor-daemon/src/instructions/policy.ts`
26+- `apps/conductor-daemon/src/instructions/router.ts`
A bugs/OPT-002-executor-timeout.md
+16, -0
 1@@ -0,0 +1,16 @@
 2+# OPT-002: executor 缺少超时保护
 3+
 4+> 提交者:Claude(代码审查)
 5+> 日期:2026-03-27
 6+
 7+## 文件
 8+
 9+`apps/conductor-daemon/src/instructions/executor.ts`
10+
11+## 现状
12+
13+executeBaaInstruction() 直接调 handleConductorHttpRequest 无超时。如果 exec 命令卡住(死循环 shell 脚本),整个 instruction pipeline 无限阻塞。
14+
15+## 建议
16+
17+加 Promise.race 超时(默认 30s,exec 可配 60s)。或在 handleConductorHttpRequest 调用时传 AbortController。
A bugs/OPT-003-policy-configurable.md
+16, -0
 1@@ -0,0 +1,16 @@
 2+# OPT-003: policy 应支持配置化
 3+
 4+> 提交者:Claude(代码审查)
 5+> 日期:2026-03-27
 6+
 7+## 文件
 8+
 9+`apps/conductor-daemon/src/instructions/policy.ts`
10+
11+## 现状
12+
13+SUPPORTED_TARGETS 和 SUPPORTED_TOOLS 硬编码为 Set 常量。Phase 2 加新 target/tool 时需要改代码。
14+
15+## 建议
16+
17+改为 BaaInstructionCenter 构造时可传入自定义 policy(allowedTargets/allowedTools),默认值仍是当前 Phase 1 集合。
A bugs/OPT-004-final-message-claude-sse-fallback.md
+16, -0
 1@@ -0,0 +1,16 @@
 2+# OPT-004: final-message.js Claude SSE 拼接需要 fallback
 3+
 4+> 提交者:Claude(代码审查)
 5+> 日期:2026-03-27
 6+
 7+## 文件
 8+
 9+`plugins/baa-firefox/final-message.js`
10+
11+## 现状
12+
13+Claude 的最终消息提取依赖 SSE chunk 中 `type: "completion"` + `completion` 字段拼接。如果 Claude SSE 格式变化(新版 API 可能用 content_block_delta),拼接会断。
14+
15+## 建议
16+
17+加 fallback:SSE 拼接为空时,尝试从 DOM 提取最终文本(找到最后一个 assistant message 的文本节点)。
A bugs/OPT-005-normalize-parse-error-isolation.md
+16, -0
 1@@ -0,0 +1,16 @@
 2+# OPT-005: normalize 阶段 parse 错误不应中断整批
 3+
 4+> 提交者:Claude(代码审查)
 5+> 日期:2026-03-27
 6+
 7+## 文件
 8+
 9+`apps/conductor-daemon/src/instructions/loop.ts` normalize()
10+
11+## 现状
12+
13+.map() 遍历 blocks 解析,中间某个 block 格式错误 throw 后,后面的合法 blocks 不会被处理。和 BUG-018 同类问题。
14+
15+## 建议
16+
17+改为 flatMap + try/catch,解析失败的 block 跳过并记录到 parseErrors 数组,不影响其他 blocks。
A bugs/OPT-006-db-table-auto-cleanup.md
+17, -0
 1@@ -0,0 +1,17 @@
 2+# OPT-006: DB 表缺少自动清理策略
 3+
 4+> 提交者:Claude(代码审查)
 5+> 日期:2026-03-27
 6+
 7+## 文件
 8+
 9+- `ops/sql/migrations/0003_baa_execution_persistence.sql`
10+- `packages/db/src/index.ts`
11+
12+## 现状
13+
14+baa_message_dedupes、baa_instruction_dedupes、baa_execution_journal 三张表没有自动清理。store.ts 的 listBaaExecutionJournal 有 limit 参数但只影响查询,不影响存储。
15+
16+## 建议
17+
18+packages/db 中加定期清理方法(保留最近 30 天或最近 10000 条),在 conductor 启动时和每小时调用一次。
M plans/discuss/REVIEW-BAA-INSTRUCTION-IMPL.md
+2, -1
1@@ -1,6 +1,7 @@
2 # BAA 指令系统代码审查(Codex commit 72de524)
3 
4-日期:2026-03-27
5+> 提交者:Claude(代码审查)
6+> 日期:2026-03-27
7 审查范围:instructions/(11 文件)、artifacts/(5 文件)、final-message.js、content-script.js 扩展、firefox-ws.ts 扩展、local-api.ts 扩展、DB migration 0003
8 
9 ---