baa-conductor

git clone 

baa-conductor / PROGRESS
im_wower  ·  2026-03-28

2026-03-27-current-code-progress.md

  1# 当前代码进度核对(2026-03-27)
  2
  3## 结论摘要
  4
  5- 当前“已提交功能代码基线”仍可按 `main@25be868` 理解,主题是 `restore managed firefox shell tabs on startup`;在当前本地代码里又额外补上了 `BUG-011`、`BUG-012`、`BUG-013`、`BUG-014`、`BUG-017` 修复,以及 `T-S029`、`T-S030`、`T-S031`、`T-S032`、`T-S033`、`T-S034` 的功能落地。
  6- 当前浏览器桥接主线已经完成到“Firefox 本地 WS bridge + Claude / ChatGPT 代发 + ChatGPT / Gemini 最终消息 raw relay + live instruction ingest + dedupe/journal 本地持久化 + artifact/upload/inject/send 主链 + 结构化 action_result + shell_runtime + 登录态持久化”的阶段。
  7- 代码和自动化测试都表明:`/describe/business`、`/describe/control`、`GET /v1/browser`、`POST /v1/browser/actions`、`POST /v1/browser/request`、`POST /v1/browser/request/cancel` 已经形成正式主链路。
  8- 目前不应再把系统描述成“只有 Claude / ChatGPT request relay”;当前更准确的表述是“通用 browser surface 已落地,正式 request relay 已覆盖 Claude 和 ChatGPT,ChatGPT / Gemini 的 `browser.final_message` raw relay 也已接通,但这层仍只是最终消息中继,不等于 Gemini 正式 request relay 已转正”。
  9- 当前仍不能写成“全部收尾完成”。剩余未闭项主要是:风控状态仍是进程内内存态、ChatGPT 仍依赖真实浏览器登录态 / header 且没有 Claude 风格 prompt shortcut、ChatGPT / Gemini 最终消息提取仍有平台特定边界,以及 BAA 仍只做到单节点本地持久化、有界 journal、单客户端单轮 delivery 首版和 Phase 1 exact target。
 10- 此前拆出的后续任务卡里,`T-S026`、`T-S027`、`T-S028`、`T-S029`、`T-S030`、`T-S031`、`T-S032`、`T-S033`、`T-S034` 已完成;当前主线剩余任务是 `T-S035``T-S036` 11
 12## 本次核对依据
 13
 14### 代码核对范围
 15
 16- `../apps/conductor-daemon/src/local-api.ts`
 17- `../apps/conductor-daemon/src/firefox-bridge.ts`
 18- `../apps/conductor-daemon/src/firefox-ws.ts`
 19- `../apps/conductor-daemon/src/browser-request-policy.ts`
 20- `../apps/conductor-daemon/src/browser-types.ts`
 21- `../plugins/baa-firefox/controller.js`
 22- `../scripts/runtime/verify-mini.sh`
 23
 24### 本次实际执行的验证
 25
 26- `pnpm -C /Users/george/code/baa-conductor -F @baa-conductor/conductor-daemon build`
 27  - 结果:通过
 28- `node --test /Users/george/code/baa-conductor/apps/conductor-daemon/src/index.test.js`
 29  - 结果:`45/45` 通过
 30- `node --test /Users/george/code/baa-conductor/tests/browser/browser-control-e2e-smoke.test.mjs`
 31  - 结果:`8/8` 通过
 32- 真实 Firefox 手工 smoke(`plugin_status`、`tab_open`、`tab_restore`、`ws_reconnect`、扩展重载自动恢复)
 33  - 结果:通过;`ws_reconnect` 额外完成 `disconnect_ms=3000`、`repeat_count=3`、`repeat_interval_ms=500` 的 3 轮稳定性验证
 34
 35## 当前已完成功能
 36
 37### 1. 本地 API 和两层 describe 已落地
 38
 39- 代码里已经固定保留两层 describe:
 40  - `/describe/business`
 41  - `/describe/control`
 42- 浏览器正式接口已经收口到:
 43  - `GET /v1/browser`
 44  - `POST /v1/browser/actions`
 45  - `POST /v1/browser/request`
 46  - `POST /v1/browser/request/cancel`
 47- 证据:
 48  - `../apps/conductor-daemon/src/local-api.ts:3230-3250`
 49  - `../apps/conductor-daemon/src/local-api.ts:4700-4875`
 50  - `../apps/conductor-daemon/src/index.test.js:1734-1795`
 51  - `../apps/conductor-daemon/src/index.test.js:1840-1955`
 52
 53### 2. `GET /v1/browser` 已经是统一读面
 54
 55- 当前读面不只是 bridge 在线状态,还包含:
 56  - `bridge`
 57  - `current_client`
 58  - `claude`
 59  - `records`
 60  - `policy`
 61  - `summary`
 62- `policy.targets[]` 现已额外带:
 63  - `last_activity_at`
 64  - `last_activity_reason`
 65  - `stale_sweep_count`
 66  - `last_stale_sweep_at`
 67  - `last_stale_sweep_idle_ms`
 68  - `last_stale_sweep_reason`
 69  - `last_stale_sweep_request_id`
 70- `current_client` 已带:
 71  - `shell_runtime`
 72  - `last_action_result`
 73- merged records 已带活跃态和持久化态合并视图。
 74- 证据:
 75  - `../apps/conductor-daemon/src/local-api.ts:2747-2825`
 76  - `../apps/conductor-daemon/src/browser-types.ts:103-150`
 77  - `../apps/conductor-daemon/src/index.test.js:1840-1858`
 78  - `../tests/browser/browser-control-e2e-smoke.test.mjs:387-404`
 79
 80### 3. 通用 browser request/cancel/SSE 主链路已落地
 81
 82- `POST /v1/browser/request` 已正式支持:
 83  - Claude:prompt shortcut + raw path 的 buffered / SSE
 84  - ChatGPT:显式 `path` 的 raw buffered / SSE
 85- SSE 事件类型已经明确实现为:
 86  - `stream_open`
 87  - `stream_event`
 88  - `stream_end`
 89  - `stream_error`
 90- `POST /v1/browser/request/cancel` 已接通 Claude / ChatGPT 的取消链路。
 91- 证据:
 92  - `../apps/conductor-daemon/src/local-api.ts:4717-4789`
 93  - `../apps/conductor-daemon/src/local-api.ts:4792-4875`
 94  - `../apps/conductor-daemon/src/firefox-bridge.ts:701-739`
 95  - `../apps/conductor-daemon/src/firefox-bridge.ts:792-917`
 96  - `../tests/browser/browser-control-e2e-smoke.test.mjs:513-645`
 97  - `../apps/conductor-daemon/src/index.test.js:1894-1955`
 98
 99### 11. ChatGPT browser relay 已收口到正式合同
100
101- `platform=chatgpt``/v1/browser/request` 已补上正式合同说明和自动化验证。
102- 当前正式支持面是:
103  - buffered
104  - SSE
105  - cancel
106- 当前不支持的是 Claude 风格的 prompt shortcut;ChatGPT 仍要求显式 `path`,并依赖浏览器里已捕获的有效登录态 / header。
107- 证据:
108  - `../apps/conductor-daemon/src/local-api.ts`
109  - `../apps/conductor-daemon/src/index.test.js`
110  - `../tests/browser/browser-control-e2e-smoke.test.mjs`
111  - `../docs/api/README.md`
112  - `../docs/api/business-interfaces.md`
113
114### 12. `browser.final_message` raw relay 已接入 ChatGPT / Gemini
115
116- Firefox 插件当前会在最终 assistant message 完成后发出统一 `browser.final_message`117- `conductor-daemon` 当前会最小兼容接收这类消息,并把最近快照挂到 `GET /v1/browser -> current_client.final_messages[]`118- ChatGPT / Gemini 都已有 automated smoke:
119  - ChatGPT:等待 stream 完成后再上报,并抑制重复
120  - Gemini:只在最终文本拼接完成后上报,并保留 synthetic `assistant_message_id` 兜底
121- 证据:
122  - `../plugins/baa-firefox/final-message.js`
123  - `../plugins/baa-firefox/controller.js`
124  - `../apps/conductor-daemon/src/firefox-ws.ts`
125  - `../apps/conductor-daemon/src/browser-types.ts`
126  - `../tests/browser/browser-control-e2e-smoke.test.mjs`
127
128### 13. BAA instruction center Phase 1 已落地
129
130- `apps/conductor-daemon/src/instructions/` 已新增:
131  - `extract.ts`
132  - `parse.ts`
133  - `normalize.ts`
134  - `dedupe.ts`
135  - `policy.ts`
136  - `router.ts`
137  - `executor.ts`
138  - `loop.ts`
139- 当前已通过 synthetic assistant message 跑通:
140  - `extract -> parse -> normalize -> dedupe -> policy -> route -> execute`
141- 当前最小工具集已覆盖:
142  - `@conductor::describe`
143  - `@conductor::status`
144  - `@conductor::exec`
145  - `@conductor::files/read`
146  - `@conductor::files/write`
147- 证据:
148  - `../apps/conductor-daemon/src/instructions/`
149  - `../apps/conductor-daemon/src/index.ts`
150  - `../apps/conductor-daemon/src/index.test.js`
151
152### 14. live `browser.final_message` 已接入 instruction center
153
154- `conductor-daemon` 当前会在收到 `browser.final_message` 后直接进入 live instruction ingest。
155- 当前读面已暴露:
156  - Firefox WS `state_snapshot.snapshot.browser.instruction_ingest`
157  - `GET /v1/browser -> data.instruction_ingest`
158- 自动化已覆盖:
159  - 普通消息忽略
160  - replay 去重
161  - 缺少 `conversation_id` 可容忍
162  - live final message 触发执行并暴露最近摘要
163- 证据:
164  - `../apps/conductor-daemon/src/instructions/ingest.ts`
165  - `../apps/conductor-daemon/src/firefox-ws.ts`
166  - `../apps/conductor-daemon/src/local-api.ts`
167  - `../apps/conductor-daemon/src/index.test.js`
168
169### 15. service-side artifact center core 已落地
170
171- `apps/conductor-daemon/src/artifacts/` 当前已新增:
172  - `types.ts`
173  - `materialize.ts`
174  - `manifest.ts`
175  - `delivery-plan.ts`
176- synthetic execution result 已覆盖:
177  - `exec` -> artifact + manifest + delivery plan
178  - `files/read` small / large 的不同 delivery 策略
179  - 多结果稳定排序
180  - 缺少可选字段不崩整批 materialize
181- 证据:
182  - `../apps/conductor-daemon/src/artifacts/`
183  - `../apps/conductor-daemon/src/artifacts.test.js`
184  - `../apps/conductor-daemon/src/index.test.js`
185
186### 4. 浏览器风控策略已在 `conductor-daemon` 内实现
187
188- 默认策略已实装,不只是文档约定:
189  - 抖动
190  - 平台限流
191  -`client/platform` 并发
192  - 失败退避
193  - 熔断
194  - stale `inFlight` 后台清扫
195  - stream open/idle timeout
196  - stream buffer 上限
197- 策略运行态现在按 lease 级别追踪最近活跃时间;SSE 事件和关键代理阶段会 `touch` 活跃时间,后台按 idle 阈值定期 sweep 明显异常卡死的 slot。
198- 证据:
199  - `../apps/conductor-daemon/src/browser-request-policy.ts:11-145`
200  - `../apps/conductor-daemon/src/local-api.ts:2810-2825`
201
202### 5. 登录态元数据持久化已经落地,而且不暴露原始凭证
203
204- 当前代码会持久化:
205  - `account`
206  - `credential_fingerprint`
207  - endpoint metadata
208  - freshness / status
209- 当前代码不会把原始 `cookie` / header 值暴露到 `GET /v1/browser`210- 断连和重启后,持久化记录仍可读。
211- 证据:
212  - `../apps/conductor-daemon/src/firefox-ws.ts:1330-1365`
213  - `../apps/conductor-daemon/src/index.test.js:3434-3560`
214  - `../tests/browser/browser-control-e2e-smoke.test.mjs:833-977`
215
216### 6. 浏览器登录态 aging 已落地
217
218- 浏览器登录态会从 `fresh -> stale -> lost` 演进。
219- 这部分不只在文档里,自动化测试已覆盖。
220- 证据:
221  - `../apps/conductor-daemon/src/index.test.js:3575-3650`
222  - `../tests/browser/browser-control-e2e-smoke.test.mjs:996-1076`
223
224### 7. 结构化 `action_result` 和 `shell_runtime` 已接入主线
225
226- 插件侧已经回传结构化 `action_result`227  - `accepted`
228  - `completed`
229  - `failed`
230  - `reason`
231  - `target`
232  - `result`
233  - `results`
234  - `shell_runtime`
235- `conductor-daemon` 已消费并挂到:
236  - `current_client.last_action_result`
237  - `current_client.shell_runtime`
238  - `records[].live.shell_runtime`
239- 证据:
240  - `../plugins/baa-firefox/controller.js:3218-3284`
241  - `../apps/conductor-daemon/src/firefox-ws.ts:1268-1328`
242  - `../apps/conductor-daemon/src/local-api.ts:4328-4375`
243  - `../apps/conductor-daemon/src/index.test.js:1849-1877`
244  - `../tests/browser/browser-control-e2e-smoke.test.mjs:428-512`
245
246### 8. Firefox 插件空壳页模型和启动恢复逻辑已存在
247
248- 插件管理动作已支持:
249  - `plugin_status`
250  - `ws_reconnect`
251  - `controller_reload`
252  - `tab_open`
253  - `tab_focus`
254  - `tab_reload`
255  - `tab_restore`
256- `desired / actual / drift` 模型已在插件侧维护。
257- `2026-03-27` 的代码跟进已经补上:
258  - 启动时自动恢复缺失的 desired shell tabs
259  - 识别平台根页并纳入受管理 shell 集合
260- 证据:
261  - `../plugins/baa-firefox/controller.js:3053-3100`
262  - `../plugins/baa-firefox/controller.js:3120-3146`
263  - `../plugins/baa-firefox/controller.js:3366-3455`
264  - `../plugins/baa-firefox/controller.js:4401-4425`
265
266### 9. 自动化和运维入口已具备
267
268- 根脚本已经提供:
269  - `pnpm test`
270  - `pnpm smoke`
271  - `pnpm verify:mini`
272- `verify-mini.sh` 当前是正式 on-node 静态 + 运行态检查入口。
273- 证据:
274  - `../package.json:5-13`
275  - `../scripts/runtime/verify-mini.sh`
276
277### 10. `BUG-011`、`BUG-012`、`BUG-013`、`BUG-014`、`BUG-017` 已在当前代码中修复
278
279- `BUG-011`
280  - `../apps/conductor-daemon/src/index.ts` 已新增 `awaitWritableDrainOrClose(...)`
281  - `../apps/conductor-daemon/src/index.test.js` 已覆盖 body close、stream close、drain 后继续写入
282- `BUG-012`
283  - `../apps/conductor-daemon/src/browser-request-policy.ts` 已增加 waiter timeout、队列清理、lease 活跃时间追踪和 stale `inFlight` 后台清扫
284  - `../apps/conductor-daemon/src/local-api.ts` 已把关键 browser request 阶段与 SSE 事件接到 `lease.touch(...)`,并把 stale sweep 诊断字段暴露到 `GET /v1/browser`
285  - `../apps/conductor-daemon/src/index.test.js` 已覆盖 target slot timeout、platform admission timeout、stale sweep 恢复 waiter、健康请求不误回收和 `/v1/browser` 读面诊断字段
286- `BUG-014`
287  - `../plugins/baa-firefox/controller.js``ws_reconnect` 已改为 deferred 结果
288  - `../tests/browser/browser-control-e2e-smoke.test.mjs` 已覆盖 `ws_reconnect.completed === false`
289- `BUG-013`
290  - `../apps/conductor-daemon/src/firefox-bridge.ts` 当前关闭路径已统一调用 `clearTimers()`
291  - `../apps/conductor-daemon/src/index.test.js` 已覆盖 stream 结束后继续推进 timer 也不会再触发 timeout / cancel
292- `BUG-017`
293  - `../apps/conductor-daemon/src/local-api.ts` 已把 buffered 模式收到的 SSE 原始文本解析成结构化对象
294  - `../apps/conductor-daemon/src/index.test.js` 已覆盖 buffered SSE 返回 `content_type` / `events` / `full_text`
295
296## 当前未完成 / 待复核
297
298### 1. 真实 Firefox 手工 smoke 已完成
299
300- `2026-03-27` 已在真实 `Firefox.app` 上完成“手动关 tab -> `tab_restore` -> WS 重连 -> 状态恢复”和“扩展重载后自动恢复”验收。
301- `plugin_status`、`tab_open`、`tab_restore`、`ws_reconnect` 与扩展重载自动恢复都已通过;当前不再把“真机浏览器管理闭环未验证”列为残余风险。
302
303### 2. open bug backlog 未清空
304
305- 当前不能把“已修复 bug”误写成“所有残余风险都已消失”。
306- open bug backlog 见 `../bugs/README.md`;截至本次核对仍保留 `BUG-018`、`BUG-019`、`BUG-020`。
307
308### 3. Gemini 已接入最终消息 raw relay,但提取仍是启发式
309
310- Gemini 当前已能通过 `browser.final_message` 上报最终 assistant message。
311- 但它的最终文本提取基于 `StreamGenerate` / `batchexecute` 风格 payload 的启发式解析,稳定性弱于 ChatGPT。
312- 当前保留 synthetic `assistant_message_id` 兜底,因此这层应表述为“已接通 raw relay,但平台提取稳定性仍有边界”,不是“Gemini 整个平台能力都已转正”。
313
314### 4. live message dedupe 和 instruction dedupe 已持久化,但仍只做单节点本地恢复
315
316- `browser.final_message` 当前已经 live 接入 instruction center,live message dedupe 和 instruction dedupe 也都已落到本地 control-plane sqlite。
317- 因此进程重启后,这两类 dedupe 状态会保留。
318- 当前残余边界不是“会丢失”,而是“只做单节点本地持久化,不做跨节点共享”。
319
320### 5. 风控状态仍是进程内内存态
321
322- 默认策略本身已实现。
323- 但策略运行态计数并未持久化,进程重启后限流 / 退避 / 熔断状态会重置。
324
325### 6. stale `inFlight` 自愈已落地,但仍保留极长静默请求误判风险
326
327- 当前代码已经能在后台定期 sweep 明显 stale 的 lease,并让同一 `target` 的 waiter 继续推进。
328- 这轮为避免误杀,默认只在 `5min` 无活跃更新后才回收 slot,并依赖 `lease.touch(...)` 标记关键活跃点。
329- 如果未来出现“健康但长时间完全静默”的超长 buffered 请求,理论上仍存在被保守阈值误判的风险;当前文档里应把它写成残余边界,而不是“完全没有自愈”。
330
331### 7. `ws_reconnect` 自动化与真机验收都已覆盖,但完成判定仍依赖后续状态同步
332
333- 当前 smoke 既覆盖 conductor 侧 `action_result` 语义透传,也已在真实 Firefox 扩展运行环境里完成手工 reconnect 验收。
334- `ws_reconnect` 的设计仍是“HTTP 立即返回 `completed=false`,真正恢复靠后续 `hello` / 状态同步体现”;这属于当前合同语义,不再是未验收风险。
335- 这轮额外补做了 `disconnect_ms=3000`、`repeat_count=3`、`repeat_interval_ms=500` 的 3 轮断开重连稳定性验证。
336
337### 8. ChatGPT 已转正,但仍保留平台前提边界
338
339- ChatGPT 现在已正式接入 `/v1/browser/request` 的显式 `path` buffered / SSE / cancel。
340- 但它仍依赖浏览器里真实捕获到的有效登录态 / header,不是“无前提可用”的平台。
341- 另外,ChatGPT 也没有 Claude 风格的 prompt shortcut;当前正式支持面仍是 raw relay,不是 prompt helper。
342
343### 9. 当前摘要已落到 bounded journal,live 路径也已接到 delivery bridge,但仍只覆盖 Phase 1 exact target
344
345- 当前 live ingest / execute 摘要已经落到有界 journal,并能在重启后恢复到:
346  - Firefox WS `state_snapshot.snapshot.browser.instruction_ingest`
347  - `GET /v1/browser``data.instruction_ingest`
348- 当前 journal 只保留最近窗口,不扩成无限历史。
349- 插件侧 upload / inject / send 仍是 DOM heuristic,当前只对 `Claude` / `ChatGPT` 做了首版选择器与流程。
350- artifact payload 当前通过本地 `download_url` 以 base64 JSON 形式提供,适合当前 text/json 类产物;大二进制和 download 闭环还没做。
351- 当前交付仍按任务边界停留在单客户端、单轮 delivery 首版。
352- 当前仍只允许 Phase 1 精确 target:
353  - `conductor`
354  - `system`
355- 当前 live 路径已经把执行结果接到 artifact / upload / inject / send,但不扩到跨节点或完整 task/run 编排。
356
357## 已拆出的后续任务
358
359- `T-S035`:加固插件侧 delivery adapter 与页面交付流程
360- `T-S036`:补 artifact download 合同与 binary delivery 能力
361
362## 下一波任务
363
364- `T-S035` 负责把 `Claude` / `ChatGPT` 的插件侧 `upload / inject / send` 从首版 DOM heuristic 收口成更稳定的 adapter 和 fail-closed 路径。
365- `T-S036` 负责把当前本地 `download_url` + base64 JSON 的 artifact payload 合同升级到更适合 binary-safe delivery 的形式,同时保持现有 text/json 兼容。
366
367## 建议给 Claude 重点复核的点
368
3691. 复核 `../apps/conductor-daemon/src/index.ts``../apps/conductor-daemon/src/index.test.js`
370   - 目标:确认 `BUG-011` 的 body / stream 背压断连修复和测试范围准确
3712. 复核 `../apps/conductor-daemon/src/browser-request-policy.ts``../apps/conductor-daemon/src/index.test.js`
372   - 目标:确认 `BUG-012` 的 timeout / cleanup / stale sweep 都已落地,且健康长请求的误判风险描述准确
3733. 复核 `../plugins/baa-firefox/controller.js``../tests/browser/browser-control-e2e-smoke.test.mjs`
374   - 目标:确认 `BUG-014` 的 deferred 结果语义已落地,且当前自动化验证只覆盖 conductor 侧语义透传
3754. 复核 `../apps/conductor-daemon/src/local-api.ts`
376   - 目标:确认当前正式 browser 读写面和 action_result / stream / cancel 的外部合同描述仍准确
3775. 复核 `../apps/conductor-daemon/src/browser-request-policy.ts:117-145`
378   - 目标:确认默认风控参数已经实装,而不是仅在文档里声明
379
380## 适合对外同步的简版结论
381
382如果只写一段给外部协作者看,可以用下面这版:
383
384> 当前代码已经完成单节点 `mini` 主接口收口,以及 Firefox 本地 bridge 下的 Claude / ChatGPT request relay 主链路、ChatGPT / Gemini 最终消息 raw relay、conductor 侧 live instruction ingest、dedupe / execution journal 本地持久化,以及 artifact / upload / inject / send 主链。`GET /v1/browser`、`POST /v1/browser/actions`、`POST /v1/browser/request`、`POST /v1/browser/request/cancel`、正式 SSE、结构化 `action_result`、`shell_runtime`、登录态元数据持久化、`browser.final_message` 最近快照、`instruction_ingest` 最近摘要、upload receipt barrier,以及 `BUG-012` 的 stale `inFlight` 自愈清扫都已落地;`BUG-011`、`BUG-012`、`BUG-013`、`BUG-014`、`BUG-017` 也已在当前代码中修复,并已通过 `conductor-daemon build`、`index.test.js`(45/45)、browser-control e2e smoke(8/8)和 `2026-03-27` 的真实 Firefox 手工 smoke。当前剩余缺口主要是:ChatGPT / Gemini 最终消息提取仍有平台边界、插件侧 upload / inject / send 仍是首版 DOM heuristic、artifact payload 仍以本地 `download_url` 的 base64 JSON 形式提供且未覆盖大二进制 / download 闭环、BAA 仍只做单节点本地持久化、execution journal 只保留最近窗口,以及 live 执行路径仍只覆盖 Phase 1 exact target。