Skip to content

feat(skills): require roles for configured namespaces - #1840

Merged
SaulMoro merged 4 commits into
Tencent:mainfrom
YogeLiu:feat/1838-role-required-skill-namespaces
Nov 13, 2026
Merged

SaulMoro merged 4 commits into
Tencent:mainfrom
YogeLiu:feat/1838-role-required-skill-namespaces

Conversation

@YogeLiu

@YogeLiu YogeLiu commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

未选择角色的成员会走兼容的全量同步路径,收到团队按业务线划分的技能。本 PR 增加 sharing.skills.roleRequiredNamespaces,使指定命名空间必须出现在有效角色的 resources.skills 中才能分发。成员仍自行执行 teamai roles set developer;CLI 不自动选择或分配角色。

Closes #1838.

改动

sharing:
  skills:
    roleRequiredNamespaces: [bus_common, ebao, health]
  • 使用现有命名空间 schema 校验目录名。字段缺省或为 [] 时保持原有分发行为。
  • 在期望 skills 集合中先按角色筛选,再处理同名技能、命名空间冲突和标签合并。项目或标签不能绕过条件。主角色、附加角色和团队分配继续采用现有有效角色;工作流副本采用其步骤角色。
  • 各工作区子目录先按自身角色筛选再聚合。完整团队技能清单仍供现有清理逻辑使用,以回收未修改副本并保留成员编辑和个人文件。
  • 跳过时输出英文原因与下一步命令;团队已分配角色时提示修改成员分配。同步更新中英文分发指南、工作区设计约束和按需加载的排查指引。

验证

  • 原实现上先运行新增回归:16 项失败,覆盖字段被丢弃、非法命名空间被接受、无角色全量分发、项目/标签绕过及同名冲突。
  • npm run typecheck:通过。
  • npm run lint:通过,包含文档检查。
  • git diff --check:通过。
  • 第一批 5 个测试文件:198 项通过(desired-skills、types、workspace-children、pull-namespace-override、pull-tombstone)。
  • 第二批 2 个测试文件:56 项通过(roles-assigned-cmd、pull-skip-sync)。合计 254 项通过。

真实 CLI / verify world

macOS、Node v22.22.3,基于 origin/main 的 6ea3ee5db414 加本 PR runtime 改动。源码包版本仍为 0.22.0,没有改发布版本。通过 npm run verify:world 构建、打包并安装到隔离 HOME,使用本地 bare 团队仓库;未调用真实远端 provider,也未更改本机 TeamAI 安装或团队配置。

World 20261112T033159-346af4
Build 6ea3ee5db414+dirty, teamai 0.22.0, sha256 8713717f3f38

在该 world 中通过 npm run -s verify -- sh <run> ... 运行 fixture 和真实 teamai 命令,逐步断言 Claude 技能文件:

操作 实际结果
未配置新字段,成员无角色,pull --force 六个 fixture 技能全部下发,兼容行为保留
团队提交角色映射及新字段,仍无角色,再 pull 收回 bus_common/ebao/health 中未修改副本;保留未受约束技能、个人技能和本地编辑
roles set developer 后 pull 收到 bus_common;此前成员编辑和个人文件仍保留
roles set ebao 后 pull --dry-run --force 已分发文件集合不变
实际 pull 收到 bus_common + ebao
roles set health 后 pull 收到 bus_common + health,旧业务线未修改副本被回收
团队新增健康技能,真实 hook-dispatch session-start --tool claude --bg-only 冷却结束后收到新健康技能,ebao 未进入分发集合

紧接手动 pull 的首次 hook 正常复用了既有 60 秒刷新冷却,所以没有立即拉取新提交;到期后的重试完成了上述后台下发检查。没有更改冷却实现。

最后重新 init/pull 并运行 npm run -s verify -- ledger <run>,卸载后的 LEDGER-2.md 结果为:

Ledger: CLEAN

首次 ledger 报出的 home/Library 是 fixture 使用系统 Python 生成的 com.apple.python 缓存。核对后仅将该测试产物移到 world 的 tmp,随后重新验证 init/pull/uninstall;没有修改 ledger 规则或 TeamAI 清理实现。宿主文件检查未报告变更;两个 Unix socket 不可读取,未作验证。

覆盖边界

  • 本地验证了 user-scope 的集合解析,以及 workspace-scope 的 CLI 分发、角色切换、dry-run、真实 SessionStart 后台入口和卸载;子目录聚合有真实文件系统单测。
  • 所有接收 skills 的工具共用此解析路径;真实文件下发检查为 Claude + git。Codex、CodeBuddy、OpenCode,其它 provider,以及产品侧 linked-worktree/submodule/self-mode 的额外组合留给 CI。没有声称运行了真实 AI 宿主会话。
  • HTTP local-agent 的服务端下发协议不在本 PR 修改范围。未运行完整测试套件或 Windows。
  • 未增加 CLI 命令或外部进程调用。未增加常驻技能上下文;新增排查文字只在按需加载的 reference 中。未测 agent wait budget 的数值变化。
  • 该字段控制资源分发,不授予外部权限。团队依赖它之前,成员须先升级 CLI;旧版不会执行这项条件。

@SaulMoro SaulMoro left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was generated by AI during triage.

读了 66d6848c 的源码改动(src/resources/desired.ts、src/types.ts)和中英文指南。实现很集中:roleAllowedSkills 在 resolveDesiredSkills 里先按有效角色筛掉受限命名空间,再交给角色扫描、sharedFirst 和标签匹配。所以项目和标签都绕不过去,字段缺省或为 [] 时行为不变。字段用现有的 NamespaceSegmentSchema 校验。指南写清楚了“团队依赖它之前,所有成员先升级”。

几点意见,都不阻断:

  • [P3 可选] 只要有一个有效角色 id 在 manifest/roles.yaml 里找不到(比如角色已被删掉),roles.length === ids.length 不成立,allowed 就是空集,所有受限命名空间都会被跳过,连其它有效角色本该收到的也一样。fail-closed 本身没问题,但提示说的是 “Your effective roles do not receive them”,会让成员以为是自己的角色映射错了。建议点名那个找不到的角色。
  • [P3 可选] warnOnce 放在 resolveDesiredSkills 的路径上,所以除了 pull,teamai doctor、dashboard 的交付视图和 benchmark 的 team-without 也会打印这条提示,而它的下一步写的是 “then teamai pull”。如果只想在 pull 时提示,可以把 skipped 返回给调用方,由 pull 来说。
  • [P3 可选] CHANGELOG 这条没写“先升级所有成员”。旧版 CLI 会忽略这个字段,照旧全量下发,正好和团队配置的意图相反。指南里有这句,CHANGELOG 里也值得加上。

CI 和 Codex review 在这个 head 上还在跑。

@jeff-r2026 your call on this one. 这是新的团队配置项(sharing.skills.roleRequiredNamespaces),只管 skills,不管 rules、agents、knowledge,算产品层面的取舍:是否接受这个键名和这个范围,需要你来定。

@SaulMoro
SaulMoro requested a review from jeff-r2026 November 12, 2026 03:41
@github-actions

Copy link
Copy Markdown

未发现指定 diff 中有充分证据支持的缺陷。

PR 描述已提供隔离 verify world 中的真实 CLI 验证记录,覆盖角色切换、旧副本回收、dry-run、后台 hook 分发及卸载,满足运行时变更的测试记录要求。其余工具、provider 和 Windows 覆盖已明确留给 CI,不构成阻断项。

本次仅阅读指定 diff,未运行、构建或安装 PR 中的代码;未独立复验描述中的测试结果。

@SaulMoro

Copy link
Copy Markdown
Collaborator

CI 的 7 个 doctor.test.ts 失败(Ubuntu Node 20/22/24、macOS shard 1,以及 coverage)在本地可以复现,确实是这个 PR 引入的:在 66d6848c 上 7 个失败,在基线 6ea3ee5d 上 92 个全部通过。

doctor 报的是:

✖ Skills to deliver can be resolved
  → Cannot read properties of undefined (reading 'roleRequiredNamespaces').

原因在测试 fixture,不在实现。src/resources/desired.ts:303 读取 teamConfig.sharing.skills.roleRequiredNamespaces。真实的 teamai.yaml 经过 SharingConfigSchema 解析,skills 有 .default({}),所以不会出问题。但 doctor.test.ts 里有 8 处 sharing: { env: { injectShellProfile: false } } 没有经过 schema,sharing.skills 是 undefined。

建议在这 8 处补上 skills: {},或者用 schema 解析出 fixture,而不是在 desired.ts 里加 ?.:类型已经保证 skills 存在,加 ?. 只是掩盖 fixture 不符合类型。


English

The 7 doctor.test.ts failures in CI (Ubuntu Node 20/22/24, macOS shard 1, and coverage) reproduce locally and come from this PR: 7 fail at 66d6848c, and all 92 pass at the base 6ea3ee5d.

doctor reports:

✖ Skills to deliver can be resolved
  → Cannot read properties of undefined (reading 'roleRequiredNamespaces').

The cause is the test fixtures, not the implementation. src/resources/desired.ts:303 reads teamConfig.sharing.skills.roleRequiredNamespaces. A real teamai.yaml goes through SharingConfigSchema, where skills has .default({}), so it cannot fail there. But the 8 sharing: { env: { injectShellProfile: false } } fixtures in doctor.test.ts skip the schema, so sharing.skills is undefined.

Add skills: {} to those 8 fixtures, or build them through the schema, rather than adding ?. in desired.ts: the type already guarantees skills, and ?. would only hide fixtures that do not match it.

@SaulMoro SaulMoro left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was generated by AI during triage.

感谢 @YogeLiu。为了推进合并,我在这个分支上推了两个提交:

  • c10e68a8 合并了 main,只有 CHANGELOG.md 冲突,两边的条目都保留了;
  • c7c36fa0 修正了 doctor.test.ts 的 fixture:10 处 sharing: { env: … } 补上 skills: {},基础的 mockTeamConfig 补上 sharing: { skills: {} }。desired.ts 没有改动,也没有加 ?.。

修正前,合并后的代码上有 7 个用例失败,和 CI 一致。其中 2 个来自没有 sharing 的 mockTeamConfig,所以只改 env fixture 不够。修正后 92 个全部通过。typecheck、lint 和完整单元测试也通过,只有 checkout-roles.test.ts 一个已知用例在路径含 "review" 的克隆里失败,与本 PR 无关。

在 c7c36fa 上批准。之前的三个 [P3 可选] 不阻断合并。CI 和 CI review 在这个 head 上通过后合并。

合并风险: 低。本次推送只改了测试 fixture 和一次 main 合并。

@github-actions

Copy link
Copy Markdown

未发现指定 diff 中有充分证据支持的缺陷。此前审查未提出具体问题,因此没有需要确认已解决的旧 finding。

PR 描述提供了隔离 verify world 中的真实 CLI 验证记录,覆盖角色切换、旧副本回收、dry-run、后台 hook 分发和卸载,满足运行时变更的测试记录要求。记录基于较早提交不构成阻断;其余工具、provider 和 Windows 覆盖已明确留给 CI 或标注未运行。

本次仅阅读指定 diff(含上下文),未运行、构建或安装 PR 代码,也未独立复验描述中的测试结果。

# Conflicts:
#	CHANGELOG.md

@SaulMoro SaulMoro left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was generated by AI during triage.

在 336636d 上批准。这是一次 main 合并,#1859 合并后 CHANGELOG.md 出现冲突,已保留两边的条目。代码没有变化,CI 在这个 head 上通过后合并。

@github-actions

Copy link
Copy Markdown

未发现指定 diff 中有充分证据支持的缺陷。此前两次审查没有提出具体 finding,因此没有需要确认已解决的旧问题。

PR 描述提供了隔离 verify world 中的真实 CLI 验证记录,覆盖角色切换、旧副本回收、dry-run、后台 hook 分发和卸载,满足运行时变更的测试记录要求。记录基于较早提交不构成阻断;其它工具、provider 和 Windows 的覆盖边界已明确说明。

本次仅阅读指定 diff(含上下文),未运行、构建或安装 PR 代码,也未独立复验描述中的测试结果。

@SaulMoro
SaulMoro merged commit 17238b7 into Tencent:main Nov 13, 2026
20 checks passed
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.

[feat] 为指定 skills 命名空间增加显式角色要求,避免未选角色时全量分发

3 participants