Skip to content

feat(core): define mesh capability boundary - #11211

Merged
yiliang114 merged 1 commit into
codex/multi-agent-mesh-foundationfrom
codex/mesh-step-2-capability
Sep 6, 2026
Merged

feat(core): define mesh capability boundary#11211
yiliang114 merged 1 commit into
codex/multi-agent-mesh-foundationfrom
codex/mesh-step-2-capability

Conversation

@yiliang114

Copy link
Copy Markdown
Collaborator

What this PR does

This is mesh implementation step 2. It adds one fail-closed classification table covering every built-in core tool and the six planned thread tools, derives the effective tool configuration by intersecting the built-in ceiling with the agent definition, and reuses the existing shell AST classifier to reject anything not classified as read-only.

The design and acceptance documents are updated in the same commit to record the stacked child-PR workflow and the exact boundary this step proves.

Why it is needed

Mesh agents share one long-lived body across threads, so v1 needs a hard read-only ceiling that agent definitions can narrow but never widen. Unknown names, including MCP tools, default to deny. Thread tools are always supplied by the mesh runtime rather than inherited from a persona definition.

This child PR depends on the runtime preparation already carried by the foundation branch from #11200, #11204, and #11202. It does not copy or modify those runtime hot paths.

Reviewer Test Plan

How to verify

Run cd packages/core && npx vitest run src/agents/mesh/capability.test.ts. Expect all 10 tests to pass. Confirm that every ToolNames value appears exactly once in the classification table, an unlisted or MCP name is denied, a narrowed agent definition cannot re-enable a denied tool, all thread tools remain present, read-only shell commands are allowed, and write or unknown commands are refused with their classifier reason.

Evidence (Before & After)

N/A — internal capability policy and tests only.

Tested on

OS Status
🍏 macOS
🪟 Windows N/A
🐧 Linux N/A

Environment (optional)

Named Vitest file in a build-less worktree using the documented local test harness.

Risk & Scope

  • Main risk or tradeoff: MCP tools currently fail closed, and web_fetch / web_search are classified as denied. Both policy choices remain pending owner confirmation rather than being treated as settled product behavior.
  • Not validated / out of scope: the predicate is not connected to shell invocation in this step. That tool-layer hook and its refusal proof belong to step 4/5 with the launcher.
  • Breaking changes / migration notes: none; no launcher consumes this policy yet.

Linked Issues

Parent delivery PR: #11206.

中文说明

本 PR 做什么

这是 mesh 实现的第 2 步。它新增一张 fail-closed 分类表,覆盖 core 的全部内置工具和计划中的六个 thread 工具;通过内置上限与 agent definition 取交集生成有效工具配置;并复用现有 shell AST 分类器,拒绝所有未判定为只读的命令。

同一个提交也更新了设计与验收文档,记录 stacked 子 PR 工作流,以及本步骤实际证明的边界。

为什么需要

Mesh agent 会跨线程复用一个长期执行体,因此 v1 需要一个 agent definition 只能收窄、不能放宽的只读硬上限。所有未知名字(包括 MCP 工具)默认拒绝。Thread 工具由 mesh runtime 固定提供,不从 persona definition 继承。

这个子 PR 依赖 foundation 分支已经承载的 #11200#11204#11202 runtime 前置改动,不复制也不修改这些 runtime 热路径。

Reviewer Test Plan

如何验证

运行 cd packages/core && npx vitest run src/agents/mesh/capability.test.ts,预期 10 个测试全部通过。确认每个 ToolNames 值都在分类表中恰好出现一次;未列出名字和 MCP 名字会被拒绝;收窄后的 agent definition 无法重新启用被拒绝工具;全部 thread 工具仍存在;只读 shell 命令允许,写命令与未知命令会带分类原因被拒绝。

Evidence (Before & After)

N/A——仅内部能力策略和测试。

Tested on

OS Status
🍏 macOS
🪟 Windows N/A
🐧 Linux N/A

Environment

在 build-less worktree 中使用文档规定的本地测试 harness,仅运行指定 Vitest 文件。

Risk & Scope

  • 主要风险或取舍:MCP 工具当前 fail closed,web_fetch / web_search 当前归类为 deny。这两项都等待 owner 确认,未作为已确定产品行为。
  • 未验证或不在范围:本步骤尚未把谓词接入 shell 调用路径。工具层 hook 与拒绝证明属于带 launcher 的第 4/5 步。
  • 破坏性变更或迁移说明:无;当前还没有 launcher 消费这项策略。

Linked Issues

父交付 PR:#11206

@qwen-code-ci-bot

qwen-code-ci-bot commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator

Qwen Triage finishedview run. See the stage comments in this thread for the result.

Qwen Triage 已完成 —— 查看运行。结果见本线程中的各阶段评论。

@yiliang114
yiliang114 merged commit 985b0d8 into codex/multi-agent-mesh-foundation Sep 6, 2026
60 of 61 checks passed
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓ — all nine sections present and filled in. One trivial variance: the heading reads ## Why it is needed where the template says ## Why it's needed. Not worth a round-trip.

Worth saying up front, because it shapes everything below: this PR merged into codex/multi-agent-mesh-foundation at 16:44:47Z, eight seconds after triage posted its "running" notice, with zero reviews and no repository CI on this PR at all. That is the stacked-child-PR workflow this very diff documents ("Child PRs do not run the repository's unit-test or lint jobs"), so I'm reading it as intended process rather than a bypass. But it does mean nothing in this review could have gated the merge, and the findings below land on #11206 — which is still open, still draft, and whose head is now this PR's own merge commit.

Problem: this is step 2 of a committed implementation plan (docs/plans/2026-09-07-mesh-implementation-acceptance.md), not a bug fix, so the reproduction bar doesn't apply. The requirement is recorded in the design doc — mesh agents share one long-lived body across threads, so v1 needs a ceiling an agent definition can narrow but never widen — and it's scoped by parent delivery PR #11206. Documented requirement, not theoretical hardening.

Direction: the shape is right, but this is a trust boundary for autonomous agents, which is precisely the surface to escalate rather than auto-approve. The PR itself flags two items as "pending owner confirmation rather than being treated as settled product behavior": MCP names failing closed, and web_fetch/web_search classified as deny. Those are product calls, and the author is explicit that they aren't settled. I'd rather a human owned them than have a bot ratify them.

Size: core paths touched (packages/core/src/agents/mesh/capability.ts). Production logic 125 lines, tests 92, docs 44 — comfortably under the 500-line escalation threshold and the 1000-line advisory. The author has admin and is a listed core area owner, so the two-tier core gate is maintainer-exempt per AGENTS.md.

Approach: the scope is genuinely minimal — one classification table, three pure functions, and doc edits that carefully record what this step does not prove. No drive-by refactors, no unrelated churn. My one substantive question is duplication: checkMeshShellCommand re-derives a thin slice of core/plan-mode-shell-policy.ts, which already wraps the same classifier for the same read-only purpose and handles considerably more around it. Detail in Stage 2.

Risk: no Stage 1e high-risk path match.

Moving on to code review. 🔍

中文说明

感谢贡献!

模板完整 ✓ —— 九个章节齐全且都有实质内容。一个很小的差异:标题写的是 ## Why it is needed,模板里是 ## Why it's needed,不值得为此来回一轮。

先说明一个影响下面所有判断的事实:本 PR 于 16:44:47Z 合入 codex/multi-agent-mesh-foundation,就在 triage 发出「正在运行」提示后 8 秒零 review,且本 PR 完全没有跑仓库 CI。这正是本 diff 自己记录的 stacked 子 PR 流程(「子 PR 不跑仓库的单测和 lint job」),所以我把它理解为既定流程而非绕过。但这确实意味着本次 review 中的任何结论都不可能拦住这次合并,下面的发现实际落在 #11206 上——它仍然是 open、仍然是 draft,而它的 head 现在已经就是本 PR 的合并提交。

问题: 这是已提交实施计划(docs/plans/2026-09-07-mesh-implementation-acceptance.md)的第 2 步,不是 bug fix,因此不适用复现门槛。需求在设计文档中有记录——mesh agent 跨线程复用一个长期执行体,所以 v1 需要一个 agent definition 只能收窄、不能放宽的上限——并由父交付 PR #11206 界定范围。属于有记录的需求,不是理论性加固。

方向: 形态是对的,但这是自主 agent 的信任边界,恰恰是应该上报而不是自动批准的那类改动。PR 自己也把两项标为「等待 owner 确认,未作为已确定产品行为」:MCP 名字 fail closed,以及 web_fetch/web_search 归类为 deny。这些是产品决策,作者也明确说尚未定案。与其让 bot 来背书,不如由人来拍板。

规模: 触及核心路径(packages/core/src/agents/mesh/capability.ts)。生产逻辑 125 行、测试 92 行、文档 44 行——远低于 500 行上报阈值和 1000 行大 PR 建议线。作者拥有 admin 权限且是 core 区域的登记 owner,因此按 AGENTS.md,两层核心门禁对维护者豁免。

方案: 范围确实很小——一张分类表、三个纯函数,以及谨慎记录了本步骤证明什么的文档改动。没有顺手重构,没有无关改动。我唯一实质性的疑问是重复:checkMeshShellCommand 重新实现了 core/plan-mode-shell-policy.ts 的一小片,后者已经为了同样的只读目的包装了同一个分类器,并且处理了更多周边情况。详见 Stage 2。

风险: 未命中 Stage 1e 高风险路径。

进入代码审查 🔍

Qwen Code · qwen3.8-max-2026-09-02

Reviewed at f22791d4770ccc2d45a409fe60d04780e45e0e2b · re-run with @qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Code review

Before reading the diff I wrote down what I'd do for "give mesh agents a read-only tool ceiling that definitions can narrow but not widen": a single name→verdict table as committed data, a compile-time exhaustiveness guard so a new ToolNames member can't slip through unclassified, an intersection function that starts from the ceiling rather than the definition, and reuse of the existing shell AST classifier instead of a new command parser. That is very close to what this PR does, so the approach matches my independent proposal — with one exception I'd have done differently, below.

The good parts are worth naming, because they're the reason this isn't a bigger concern:

  • as const satisfies Record<CoreToolName | MeshThreadToolName, MeshToolClassification> makes exhaustiveness a build property, not a test property. I verified the count independently: ToolNames has 49 members at this commit, plus 6 thread tools = 55, and the table has exactly 55 entries. Add a tool to core and this file stops compiling until someone classifies it.
  • classifyMeshTool gates on Object.hasOwn, so __proto__ and friends fall through to deny rather than walking the prototype chain. The test covers it.
  • The mesh deny set is a strict superset of the existing EXCLUDED_TOOLS_FOR_SUBAGENTS in agents/runtime/agent-core.ts — every tool that set excludes (agent, cron_, team_, task_*, todo_write, plan lifecycle, enter/exit_worktree, artifact, record_artifact, workflow, send_message, list_agents, request_shutdown, task_stop) is also denied here. Consistent with the repo's existing subagent posture, and stricter.
  • executionAllowedTools mirrors tools, so the declaration allowlist and the execution allowlist can't drift apart.

Three things I'd want a human to look at, none of them blocking on a staging branch:

1. checkMeshShellCommand duplicates a thinner version of core/plan-mode-shell-policy.ts. Reusing classifyShellCommandSafetyInDirectory is exactly right. But that classifier already has a production consumer solving the same problem — plan mode also permits only read-only shell — and it handles three things the new predicate doesn't: it wraps the call in try/catch and degrades a throwing classifier to 'unknown' instead of letting the promise reject; it races the parse against an AbortSignal so a slow AST walk is cancellable; and it re-validates mode, approval revision, cwd, target dir and a deep-equal of the invocation params before an approval is honored, i.e. it closes the classify-then-execute TOCTOU gap. The new function is 8 lines with none of that, and takes cwd on faith from a caller that doesn't exist yet. Mesh denies monitor at the name level, so plan mode's monitor-normalization branch is moot here — but the error degradation and the stale-context revalidation are not. My recommendation is to reuse or extract that module's classification core before step 4/5 wires this, or at minimum match its degrade-to-unknown behavior. As written, whether a classifier exception fails closed is entirely up to an unwritten caller.

2. There are now three parallel notions of "read-only tool", and they disagree. agents/runtime/subagent-plan-tool-policy.ts already exports READ_ONLY_INSPECTION_TOOLS = read_file, grep_search, glob, list_directory, lsp, tool_search, read_mcp_resource. This table denies lsp and read_mcp_resource. Denying is the conservative direction so nothing is breached, and the MCP denial is consistent with the PR's stated fail-closed-for-MCP default — but neither design doc mentions that the existing set exists or why mesh diverges from it. One sentence recording that as deliberate would stop the next person "fixing" the inconsistency in the wrong direction.

3. The ceiling is currently asserted, not enforced. Nothing imports capability.ts. I checked all five sibling modules in agents/mesh/ (dispatch-policy, mentions, mesh-store, thread-actions, types) and the agents/runtime/index.ts barrel — no importer. The PR declares this honestly ("the predicate is not connected to shell invocation in this step"), and SKILL being allowed matches existing subagent behavior, where skill availability is computed as !EXCLUDED_TOOLS_FOR_SUBAGENTS.has(ToolNames.SKILL). So this is staged work, not an oversight. But the consequence is concrete: no shell command is actually refused at runtime today, and the 10 tests prove the table classifies correctly, not that anything is blocked. It also means I cannot name a single downstream consumer, which is the exact condition under which the core-module gate says to escalate rather than approve.

Two smaller notes: buildMeshToolConfig([]) yields the six thread tools and nothing else — correct per "thread tools are always supplied by the mesh runtime", just worth knowing that an empty definition isn't an empty toolset. And web_fetch/web_search being denied is a real capability reduction for a research-oriented agent; the PR flags it as pending owner confirmation, which I think is the right handling.

Testing

Stating plainly what evidence this section carries: the PR's own CI, read through the API. I did not build or run any PR code — triage is static, and executed code could read the write PAT in this environment.

On this PR's head commit there are 73 check-runs and not one of them is a test, lint, typecheck or build job. Every entry is bot orchestration. So there is zero automated test evidence attached to this PR — which the diff itself documents as intended for stacked child PRs.

The load-bearing signal is the deferred gate, #11206, whose head 985b0d856b9db8b7797d84ad706eff7ca26c57b7 is this PR's merge commit. Fetched once, not polled:

Check (on #11211 head f22791d4) Conclusion
label success
assign success
authorize success
delete-asset-branch success
triage in_progress (this run)
review-pr, verify, tmux-testing, precheck-pr, resolve-pr, publish-*, fallback-comment, review-config, delay-automatic-review, ack-review-request skipped / cancelled
Test / Lint & Static / Integration Tests not present on this PR
Deferred gate — #11206 at 985b0d85 Conclusion
Test (ubuntu-latest, Node 22.x) in_progress
Lint & Static (ubuntu-latest, Node 22.x) in_progress
Integration Tests (no-AK, No Sandbox) in_progress
Test (macos-latest, Node 22.x) skipped
Test (windows-latest, Node 22.x) skipped
Integration Tests (CLI, No Sandbox) skipped
Desktop Shell (ubuntu-22.04) success
Desktop Shell (windows-2022) success
Classify PR success

Read that second table carefully: the three checks that would actually exercise this code — unit tests, lint/typecheck, integration — were still running at review time, and macOS and Windows unit runs are skipped. Nothing has failed. Nothing load-bearing has passed either. The step's own acceptance doc says "The step is not complete until #11206 CI passes after the child PR merges", and that condition is not yet met.

Not verified, and why:

  • "1 file, 10 tests passed" for capability.test.ts — the author's claim. I did not re-run it (⛔ triage never executes PR code), and no CI check on either PR corroborates it.
  • "Targeted lint and core typecheck also pass on this branch" — also the author's claim. This one matters more than it looks: the satisfies exhaustiveness guard is a typecheck property, and since no typecheck job ran on this PR, that guard has never been exercised by automation. It rests entirely on a local run.
  • Runtime refusal of a write command — unobservable. No caller exists, so there is nothing to exercise.

Sandboxed verification would settle this, but not yet: @qwen-code /verify on #11206 after step 4/5 wires the predicate is what would prove the refusal path actually fails closed — that a command classified write or unknown cannot reach execution, and that a classifier exception denies rather than rejects. Today neither /verify nor /tmux can settle it, because there is no consumer to A/B against and no TUI surface; the claim is a table plus 10 unit tests, and I've verified both statically rather than treating the green local run as evidence.

中文说明

代码审查

在读 diff 之前,我先写下了自己对「给 mesh agent 一个只能收窄、不能放宽的只读工具上限」的做法:一张以提交数据形式存在的「名字→判定」表、一个编译期穷尽性约束(让新增的 ToolNames 成员无法漏掉分类)、一个从上限而不是从 definition 出发取交集的函数,以及复用现有 shell AST 分类器而不是新写命令解析。这和本 PR 的做法非常接近,所以方案与我的独立提案一致——只有一处我会做得不同,见下。

值得点名的优点,也是这件事没有变成更大隐患的原因:

  • as const satisfies Record<CoreToolName | MeshThreadToolName, MeshToolClassification> 把穷尽性变成了构建期属性,而不只是测试属性。我独立核对了数量:本提交上 ToolNames 有 49 个成员,加上 6 个 thread 工具 = 55,而分类表恰好 55 条。往 core 里加一个工具,这个文件就会编译不过,直到有人给它分类。
  • classifyMeshToolObject.hasOwn 判定,因此 __proto__ 之类会落到 deny,而不是沿原型链取值。测试覆盖了这点。
  • mesh 的 deny 集合是现有 agents/runtime/agent-core.tsEXCLUDED_TOOLS_FOR_SUBAGENTS严格超集——该集合排除的每个工具(agent、cron_、team_、task_*、todo_write、plan 生命周期、enter/exit_worktree、artifact、record_artifact、workflow、send_message、list_agents、request_shutdown、task_stop)在这里也都被拒绝。与仓库既有的 subagent 姿态一致,且更严格。
  • executionAllowedToolstools 保持一致,因此声明白名单和执行白名单不会各自漂移。

有三点希望有人看一眼,在 staging 分支上都不构成阻塞:

1. checkMeshShellCommand 重复实现了 core/plan-mode-shell-policy.ts 的一个更薄的版本。 复用 classifyShellCommandSafetyInDirectory 完全正确。但该分类器已经有一个生产消费者在解决同样的问题——plan mode 同样只允许只读 shell——而它处理了三件新谓词没处理的事:它用 try/catch 包住调用,把分类器抛错降级为 'unknown',而不是让 promise reject;它用 AbortSignal 与解析竞速,使缓慢的 AST 遍历可被取消;它在批准生效前重新校验 mode、approval revision、cwd、target dir 以及调用参数的 deep-equal,也就是闭合了「先分类后执行」的 TOCTOU 缺口。新函数只有 8 行,这些都没有,而且 cwd 完全由一个尚不存在的调用方传入。mesh 在名字层就拒绝了 monitor,所以 plan mode 的 monitor 归一化分支在这里无关紧要——但错误降级和上下文重校验并非无关。我的建议是在第 4/5 步接线之前复用或抽出该模块的分类核心,至少也要与其「降级为 unknown」的行为一致。按现在的写法,分类器抛异常时是否 fail closed 完全取决于一个还没写的调用方。

2. 现在有三套并行的「只读工具」定义,而且彼此不一致。 agents/runtime/subagent-plan-tool-policy.ts 已经导出 READ_ONLY_INSPECTION_TOOLS = read_file、grep_search、glob、list_directory、lsp、tool_search、read_mcp_resource。本表把 lspread_mcp_resource 判为 deny。拒绝是更保守的方向,所以没有破坏什么,而且 MCP 的拒绝与 PR 声明的「MCP 一律 fail closed」默认一致——但两份设计文档都没有提到这个既有集合的存在,也没说明 mesh 为何与它分歧。加一句话把这个分歧记录为有意为之,可以避免下一个人朝错误方向去「修正」这个不一致。

3. 目前这个上限是被声明的,而不是被执行的。 没有任何文件 import capability.ts。我检查了 agents/mesh/ 下全部五个同级模块(dispatch-policymentionsmesh-storethread-actionstypes)以及 agents/runtime/index.ts 这个 barrel——没有 importer。PR 对此是坦诚的(「本步骤尚未把谓词接入 shell 调用路径」),而且 SKILL 被判为 allow 与既有 subagent 行为一致,那里 skill 可用性是按 !EXCLUDED_TOOLS_FOR_SUBAGENTS.has(ToolNames.SKILL) 计算的。所以这是分步实施,不是疏漏。但后果很具体:今天运行时并没有任何 shell 命令真的被拒绝,那 10 个测试证明的是分类表分类正确,而不是任何东西被拦住了。这也意味着我无法说出任何一个下游消费者,而这恰恰是核心模块门禁要求上报而非批准的条件。

另外两点小注:buildMeshToolConfig([]) 会得到六个 thread 工具而非空集——按「thread 工具固定由 mesh runtime 提供」这是正确的,只是要知道空 definition 不等于空工具集。以及 web_fetch/web_search 被判 deny 对偏研究型的 agent 是实际的能力收缩;PR 把它标为等待 owner 确认,我认为这个处理是对的。

测试

明确说明本节携带的证据:本 PR 自己的 CI,通过 API 读取。我没有构建或运行任何 PR 代码——triage 是静态的,而执行代码可能读到本环境中的 write PAT。

在本 PR 的 head 提交上有 73 个 check-run,其中没有一个是测试、lint、typecheck 或构建 job。全部是 bot 编排类。所以本 PR 上没有任何自动化测试证据——diff 自己把这一点记录为 stacked 子 PR 的预期行为。

真正承重的信号是被推迟的门禁 #11206,它的 head 985b0d856b9db8b7797d84ad706eff7ca26c57b7 就是本 PR 的合并提交。一次性抓取,未轮询:

请看上面第二张表:真正会执行到这段代码的三个检查——单测、lint/typecheck、集成测试——在审查时仍在运行,而 macOS 和 Windows 的单测被跳过。没有失败项,但也没有任何承重项通过。本步骤的验收文档自己写着「The step is not complete until #11206 CI passes after the child PR merges」,这个条件目前尚未满足。

未验证项及原因:

  • capability.test.ts「1 file, 10 tests passed」——作者的声明。我没有重跑(⛔ triage 从不执行 PR 代码),两个 PR 上也没有任何 CI 检查佐证。
  • 「Targeted lint and core typecheck also pass on this branch」——同样是作者的声明。这一条比看上去更重要:satisfies 穷尽性约束是一个 typecheck 属性,而由于本 PR 没有跑 typecheck job,这个约束从未被自动化真正执行过,完全依赖一次本地运行。
  • 运行时拒绝写命令——不可观测。没有调用方,因此无从执行。

沙箱验证可以定论,但还不是现在:在第 4/5 步把谓词接线之后,对 #11206@qwen-code /verify,才能证明拒绝路径确实 fail closed——被判为 writeunknown 的命令无法到达执行,且分类器异常是拒绝而不是抛错。今天 /verify/tmux 都无法定论,因为没有可 A/B 的消费者,也没有 TUI 界面;这个声明目前就是一张表加 10 个单测,而我是静态核对这两者,并没有把绿色的本地运行当作证据。

Qwen Code · qwen3.8-max-2026-09-02

Reviewed at f22791d4770ccc2d45a409fe60d04780e45e0e2b · re-run with @qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Confidence: 3/5 — the code is clean and the exhaustiveness guard is genuinely well done, but the ceiling this PR declares isn't enforced by anything yet, and two of its policy choices are explicitly waiting on a product owner.

Stepping back. My independent proposal and this PR agree on almost everything: table-as-data, compile-time exhaustiveness, intersection from the ceiling down, reuse of the existing AST classifier. Where I'd have gone differently is the shell predicate. I'd have reused core/plan-mode-shell-policy.ts's classification core rather than writing a fresh 8-line function, because that module already paid for the lessons this one hasn't — degrade a throwing classifier to unknown, race the parse against an abort signal, and re-validate the invocation context before honoring a decision. And I'd have landed the table in the same commit as its first consumer, so the step that declares a read-only ceiling is also the step that proves one. Separating them is defensible for a 3795-line feature split into numbered steps, but the cost is exactly what this review ran into: a merged PR with no CI, no consumer, and a refusal path that can only be reasoned about, not observed.

Would I curse or thank the author maintaining this in six months? Mostly thank them. The satisfies guard means a new core tool cannot join the registry without someone making an explicit deny/allow decision, which is the single most valuable line in the diff — I verified it holds at 49 + 6 = 55 entries. The deny set is a strict superset of the existing subagent exclusions, so it doesn't quietly loosen anything. The docs edits are unusually honest about scope, recording that this step proves classification and not invocation-time refusal, and downgrading two earlier "decisions" to "conservative defaults while the owner decision remains open". That last part is why I'm not more confident, not less: the author has correctly refused to smuggle product decisions past a reviewer, and the natural consequence is that a human should own them.

So the verdict is defer, and I want to be precise about why, because none of it is a defect I'd ask to have fixed:

  • I can't approve. Stage 2 established there is no downstream consumer to name, which is the condition under which the core-module gate escalates instead of approving. The PR is also already merged, so an approval here would attest to a merge that happened before the review rather than authorizing one.
  • I won't request changes. Nothing is blocking, the author is a core area owner with admin, and a request-changes on an already-merged staging PR is noise that gates nothing.
  • The deferred gate hasn't spoken. feat(mesh): add persistent shared-thread agent collaboration #11206 — open, draft, REVIEW_REQUIRED, head equal to this PR's merge commit — had Test, Lint & Static and Integration Tests (no-AK, No Sandbox) still in progress at review time, with macOS and Windows unit runs skipped. The acceptance doc's own completion condition ("not complete until feat(mesh): add persistent shared-thread agent collaboration #11206 CI passes after the child PR merges") is unmet.

I tried to resolve an owner to hand this to and could not: $QWEN_MAINTAINER_HANDLE is unset, the PR carries no labels so the deterministic area resolver in .github/issue-owners.json matches nothing (matchArea is label-driven), and there are zero reviews so the most-recent-human-reviewer fallback is also empty. Per the gate's own rule I'm not going to guess a login. The two questions that need a human are therefore recorded here rather than assigned, and #11206 is where they actually land:

  1. MCP names fail closed, and web_fetch/web_search are denied. Both flagged by the author as pending owner confirmation. These decide whether a mesh agent can do research or use private MCP servers at all — a product call, not an implementation detail.
  2. Reconcile checkMeshShellCommand with core/plan-mode-shell-policy.ts before step 4/5 wires it. Cheaper to settle now, while there's no caller, than after a launcher depends on the current signature and its reject-on-throw behavior.

Nothing here should hold up the next numbered step. It should hold up #11206's merge to main until CI is green and someone owns the two decisions above.

中文说明

Confidence: 3/5 —— 代码是干净的,穷尽性约束做得确实好,但本 PR 声明的这个上限目前还没有任何东西去执行,而其中两项策略选择明确在等产品 owner 拍板。

退一步看整体。我的独立提案和本 PR 在几乎所有点上都一致:表即数据、编译期穷尽性、从上限向下取交集、复用现有 AST 分类器。我会做得不同的地方是 shell 谓词。我会复用 core/plan-mode-shell-policy.ts 的分类核心,而不是新写一个 8 行函数,因为那个模块已经为这个新函数尚未经历过的教训付过学费——把分类器抛错降级为 unknown、用 abort signal 与解析竞速、以及在决定生效前重新校验调用上下文。我也会把这张表和它的第一个消费者放在同一个提交里落地,让声明只读上限的那一步同时也是证明它的那一步。对一个拆成编号步骤的 3795 行特性来说,把它们分开是可以理解的,但代价正是本次 review 撞上的:一个已合并、没有 CI、没有消费者的 PR,以及一条只能靠推理、无法观测的拒绝路径。

六个月后维护它,我会骂作者还是谢作者?大部分是谢。satisfies 约束意味着新的 core 工具无法在不做出显式 deny/allow 决定的情况下进入注册表,这是整个 diff 里最有价值的一行——我核对了它成立,49 + 6 = 55 条。deny 集合是既有 subagent 排除项的严格超集,所以它没有悄悄放松任何东西。文档改动对范围的表述异常坦诚,记录了本步骤证明的是分类而不是调用期拒绝,并把先前两处「决定」下调为「owner 决策未定前的保守默认」。最后这一点正是我信心没有更高的原因,而不是更低:作者正确地拒绝了把产品决策偷渡过 reviewer,其自然结果就是应该由人来拍板。

所以结论是暂缓(defer),我想把原因说准确,因为其中没有一条是我会要求修的缺陷:

  • 我不能批准。Stage 2 已经确认说不出任何下游消费者,而这正是核心模块门禁要求上报而非批准的条件。而且本 PR 已经合并,所以在这里批准等于为一次发生在审查之前的合并背书,而不是授权一次合并。
  • 我不会 request changes。没有阻塞项,作者是拥有 admincore 区域 owner,而对一个已经合并的 staging PR 提 request-changes 只是拦不住任何东西的噪音。
  • 被推迟的门禁还没有发声。feat(mesh): add persistent shared-thread agent collaboration #11206——open、draft、REVIEW_REQUIRED,head 等于本 PR 的合并提交——在审查时 TestLint & StaticIntegration Tests (no-AK, No Sandbox) 仍在进行中,且 macOS 与 Windows 单测被跳过。验收文档自己的完成条件(「not complete until feat(mesh): add persistent shared-thread agent collaboration #11206 CI passes after the child PR merges」)尚未满足。

我尝试解析出一个 owner 来接手,但没能成功:$QWEN_MAINTAINER_HANDLE 未设置,本 PR 没有任何 label,因此 .github/issue-owners.json 里的确定性区域解析器匹配不到任何东西(matchArea 完全由 label 驱动),而且零 review,所以「最近一位人类 reviewer」这条兜底也是空的。按门禁自己的规则,我不会去猜一个 login。因此这两个需要人来回答的问题被记录在这里而不是被指派,而它们实际落地的地方是 #11206

  1. MCP 名字 fail closed,且 web_fetch/web_search 被判 deny。 两项都被作者标为等待 owner 确认。它们决定 mesh agent 到底能不能做检索、能不能用私有 MCP server——这是产品决策,不是实现细节。
  2. 在第 4/5 步接线之前,把 checkMeshShellCommandcore/plan-mode-shell-policy.ts 调和。 现在还没有调用方,处理起来更便宜;等 launcher 依赖了当前签名和它「抛错即 reject」的行为之后就贵了。

这些都不应该拖住下一个编号步骤。它们应该拖住 #11206 合入 main,直到 CI 变绿、并且有人对上面两个决策负责。

Qwen Code · qwen3.8-max-2026-09-02

Reviewed at f22791d4770ccc2d45a409fe60d04780e45e0e2b · re-run with @qwen-code /triage

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants