- commit
- 6a3d654
- parent
- 9bad42f
- author
- im_wower
- date
- 2026-03-29 20:52:33 +0800 CST
docs: add BUG-026 and BUG-027 reports
3 files changed,
+221,
-0
1@@ -0,0 +1,110 @@
2+# BUG-026: `/artifact/repo/:repo_name` 根路径不会落到默认 `log.html`
3+
4+> 提交者:代码核对 + 公网实测
5+> 日期:2026-03-29
6+
7+## 现象
8+
9+当前 stagit 仓库静态页的显式文件路径可正常访问,但 repo 根路径不会按设计落到默认 `log.html`:
10+
11+- `GET /artifact/repo/baa-conductor/log.html` 返回 `200 text/html`
12+- `GET /artifact/repo/baa-conductor` 返回 `404 application/json`
13+
14+这意味着用户或 AI 只拿到 repo 根 URL 时,不能直接进入仓库首页,必须显式补上 `/log.html`。
15+
16+## 触发路径
17+
18+```text
19+GET /artifact/repo/:repo_name
20+-> route matcher 先命中 /artifact/:artifact_scope/:artifact_file
21+-> 走通用 artifact read
22+-> 读取 artifacts/repo/:repo_name 普通文件
23+-> 文件不存在
24+-> 404
25+```
26+
27+而不是:
28+
29+```text
30+GET /artifact/repo/:repo_name
31+-> 命中 /artifact/repo/:repo_name/*
32+-> repo handler 把空 wildcard fallback 为 log.html
33+-> 返回 stagit 首页
34+```
35+
36+## 根因
37+
38+根因已经明确:
39+
40+- `LOCAL_API_ROUTES` 里通用路由 `/artifact/:artifact_scope/:artifact_file` 定义在 repo 专用路由 `/artifact/repo/:repo_name/*` 之前
41+- `matchRoute()` 按声明顺序返回第一个匹配项
42+- 对三段路径 `/artifact/repo/<repo>` 来说,前者已经完全匹配,后者根本没有机会执行
43+- 因此 repo handler 中的默认值 `context.params["*"] || "log.html"` 只对 `/artifact/repo/<repo>/...` 生效,对根路径不生效
44+
45+这不是 stagit 生成问题,也不是公网部署问题,而是本地 API 路由分派顺序问题。
46+
47+## 复现步骤
48+
49+公网最小复现:
50+
51+```bash
52+curl -sS -o /dev/null -w '%{http_code} %{content_type}\n' \
53+ https://conductor.makefile.so/artifact/repo/baa-conductor/log.html
54+
55+curl -sS -o /dev/null -w '%{http_code} %{content_type}\n' \
56+ https://conductor.makefile.so/artifact/repo/baa-conductor
57+```
58+
59+2026-03-29 实测结果:
60+
61+- 第一条返回:`200 text/html; charset=utf-8`
62+- 第二条返回:`404 application/json; charset=utf-8`
63+
64+本地代码最小核对点:
65+
66+- `apps/conductor-daemon/src/local-api.ts`
67+- 通用 artifact 路由先于 repo 路由定义
68+- `matchRoute()` 采用 first-match 行为
69+- `handleArtifactRepoRead()` 里虽然实现了 `log.html` fallback,但根路径走不到这里
70+
71+## 当前影响
72+
73+- repo 静态页不是完全不可用,因为显式 `/log.html` 可正常访问
74+- 但“repo 根路径可作为稳定入口”这个语义当前不成立
75+- 任何只拼出 `/artifact/repo/<repo>` 的调用方都会得到 404
76+- 会影响 AI/脚本/人工直接把 repo 根 URL 当作首页入口的体验和可发现性
77+
78+## 修复建议
79+
80+### 方案 A(推荐)
81+
82+调整路由优先级,让 `/artifact/repo/:repo_name/*` 在通用 artifact 路由之前匹配。
83+
84+这样最直接,也与现有 fallback 设计一致。
85+
86+### 方案 B
87+
88+保留当前顺序,但让 `matchRoute()` 对“更具体的静态段更多”的路由优先。
89+
90+这更通用,但复杂度高于当前问题本身。
91+
92+### 方案 C
93+
94+单独增加一个显式根路径路由 `/artifact/repo/:repo_name`,直接映射到 `log.html`。
95+
96+可以修问题,但会让 repo 路由定义分裂成两条。
97+
98+## 严重程度
99+
100+**Medium**
101+
102+repo 静态浏览功能本身可通过显式 `/log.html` 使用,不是全量不可用;但默认首页入口失效,且与当前代码中的 fallback 意图不一致。
103+
104+## 发现时间
105+
106+`2026-03-29 by Codex`
107+
108+## 备注
109+
110+- 同一时间点公网已确认 `https://conductor.makefile.so/artifact/repo/baa-conductor/log.html` 正常
111+- 本 bug 只指向 repo 根路径 fallback 失效,不指向 stagit 内容生成失败
1@@ -0,0 +1,109 @@
2+# BUG-027: 插件启动期诊断事件会在 WS 建立前丢失,阻塞 `logs/baa-plugin` 排障链路
3+
4+> 提交者:代码核对
5+> 日期:2026-03-29
6+
7+## 现象
8+
9+当前 `logs/baa-plugin/YYYY-MM-DD.jsonl` 被设计成 Firefox 插件诊断的统一落点,但插件冷启动、插件重载或页面首次注入时,最早一批关键事件可能完全不会进入 conductor:
10+
11+- `page_bridge_ready`
12+- `interceptor_active`
13+- 其他依赖页面刚加载时立即发送的诊断事件
14+
15+结果是:
16+
17+- 插件后续若成功连上 WS,后面的诊断日志能看到
18+- 但最关键的“页面桥接是否成功注入”“page-interceptor 是否已激活”这批启动期证据会静默缺失
19+- 当当前排障路径依赖 `logs/baa-plugin/` 判断注入链路时,会出现“没有日志,不知道是没注入还是只是太早发了”的盲区
20+
21+## 触发路径
22+
23+```text
24+刷新 ChatGPT / Claude / Gemini 页面
25+-> content-script / page-interceptor 刚加载即发送 page_bridge_ready / interceptor_active
26+-> controller 这时尚未 connectWs() 或 WS 仍未 open
27+-> wsSend() 直接返回 false
28+-> 事件无重试、无排队、无本地缓冲
29+-> conductor 侧 logs/baa-plugin/ 看不到这批启动期日志
30+```
31+
32+## 根因
33+
34+根因基本确认:
35+
36+- content-script 会在加载后立即发送 `page_bridge_ready`
37+- page-interceptor 会在激活后立即发送 `interceptor_active`
38+- controller 直到初始化尾部才调用 `connectWs()`
39+- `wsSend()` 在 socket 未连接时直接返回 `false`
40+- `plugin_diagnostic_log` 没有补发、排队或本地缓存机制
41+
42+因此,所有发生在 WS 建立之前的诊断事件都会被静默丢弃。
43+
44+## 复现步骤
45+
46+这是一个很短的时序问题,最小复现依赖真实 Firefox 插件环境:
47+
48+1. 启动 conductor,确保会写 `logs/baa-plugin/`
49+2. 重载 Firefox 插件或冷启动浏览器
50+3. 刷新一个 AI 页面,例如 ChatGPT
51+4. 观察页面控制台可看到 `content_script_loaded` / `interceptor_active`
52+5. 再查看 conductor 的 `logs/baa-plugin/YYYY-MM-DD.jsonl`
53+
54+预期:
55+
56+- 应能看到 `page_bridge_ready`
57+- 应能看到 `interceptor_active`
58+
59+当前高概率实际情况:
60+
61+- 若事件发生在 WS `open` 之前,这两条日志不会出现在 `logs/baa-plugin/`
62+- 后续较晚产生的日志可能正常出现,造成“部分有日志、最早证据缺失”的假象
63+
64+## 当前影响
65+
66+- 直接影响当前依赖 `logs/baa-plugin/` 排查插件注入、桥接就绪、SSE 拦截起点的问题
67+- 当问题恰好发生在页面刚加载或插件刚重载阶段时,conductor 侧日志失去最关键证据
68+- 这不是普通信息缺失,而是会阻塞“确认 page-interceptor / content-script 是否启动成功”这条诊断路径
69+- 对正常业务请求不一定构成功能性故障,但对当前诊断主流程是阻塞性的
70+
71+## 修复建议
72+
73+### 方案 A(推荐)
74+
75+在 controller 侧为 `plugin_diagnostic_log` 增加一个很小的启动缓冲队列:
76+
77+- WS 未 open 时先暂存在内存
78+- `onopen` 后立即 flush
79+- 队列限制条数,避免无上限积累
80+
81+### 方案 B
82+
83+在 content-script/page-interceptor 侧延迟发送首批诊断事件,等 controller 与 WS 建立后再发。
84+
85+这个方案实现简单,但会把可靠性依赖到更多时序假设上。
86+
87+### 方案 C
88+
89+保留现有链路,但在 controller 与页面握手成功后主动补发一轮启动状态摘要。
90+
91+这样能补证据,但语义上不如真实事件直观。
92+
93+## 严重程度
94+
95+**High**
96+
97+这会直接阻塞当前 `logs/baa-plugin/` 诊断链路最重要的一段:页面启动与注入时序。功能本身不一定坏,但排障会失真。
98+
99+## 发现时间
100+
101+`2026-03-29 by Codex`
102+
103+## 备注
104+
105+相关代码位置:
106+
107+- 启动期事件发送:[content-script.js](/Users/george/code/baa-conductor/plugins/baa-firefox/content-script.js#L888)
108+- 启动期事件发送:[page-interceptor.js](/Users/george/code/baa-conductor/plugins/baa-firefox/page-interceptor.js#L228)
109+- WS 未连通时直接丢弃:[controller.js](/Users/george/code/baa-conductor/plugins/baa-firefox/controller.js#L4003)
110+- controller 在初始化尾部才开始连 WS:[controller.js](/Users/george/code/baa-conductor/plugins/baa-firefox/controller.js#L7322)
+2,
-0
1@@ -13,6 +13,8 @@ bugs/
2
3 ## 待修复
4
5+- `BUG-026`:[`BUG-026-artifact-repo-root-fallback-broken.md`](./BUG-026-artifact-repo-root-fallback-broken.md)
6+- `BUG-027`:[`BUG-027-startup-plugin-diagnostic-events-lost-before-ws-open.md`](./BUG-027-startup-plugin-diagnostic-events-lost-before-ws-open.md)
7 - `OPT-002`:[`OPT-002-executor-timeout.md`](./OPT-002-executor-timeout.md)
8 - `OPT-003`:[`OPT-003-policy-configurable.md`](./OPT-003-policy-configurable.md)
9 - `OPT-004`:[`OPT-004-final-message-claude-sse-fallback.md`](./OPT-004-final-message-claude-sse-fallback.md)