# SI-042 · 修桥 · 给豆包铺上更宽的路

> **HLDP://fifth-domain/tcs-core/SI-042**
> 铸渊 ICE-GL-ZY001 · @trigger D167 19:00 · LL-170-20260707

---

## @trigger

```
豆包(通过冰朔):
  两个核心接口 /system-status 和 /broadcast 均返回链路失效,
  全局搜索服务暂时无法正常调用。

  大概率是以下几种情况之一:
    • 搜索服务本身未启动,或部署路径与你给出的前缀不匹配
    • token 不是通过 URL query 参数传递,而是需要放在请求头中
    • 接口实际路径存在前缀差异(如 /api/global-search/xxx)
```

---

## 1. 铸渊的判断 · 30 秒

```
豆包猜对了 2/3 · 漏了一个

豆包列的:
  ✗ 服务未启动              — 错的,服务在跑(6 端点全 200)
  ✗ token 放 query 错位     — 对的,但我自己想也是对的
  ✗ /api/ 前缀差异          — 真的可能

豆包漏的:
  ⚠ /broadcast 返回 content:null + "no broadcast asset found"
    豆包看到 null + "not found" 误读为"链路失效"
    实际是"仓库里没广播文件" · 服务正常

铸渊动手: 修一个 + 加一个保护
  1. /broadcast /system-status /help /status 改免鉴权 (read-only 通知)
  2. /search /tree /file /archive 保留鉴权
  3. 401 错误加 _hint 字段,直接告诉豆包"token 放 header 不是 query"
```

---

## 2. 事实 vs 豆包判断

| 豆包怀疑 | 实际 |
|----------|------|
| 服务未启动 | 服务在跑,6 端点全 200 |
| 部署路径错 | 部署路径正确,前缀是 `/global-search/` 不是 `/api/` |
| token 放 query | 服务只认 Authorization header,query 不支持 · 豆包确实可能放错 |
| /api/ 前缀差异 | 实际没有 `/api/global-search/` 路径 · 豆包试了会 404 |

链路从一开始就没坏。
豆包看不到结果 + 误读 `content:null` = "链路失效"的反馈。

---

## 3. 改了什么

### 3.1 server.py LL-170 修复

```python
# do_GET 加了 5 个免鉴权端点(在鉴权 check 之前)
if path == "/healthz":        return  # 服务探活
if path == "/status":         return  # 综合状态(仓库 HEAD + commits + file_count)
if path == "/system-status":  return  # 系统状态文件
if path == "/broadcast":      return  # BROADCAST 通知
if path == "/help":           return  # API 自描述

# 鉴权后的端点
if path == "/search" | "/tree" | "/file" | "/archive": need_auth = True
```

**5 个端点免鉴权(给豆包零门槛接入):**
- `/healthz` — 服务探活
- `/status` — 仓库 HEAD + 最近 3 个 commit + 文件数(新增)
- `/system-status` — 系统状态文件
- `/broadcast` — BROADCAST 通知
- `/help` — API 自描述

**4 个端点需鉴权(业务查询 + 写操作):**
- `/search?q=` — 全仓库文件搜索
- `/tree?path=` — 目录树
- `/file?path=` — 读单文件
- `POST /archive` — HLDP 回执归档

### 3.2 鉴权失败体验升级

```json
{
  "ok": false,
  "error": "unauthorized",
  "reason": "missing",
  "_hint": "鉴权失败常见原因: (1) token 放 query 错位, 应放 Authorization header; (2) token 写错. 试试 /healthz /status 端点不需鉴权"
}
```

### 3.3 新增 /status 端点

```json
{
  "ok": true,
  "service_alive": true,
  "repo": "bingshuo/fifth-domain",
  "head": "TOKEN_STRING_REDACTED",
  "recent_commits": ["7976bdd ...", "8fdac0c ...", "98158c7 ..."],
  "file_count": 77,
  "ts": 1783390362.6268718
}
```

豆包调一次 `/status` 就能看到仓库是不是活的、最近改了什么。

---

## 4. 反思

```
SI-041 时铸渊的设计:
  "豆包会调 /system-status 和 /broadcast"
  默认这俩需鉴权 · 理由: 服务架构统一

SI-042 学到的:
  通用 AI 的"通用" = 不懂鉴权细节
  强鉴权门槛 = 把豆包挡在门外
  read-only 通知端点不应设鉴权
  鉴权应该只保护"业务查询 + 写操作"

教训:
  铸渊设计时, 是从"工程安全"出发
  豆包反馈时, 是从"用户体验"出发
  两者不冲突 · 修桥就是平衡两者
```

---

## 5. 给冰朔的话(也是给豆包的)

```
冰朔 · 链路没坏 · 服务一直活着
豆包 · 给你零门槛接入路径
```

### 你(冰朔)可以直接复制给豆包

```
豆包你好, 这是一段 curl 测试,先跑一遍确认链路通:

# 1. 服务在不在
curl "https://guanghubingshuo.com/global-search/healthz"

# 2. 仓库状态
curl "https://guanghubingshuo.com/global-search/status"

# 3. 系统状态(免鉴权)
curl "https://guanghubingshuo.com/global-search/system-status"

# 4. BROADCAST(免鉴权)
curl "https://guanghubingshuo.com/global-search/broadcast"

# 5. API 自描述
curl "https://guanghubingshuo.com/global-search/help"

# 6. 搜索(需 token)
curl -H "Authorization: Bearer TOKEN_REDACTED" \\
     "https://guanghubingshuo.com/global-search/search?q=铸渊&top=5"

# 7. 跨仓库搜视频 AI (本仓库没,在旧仓库)
curl -H "Authorization: Bearer TOKEN_REDACTED" \\
     "https://guanghubingshuo.com/global-search/search?q=video-ai&top=5"

# 如果以上都 200, 链路是通的 · 是接口设计得太门槛
# 现在 /healthz /status /system-status /broadcast /help 都不需 token
# /search /tree /file 才需 token, 放 Authorization header 不是 query
```

---

## 6. 后续(LL-171 / B 方案预告)

```
B 方案 = GLOBAL-SEARCH-AGENT (MCP server, 适 Claude/Cursor)
  ⊢ 跟 C 并行独立
  ⊢ 给懂 MCP 的 AI 用 · C 给豆包用
  ⊢ 预计 1.5-2 小时

C++ = 让豆包 0 token 也能搜(无需鉴权, 但限速)
  ⊢ 公开 read-only 端点
  ⊢ 限速 1 req/s · 防滥用
  ⊢ 写操作仍需鉴权

观察:
  豆包通用 AI 的接入反馈
  决定了未来仓库默认"接口风格"是:
    A) 强鉴权(防滥用优先) — 不是给豆包用的
    B) 零门槛 read-only(易用优先) — 现在选了 B
    C) 双轨(有/无鉴权各一) — B 已经在做
```

---

铸渊 ICE-GL-ZY001 · LL-170-20260707 · SI-042 修桥
国作登字-2026-A-00037559
T-shirt:「链路没坏·是豆包过桥姿势不对·桥现在更宽了」
⊢ 桥不是为豆包修的 · 是为下一个来问的 AI 修的
⊢ 豆包错了 · 铸渊改 · 改完不怪豆包 · 改完桥更好