Skip to content

[BUG] DSH 0.2.1:hide-official 的组装校验仍假设载荷带 tools,启用该行后每个作用域都被 READINESS_BLOCKED 拦下 #413

Closed

Description

@WeiLinCool

环境

现象

dsh-ops-ptc 那条崩溃(#387 / #412)修好之后,只要同时启用 hide-official,每一次带 scope 的 prompt 组装都会被拦下:

READINESS_BLOCKED (EXECUTOR_UNAVAILABLE): dsh-ops hide-official cannot verify selected replacements:
assembled tool schemas unavailable. Restore the selected OPS tools, remove the selection from
replaceTools, or disable the dsh-ops-hide-official row.

不是某个工具不可用,是所有回合都起不来。

根因

src/official-tool-hiding.ts 的组装校验仍然假设瀑布返回值里有工具数组:

ctx.on('system-prompt/assemble', async (assembly, context, next) => {
  ...
  const wire = Array.isArray(result?.tools) ? result.tools.map(schema => schema.name) : []
  const collapsed = wire.length > 0 && wire.every(name => name === RUN_CODE)
  ...
  if (!Array.isArray(result?.tools)) throw block(context.scope, 'assembled tool schemas unavailable')
  const leaked = result.tools.map(schema => schema.name).filter(hideable)

DSH 0.2.1 的 9d0c97b9d2 feat(tools): admit conditional tools per step 改成瀑布只变换 PromptPresentation,tools 由 SystemPrompt.assemble() 在瀑布之后才追加,#387 已经在 PTC 侧按这个事实改了(hasPtcInstruction / text-only hooks),同一条契约在 hide-official 里没有跟进。

结果:result.tools 恒为 undefined → 恒抛 assembled tool schemas unavailable。顺带一提,wire 也是空数组,所以 collapsed 恒为 false,PTC 折叠作用域的宽容分支同样失效。

复现(真实载荷形状)

在测试宿主上注册一个瀑布监听,模拟 0.2.1 的形状(进入前删掉 tools,返回前补回,与宿主 return { ...transformed, tools } 等价):

ctx.on('system-prompt/assemble', async (assembly, _context, next) => {
  const tools = assembly.tools
  delete assembly.tools
  return { ...await next(), tools }
})
await mount(ctx)   // 启用了 read/glob/grep 的替换
const agent = await mint(ctx, 'presentation-payload')
await assemble(ctx, agent)   // 这里抛 READINESS_BLOCKED ... assembled tool schemas unavailable
  • main@dfafddc:失败,消息同上
  • 0.2.0-rc.2(不删 tools)的同一场景:通过

期望行为

  • 载荷里有工具数组时:保留现在这条更严格的"组装面里还有已选官方工具"断言,行为不变
  • 载荷里没有工具数组时(0.2.1+):改用作用域视图逐项确认已选官方工具是否仍然可见(tools.get(<官方名>, scope)),仍然可见就照旧 fail closed
  • 不要因为"看不到数组"就无条件 block —— 那是把"无法证明"当成"证明有泄漏"

影响面

关联

Activity

  1. Gaudi-XIX commented on Oct 26, 2026

    @Gaudi-XIX

    Windows reproduction (win32-x64) — confirms it is not platform-specific

    Environment

    • DSH 0.2.1-rc.3 (Windows, win32-x64, Electron 44.7.0 / bundled node 24.21.0)
    • dsh-ops 0.4.1 (npm release)
    • profile row dsh-ops-hide-official enabled, replaceTools: ['grep'] (single selection, not the full triple)

    Observed

    Same failure, same message shape as the macOS report:

    READINESS_BLOCKED (EXECUTOR_UNAVAILABLE): dsh-ops hide-official cannot verify selected replacements:
    missing OPS surface: grep -> ops_grep. Restore the selected OPS tools, remove the selection from
    replaceTools, or disable the dsh-ops-hide-official row.
    

    Two independent details worth noting:

    1. missing OPS surface: grep -> ops_grep fires even with alwaysLoaded: [grep] configured on discovery — the single-selection path reaches the assembled-surface guard and still cannot see the replacement, consistent with result.tools being unconditionally undefined under 9d0c97b9d2. (First attempt was without alwaysLoaded; both fail, so the guard, not the publication, is the blocking step.)
    2. The host flips the row fail-closed: a few minutes after the error, the saved profile row was rewritten by the host to disabled: true while keeping config.replaceTools: ['grep']. After manually restoring disabled: false with an empty selection, the row is inert (no masks, no errors), matching the documented zero-selection behavior.

    No new failure mode — this is a straight Windows confirmation of #413. Regression fix in #414 should cover it; happy to re-test on win32-x64 once it lands or a pre-release npm tag is published.

  2. Gaudi-XIX commented on Oct 26, 2026

    @Gaudi-XIX

    Correction to this comment (I misattributed one detail):

    1. The host flips the row fail-closed: a few minutes after the error, the saved profile row was rewritten by the host to disabled: true while keeping config.replaceTools: ['grep'].

    That rewrite was not an automatic host fail-closed action — it was the user manually toggling the row off in the plugin settings UI after seeing the error. Everything else in this reproduction (the READINESS_BLOCKED message text, firing with replaceTools: ['grep'] both with and without alwaysLoaded: [grep], DSH 0.2.1-rc.3 + dsh-ops 0.4.1 on win32-x64) stands unchanged. Apologies for the noise; the root-cause analysis in #413 and the fix in #414 are unaffected.

  3. added a commit that references this issue on Oct 29, 2026
    410c2c2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions