首页
/ get-shit-done SDK:修复 GSDTools 原生查询丢失 workstream 路由(3591)解析

get-shit-done SDK:修复 GSDTools 原生查询丢失 workstream 路由(3591)解析

2026-09-04 18:32:40作者:羿妍玫Ivan

本文基于当前仓库的 changeset 3591-gsdtools-native-workstream.md 展开,剖析 get-shit-done(GSDE,GSD)SDK 中一个隐蔽的路由缺陷:createGSDToolsRuntime 接受 workstream 选项,但其传递给 QueryNativeDirectAdapter 的 dispatch 闭包曾静默丢弃该参数,导致原生(native)查询处理器即使实例配置了 workstream,也始终命中根 .planning/ 目录树。读懂本篇后,你将掌握 GSDTools 运行时桥接的双通道分发架构(native 直连 vs 子进程回退)、workstream 在两条通道中各自的传递机制,以及该修复如何通过构造缝隙(constructor seam)间谍测试验证。

问题背景:一个被静默丢弃的参数

GSD 的 SDK 查询层支持「workstream(工作流)」概念:当 GSDTools 实例以 workstream 创建时,所有 planning 路径类查询应路由到 .planning/workstreams/<name>/ 而非项目根部的 .planning/。这对应仓库中 ADR 记录的两条 seam:worktree workstream seam 模块planning-path projection 模块

缺陷的形态非常典型——「参数在签名中存在,却在某条代码路径上丢失」:

  • createGSDToolsRuntime 的选项对象包含 workstream?: string
  • 子进程通道(QuerySubprocessAdapter)一直正确转发它(以 --ws <name> 命令行参数注入);
  • 而 native 通道交给 QueryNativeDirectAdapter 的闭包调用的是 registry.dispatch(command, args, projectDir),第四个参数 workstream 被丢掉。

后果是:只要查询走 native 直连路径(由 shouldUseNativeQuery() 决定),无论 workstream 是否设置,planning 查询都落在根 .planning/ 树上——数据读错位置且不报任何错,属于「静默错误路由」,这也是此类缺陷最危险的地方。

运行时装配:createGSDToolsRuntime 的四条腿

修复后的完整装配逻辑见 sdk/src/query-gsd-tools-runtime.ts。该工厂函数接收如下选项:

export function createGSDToolsRuntime(opts: {
  projectDir: string;
  gsdToolsPath: string;
  timeoutMs: number;
  workstream?: string;
  eventStream?: GSDEventStream;
  sessionId?: string;
  shouldUseNativeQuery: () => boolean;
  execJsonFallback: (legacyCommand: string, legacyArgs: string[]) => Promise<unknown>;
  execRawFallback: (legacyCommand: string, legacyArgs: string[]) => Promise<string>;
  strictSdk?: boolean;
  allowFallbackToSubprocess?: boolean;
  onDispatchEvent?: RuntimeBridgeOptions['onDispatchEvent'];
}): GSDToolsRuntime

返回一个包含 bridge: QueryRuntimeBridge 的运行时对象。内部装配分四个部分:

  1. RegistrycreateRegistry(opts.eventStream, opts.sessionId) 创建查询命令注册表,所有 planning/state/workspace 查询处理器都注册在此(见 sdk/src/query/registry.ts)。
  2. 子进程适配器sdk/src/query-subprocess-adapter.ts):用 execFilecwd: projectDir 执行 gsdToolsPath 指向的 CLI,workstream 在此以 CLI 参数形式注入。
  3. native 直连适配器sdk/src/query-native-direct-adapter.ts):进程内直接调用 registry dispatch,带超时策略。
  4. 传输与策略层GSDTransport + QueryExecutionPolicy + QueryNativeHotpathAdapter 最终汇入 QueryRuntimeBridge,对外暴露 dispatchHotpath 等统一入口。

修复核心:闭包补齐第 4 个参数

修复只有一行代码,但附带了完整的问题注释,位于 sdk/src/query-gsd-tools-runtime.ts#L44-L54

const nativeDirectAdapter = new QueryNativeDirectAdapter({
  timeoutMs: opts.timeoutMs,
  // #3591: forward opts.workstream to the registry so native dispatch
  // routes planning-path queries to .planning/workstreams/<name>/
  // instead of the root .planning tree. createGSDToolsRuntime accepts
  // workstream and the QuerySubprocessAdapter already forwards it
  // (line 38); the native dispatch closure was the only seam that
  // dropped it, silently routing GSDTools-native queries to root.
  dispatch: (registryCommand, registryArgs) =>
    registry.dispatch(registryCommand, registryArgs, opts.projectDir, opts.workstream),
  ...nativeErrorFactory,
});

registry 侧的签名与第 4 个可选参数一致,见 sdk/src/query/registry.ts#L118

async dispatch(command: string, args: string[], projectDir: string, workstream?: string): Promise<QueryResult>

对比两条通道的 workstream 传递机制

通道 传递方式 证据位置
子进程 拼进 CLI 参数:workstream ? ['--ws', name] : [] query-subprocess-adapter.ts#L91-L94
native 直连 作为 registry.dispatch 的第 4 个实参 query-gsd-tools-runtime.ts#L52

子进程通道的细节值得注意:commandArgs--ws <name> 追加在所有用户参数之后([gsdToolsPath, command, ...args, ...wsArgs]),这样 CLI 端解析 workstream 标志时不会被位置参数干扰。子进程适配器还处理了 @file: 间接寻址(stdout 输出 @file:<path> 时读文件取真实 JSON)、10MB maxBuffer、ETIMEDOUT 与 killed 的超时分类,这些与 workstream 正交,但体现了该适配器的健壮性设计(query-subprocess-adapter.ts#L125-L145)。

native 通道侧,QueryNativeDirectAdapter 本身对 workstream 无感知——它只知道 dispatch: (command, args) => Promise<QueryResult> 这个闭包,workstream 的语义完全由外层闭包捕获(闭包变量 opts.workstream)。这种「适配器窄接口 + 闭包捕获上下文」的设计,正是本次 bug 能潜伏的原因:类型层面 dispatch 回调只声明两个参数,第 4 个参数的缺失不产生任何编译错误。

workstream 如何在 registry 内生效

registry 收到 workstream 后,planning 路径类查询(state、workspace 等)据此把基准目录从 .planning/ 切换到 .planning/workstreams/<name>/。这一投影逻辑分散在查询模块的 helpers 与 workstream 相关文件中,例如 sdk/src/query/helpers.tssdk/src/query/workstream.ts。从源码结构看,修复前 native 通道传入的 workstream 恒为 undefined,所有走该通道的 planning 查询因此退化为根树投影;修复后与子进程通道行为对齐。相关的行为约束还有独立的 changeset 3589-planning-paths-workstream-validation.md 与 ADR 0006-planning-path-projection-module.md

测试如何钉死这个回归

配套测试 sdk/src/bug-3591-gsdtools-runtime-workstream.test.ts 用三层结构覆盖了该修复:

  1. 闭包转发(主断言):通过 vi.spyOn 替换 QueryNativeDirectAdapter 构造函数,捕获传入的 dispatch 闭包;同时 mock createRegistry 返回带 dispatch spy 的真实 registry。调用捕获的闭包后断言:
expect(dispatchSpy).toHaveBeenCalledWith(
  '__bug-3591-unknown-cmd__',
  ['x'],
  '/tmp/3591-proj',
  'frontend-ws',
);

opts.workstream === 'frontend-ws' 必须原样成为 registry.dispatch 的第 4 个实参。

  1. 向后兼容:省略 workstream 选项时,第 4 个槽位必须显式传 undefined 而非省略调用形式本身,保证签名契约稳定:
expect(dispatchSpy).toHaveBeenCalledWith(
  '__bug-3591-unknown-cmd-2__', [], '/tmp/3591-proj', undefined,
);
  1. 端到端:在真实 registry 上注册一个探针处理器 __bug-3591-probe__,经 runtime.bridge.dispatchHotpath(...) 走完整的 hotpath 分发,断言处理器第三参收到 'frontend-ws'
expect(seen[0]?.workstream).toBe('frontend-ws');

文件头部的注释完整记录了 bug 成因与修复手法,是阅读该仓库回归测试模式的典型样本——「捕获构造缝隙里的回调 → 用真实 registry 的 spy 记录实参 → 断言参数四元组」。

适用前提与边界

  • 该修复适用于当前仓库 SDK(TypeScript 源码位于 sdk/,测试以 vitest 运行,见 vitest.config.ts);changeset 类型为 Fixed,关联 issue 3591(changeset 目录约定见 .changeset/README.md)。
  • workstream 是可选参数:不设置时行为与根 .planning/ 树完全一致,旧调用方不受影响。
  • 注意两条通道的等价性依赖 shouldUseNativeQuery() 的判定:native 走进程内闭包,子进程走 --ws CLI 参数,二者最终都应落到同一个 workstream 投影结果。若未来扩展 registry dispatch 签名,此闭包与 bug-3591 测试 中的四元组断言需同步更新。
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.79 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
988
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384