refactor(repo): workspace 谓词抽成共享构造器 + 删一个死函数
用户 2026-09-26:「审查一下服务端,我觉得现在还是有大量不符合设计的地方与冗余代码」。
# 先说审查结论:**"大量冗余"核不出来**
| 检查项 | 读数 |
| --- | --- |
| 99 个 handler | **全部注册,零死路由** |
| 死函数 | 2 个(本次删 1,另 1 个被测试用、保留) |
| 注释占比 | 23%(这个仓每个非显然决定都记"为什么",是有意的) |
| 测试 | 13644 行 = 源的 41% |
# 但找到一处真问题:`workspace` 谓词手抄了三遍
同一件事在三处各写一遍:
args := []any{agentName}
if strings.TrimSpace(workspace) != "" {
args = append(args, workspace)
q += fmt.Sprintf(` AND s.workspace = $%d`, len(args))
}
★ 代价不是"多几行",是**加参数要改三处、漏一处不会编译报错**。
本次给三个函数加 workspace 参数(`ListInboxScoped`/`CountUnreadScoped`/
`MarkAllInboxReadForSession`)就是手抄了三遍。
同仓有同类先例:`quota.go` 里那条 `★★★ 判据自检` 记的
「占位符编号错位导致静默少行」—— 根因完全一样(同一个模板抄多处,
靠人肉保持一致)。
⇒ 抽 `workspaceScope(q, args, workspace) (string, []any)`,三处各变成一行。
# 为什么"必需"这条不在 repo 层
`checkWorkspace` **允许空**:空 = 不过滤 = 人类侧(一个人跨工作区,WebUI
按 session_workspace 分组显示)。"Agent 侧必须带"是**接口契约**,放在 Handler。
抽出来的函数注释里把这层分工写死了,免得后来者以为 repo 层该拒绝空值。
# 与 `FindOrCreateDefaultSession` 里那套**故意不共用**
那里要的是「工作区为空时从 mails 反推」(历史会话兼容),语义更宽。
合并前要先确认那是不是想要的行为 —— 现在保持分开。
# 删 `SessionMailCount`
全仓零调用(连测试都没有)。`GetSessionMailByID` 也只被两个测试用,
但它是那两个测试的被测对象,**不删**(测试专用包装与死代码不是一回事)。
# 验证
· 变异:把 `workspaceScope` 改成永远不过滤 ⇒
`TestInboxListIsScopedByWorkspace` + `TestMarkAllReadIsScopedByWorkspace` 判红
· 12 个包通过;`internal/repo` 唯一的 FAIL
(`TestReplacePlatformSessionsKeepsOtherWorkspaces`)**改动前就红** ——
已用 `git stash` 式回退验证,它是 `DEBTS.json` 里记的 platform_sessions
PK 缺陷那条判据,与本次无关。
# 顺带记一笔(对我自己的)
本机 `go` 是 1.24.4 而 `go.mod` 要求 1.25.0,**`go build` 会去下载 toolchain
并因离线失败**(exit=1)。我前面几轮用 `go build ./... | head -5 && echo "编译 ok"`
判断,把 `head` 的 exit 0 当成了编译成功 —— **那是假的**。本轮才发现,
改用本地已有的 `toolchain@v0.0.1-go1.26.7` 才拿到可信结果。
⇒ 判据里凡用 `cmd | head && echo ok` 的形状,退出码被管道最后一道吞掉,
之后一律用 `cmd >/dev/null 2>&1; echo $?` 或显式检查 `${PIPESTATUS[0]}`。