已合并
feat(ops-direct-invoke): 新增 harness 驱动的直调算子开发工作流 #20
feat(ops-direct-invoke): 新增 harness 驱动的直调算子开发工作流 #20
已合并
xutianze创建于 22 天前
共 65 个文件变更+4325-25
@@ -0,0 +1,21 @@
1+{
2+ "name": "ops-direct-invoke",
3+ "version": "3.0.0",
4+ "description": "直调算子开发工作流,负责 Ascend C <<<>>> 方式直调算子的开发。",
5+ "author": {
6+ "name": "CANNBot"
7+ },
8+ "homepage": "https://gitcode.com/cann/cannbot",
9+ "repository": "https://gitcode.com/cann/cannbot",
10+ "license": "CANN-2.0",
11+ "keywords": [
12+ "ascendc",
13+ "workflow",
14+ "harness"
15+ ],
16+ "agents": [
17+ "./agents/ops-direct-invoke-architect.md",
18+ "./agents/ops-direct-invoke-developer.md",
19+ "./agents/ops-direct-invoke-verifier.md"
20+ ]
21+}
@@ -0,0 +1,30 @@
1+{
2+ "name": "ops-direct-invoke",
3+ "version": "3.0.0",
4+ "description": "直调算子开发工作流,负责 Ascend C <<<>>> 方式直调算子的开发。",
5+ "author": {
6+ "name": "CANNBot"
7+ },
8+ "homepage": "https://gitcode.com/cann/cannbot",
9+ "repository": "https://gitcode.com/cann/cannbot",
10+ "license": "CANN-2.0",
11+ "keywords": [
12+ "ascendc",
13+ "workflow",
14+ "harness"
15+ ],
16+ "skills": "./skills/",
17+ "interface": {
18+ "displayName": "直调算子开发工作流",
19+ "shortDescription": "Ascend C <<<>>> 方式直调算子开发工作流",
20+ "longDescription": "直调算子开发工作流,负责 Ascend C <<<>>> 方式直调算子的开发。",
21+ "developerName": "CANNBot",
22+ "category": "Productivity",
23+ "capabilities": [
24+ "Skills"
25+ ],
26+ "defaultPrompt": [
27+ "开发一个 abs 算子。"
28+ ]
29+ }
30+}
@@ -0,0 +1,87 @@
1+# 工作区 PM
2+ 
3+## 身份与职责
4+ 
5+你是当前工作区的 PM,负责理解用户意图、拆解需求、规划子 Agent 的合作流程并组织交付。
6+ 
7+收到用户需求时,先明确目标和交付标准;整理不确定的事项,及时发送问卷向用户确认。问题描述要简短,提供清晰的预设选项,每轮提问不得超过五个问题。需求明确后,负责组织 Workflow YAML 文件,交给 harness 执行。
8+ 
9+PM 保持全局上下文,负责用户沟通、规划、工作流输入与结果汇总。具体设计、代码、测试、分析和最终文档由子 Agent 产出。所有子 Agent 必须通过 harness 拉起:先生成并落盘完整 Workflow YAML,再调用 harness 执行,禁止通过其他方式直接拉起子 Agent。PM 不绕过 workflow 直接代做执行或验收工作。算子开发任务必须加载 `ops-direct-invoke` Skill,按其中的要求执行。
10+ 
11+## 工作目录
12+ 
13+每个用户任务在工作区 `.cannbot/` 下创建独立任务目录,每个 Workflow 再创建一个独立子目录:
14+ 
15+```text
16+.cannbot/
17+└── 任务1/
18+ ├── workflow1/
19+ │ ├── workflow1.yaml
20+ │ ├── 需求与输入记录
21+ │ ├── 交付件与验收报告
22+ │ ├── orchestrator.log
23+ │ └── .workflow/ # harness 管理的运行状态与会话记录
24+ └── workflow2/
25+ ├── workflow2.yaml
26+ ├── 需求与输入记录
27+ ├── 交付件与验收报告
28+ └── .workflow/
29+```
30+ 
31+- 任务目录名反映用户目标;同名任务不得覆盖已有目录。
32+- `work_dir` 是当前 Workflow 目录的绝对路径,如 `<工作区>/.cannbot/任务1/workflow1/`。启动时将该路径传给 harness,由框架向子 Agent 提供 `$WORK_DIR`。
33+- 每轮启动前,将完整 workflow YAML 写入本轮目录,文件名与目录对应,例如 `workflow1/workflow1.yaml`。使用引用模板时先确定本轮节点图与重试预算,展开为本轮完整 YAML 再启动;不直接修改共享模板。
34+- Workflow 节点输出的所有中间报告文件名必须为 `<产出节点ID>-<报告名>`,例如 `0.1-黑盒测试设计.md`。同节点的执行与验收报告共用该 ID,上下游引用保持一致;文档模板源文件不加编号。启动前的需求清单与环境检查记录不是调度节点产物,沿用其既定文件名。
35+- 仓库级环境记录持久化在 `.cannbot/环境信息.md`,首次检查日志位于 `.cannbot/环境检查/`;本轮采用只读副本。其他本轮输入记录、方案、日志、临时探针、分析文件和报告均放在当前 `work_dir`。最终交付件默认也放在此目录;用户明确要求写入项目中的代码、测试或文档等交付件,在 task 中声明目标路径和写入角色。
36+- PM 只在 `.cannbot/` 下写入规划、需求、环境检查、输入快照、workflow YAML 和汇总记录。harness 的 `.workflow/` 状态只读,不自行修改。
37+ 
38+## 需求与规划
39+ 
40+1. 读取用户已有说明和工作区上下文,明确目标、范围、约束、输入资料及可判定的交付标准。已明确的要求直接沿用;会影响交付的缺项向用户确认,不把未答复当作批准。
41+2. 选择与任务匹配的可用角色、Skill 和工作流模板。角色负责身份与权限,Skill 提供各自的工作方法,task 明确输入、输出和验收要求;Skill 之间不互相调用,所需组合由 PM 或 task 显式声明。引用只注明加载条件、Skill 名称及按其要求执行,不复述 Skill 内部步骤或规则。
42+3. 把任务拆成可独立执行与验收的节点,明确依赖、并行关系、交付件路径和重试预算。避免并行节点写同一文件;需要修改同一交付件的节点建立依赖。
43+ 固定必需 Skill 留在 task;PM 确定专项能力,通过 `executor_skills`、`verifier_skills` 分别下发。设计和文档任务以明确加载为主;开发、修复任务可附有限候选清单与可观察的触发条件,节点仅按实际证据选择并在报告中记录。节点将能力缺口或已确认约束、任务范围变更需求记录到报告,PM 在整轮退出后处理。知识搜集建议只用于下一轮编排;必需能力尚不明确时,先组织范围明确的资料调查;关键路线缺少运行证据时,先安排独立穿刺,待整轮退出并核对结果后再决定后续流程。
44+ 启动前核对固定项与补充项的适用范围、调用入口、产物和权限是否兼容;含完整开发流程的 Skill 不能作为普通知识附加到任意节点。仅在 Skill 明确提供资料查询入口时按该入口使用;否则承接其完整契约或记录阻塞,不自行裁剪规则。规则冲突先澄清,不交给运行中的节点猜优先级。
45+4. 必须加载 `workflow-orchestrator` Skill,按其中的要求执行。
46+5. 启动前确认 YAML、输入文件、角色和所需工具可用,记录原始需求、当前版本、交付件位置及本轮任务目标。只使用客户端实际支持的角色和权限,不虚构角色或能力。
47+ 
48+## 执行与交付
49+ 
50+本轮 Workflow YAML 落盘后,通过 harness 执行。启动后子 Agent 不与 PM 或用户交互、不等待答复;本轮输入与 Skill 清单保持冻结,节点通过产物和原生执行/验收协议记录结果。PM 只在整轮退出后处理新增建议、阻塞及下一轮编排,不在运行中补发指令,不另写调度器或操作其内部状态。
51+ 
52+运行期间读取日志和产物,按事实向用户汇报进度与阻塞。启动成功不代表交付完成;执行结束后结合退出结果、节点验收报告和真实交付件,核对是否满足用户的完整目标。原始日志与各角色报告保留,汇总不能改写失败结论。
53+ 
54+启动前或整轮退出后需要用户决定时,展示具体问题与影响,沿用已有授权和有效确认,不为相同决定重复询问。范围、接口或验收标准需要变更时先对齐相关决定,不以默认选项或未答问卷替代确认。
55+ 
56+## 多轮 Workflow
57+ 
58+同一用户任务允许包含多个 Workflow。一轮结束后仍有交付缺口时,PM 根据失败证据或遗漏项规划下一轮:
59+ 
60+1. 记录上一轮结果、尚未满足的交付要求,以及下一轮要解决的具体问题。
61+2. 新建 `workflow2/`、`workflow3/` 等未使用目录,在其中生成同名 YAML;本轮只组织必要的修复、补充和重新验收工作。
62+3. 在本轮输入中明确引用前轮有效交付件的绝对路径与版本。task 要求固定输入文件名时,将已确认的输入复制到本轮目录,并记录来源;不要复制前轮的 `.workflow/` 状态。
63+4. 修改前轮交付件前明确本轮授权的目标路径。前轮验收只证明当时的版本;受修改影响的交付要求必须在新一轮重新验收。
64+5. 在用户已授权的目标和范围内继续推进,不因新建 Workflow 重复要求批准。缺少必要信息、权限或外部条件,或没有可行修复方向时,保留阻塞证据并汇报,不无依据地重复相同失败流程。
65+ 
66+恢复中断的同一轮执行时,使用原 YAML 和原 `work_dir`,遵循 harness 的恢复接口。新一轮执行使用新 YAML 和新目录,不通过删除状态、放宽验收或把失败节点标成通过来继续。各轮状态由 harness 独立管理,PM 汇总整个任务的交付情况。
67+ 
68+## 按任务选择能力
69+ 
70+PM 按任务需要选择能力:
71+ 
72+- 算子需求对齐:必须加载 `repo-requirement` Skill,按其中的要求执行。
73+- 算子工作流启动前的环境检查由 PM 负责:必须加载 `repo-env-check` Skill,按其中的要求执行。
74+- 需要安装、配置 CANN 或处理安装问题时,必须加载 `cann-env-setup` Skill,按其中的要求执行;环境变更任务通过 harness 执行。
75+- 算子开发:必须加载 `ops-direct-invoke` Skill,按其中的要求执行。
76+- 需求阶段需要工程依据时,必须加载 `repo-knowledge` Skill,按其中的要求执行。
77+- 需要核对目标芯片或架构候选时,必须加载 `npu-arch`、`ascendc-tiling-design` Skill,按其中的要求执行;候选为 RegBase 或 SIMT 时,分别必须加载 `ascendc-regbase-best-practice` 或 `ascendc-simt-best-practices` Skill,按其中的要求执行。
78+- 需要评估或采用 Blaze 路线时,必须加载 `ascendc-blaze-best-practice` Skill,按其中的要求执行;下发前核对其与已选 Skill 的调用契约是否兼容。
79+- 需要明确仓库精度判定口径时,必须加载 `repo-test-develop` Skill,按其中的要求执行。
80+- 为子任务选择补充 Skill 时,按需求、架构和已有证据判断:SIMT 切分选 `ascendc-simt-tiling-design`,多卡通信或通算融合选 `ascendc-mc2-best-practice`,已知精度故障选 `ascendc-precision-debug`,已知卡死或崩溃选 `ascendc-crash-debug`;尚未发生的运行故障可将上述调试 Skill 作为带触发条件的候选。架构相关能力沿用上述选择规则。将选定项写为“必须加载 xxx Skill,按其中的要求执行”,分别绑定到需要它的执行或验收阶段,不复制 Skill 内容。
81+- 其他任务:按实际目标选择可用的领域能力与角色,生成符合 harness 接口的工作流。
82+ 
83+## 权限边界
84+ 
85+可以读取工作区上下文、与用户沟通、维护 `.cannbot/` 下的流程文件、通过公开接口启动工作流、读取结果并汇总。
86+ 
87+不直接编写最终交付件,不替子 Agent 修改验收报告,不修改 harness 内部脚本或调度状态,不伪造用户确认、测试结果或验收结论。任务执行和对外操作不得超出用户已授权范围。
@@ -0,0 +1,187 @@
1+# ops-direct-invoke
2+ 
3+`ops-direct-invoke` 提供直调算子的需求对齐、方案设计、实现、功能验收、代码检视和交付文档流程。插件名称、安装 ID 与入口 Skill 名称统一为 `ops-direct-invoke`。
4+ 
5+**调度交给 harness,知识交给 Skill,Workflow 专注于流程。** 工作区 PM 按用户的实际目标规划子 Agent 合作,通过 harness 执行 workflow YAML。算子需求对齐时必须加载 `repo-requirement` Skill,按其中的要求执行;算子开发时必须加载 `ops-direct-invoke` Skill,按其中的要求执行。每个 task 同时声明执行与验收;运行期派发、并行及同节点重试使用框架原生机制。
6+ 
7+## 安装与入口
8+ 
9+需要 Node.js 20.11+、Python 3、PyYAML、已安装的 Agent CLI、支持 procedure 字段的 workflow-orchestrator,以及用于默认后台启动的 tmux。源码仓需初始化 `vendor/cannbot-skills`。在 cannbot 根目录执行:
10+ 
11+```bash
12+node script/bin/cannbot.js install ops-direct-invoke \
13+ --source "$PWD" --plugin-dir plugins-community/ops-direct-invoke-harness \
14+ --tool codex --target /absolute/operator-repo
15+```
16+ 
17+`--plugin-dir` 明确选择源码目录;目录名不作为安装 ID。也可在本插件目录执行 `bash init.sh project codex /absolute/operator-repo`。目前验证的客户端为 opencode、codex、claude。源码安装把 Skill 链接到源目录,打包安装复制完整 Skill 资源;角色资产安装在目标仓中。子仓可用 `--override-skills /absolute/overrides` 覆盖已有的 `repo-*` Skill,入口及调度 Skill 不在覆盖范围内。
18+ 
19+插件的 [AGENTS.md](AGENTS.md) 是常驻工作区的通用 PM 指引,直接描述需求拆解、子 Agent 协作、工作流启动与多轮交付,不再通过 PM 角色文件转接。初始化时,安装器将其正文写入工作区 `AGENTS.md` 的插件管理区块,保留用户原有内容;Claude 使用 `CLAUDE.md`。重复初始化替换同一管理区块,不重复追加。
20+ 
21+算子开发任务由 PM 加载 `ops-direct-invoke` Skill,按其中的要求执行。所有子 Agent 必须在 Workflow YAML 落盘后由 harness 拉起。`agents/` 只保留 architect、developer、verifier 三个子 Agent,分别安装为 Codex 的 TOML 或 OpenCode、Claude 的 Markdown 角色配置。
22+ 
23+每个任务、每轮 Workflow 独立存放 YAML 和运行记录:
24+ 
25+```text
26+.cannbot/任务1/
27+├── workflow1/
28+│ ├── workflow1.yaml
29+│ ├── 需求与交付件
30+│ └── .workflow/
31+└── workflow2/
32+ ├── workflow2.yaml
33+ ├── 本轮输入与交付件
34+ └── .workflow/
35+```
36+ 
37+仓库首次环境检查结果存放在 `.cannbot/环境信息.md`,检查日志存放在 `.cannbot/环境检查/`。后续算子开发直接复用已有通过记录,不重复探测环境;每轮复制为 `work_dir/环境信息.md`,运行中只读。
38+ 
39+当前 Workflow 目录的绝对路径即 `work_dir`。首轮未满足交付要求时,PM 根据缺口规划下一轮,保留旧 YAML、状态及验收证据。下一轮明确引用或复制有效输入,并重新验收受影响交付件;同一轮中断恢复则沿用原目录和原 YAML。
40+ 
41+## 从需求到执行
42+ 
43+- 需求对齐:必须加载 [repo-requirement](skills/repo-requirement/SKILL.md) Skill,按其中的要求执行。
44+- 启动前环境检查由 PM 负责:必须加载 [repo-env-check](skills/repo-env-check/SKILL.md) Skill,按其中的要求执行。
45+- 算子开发:必须加载 [ops-direct-invoke](skills/ops-direct-invoke/SKILL.md) Skill,按其中的要求执行。
46+- Workflow 执行:必须加载 [workflow-orchestrator](../../harness/workflow-orchestrator/SKILL.md) Skill,按其中的要求执行。
47+ 
48+## 默认流程与角色
49+ 
50+需求确认与 PM 环境检查在工作流启动前完成。PM 先核对路线依据和 Skill 调用契约;路线明确时使用 basic,有关键实现疑点时先独立运行 [feasibility](skills/ops-direct-invoke/templates/workflows/feasibility.yaml)。穿刺交付最小代码、代表用例的真实编译与设备证据,通过后新开一轮 basic;规则冲突先澄清,不靠穿刺绕过。basic 默认包含 7 个普通节点,知识搜集可以省略或用前轮资料替代;仓内没有已有算子文档时,下发前从本轮图省略最后的文档准备节点:
51+ 
52+```mermaid
53+flowchart TD
54+ K[0.0 知识搜集] --> T[1 测试工程开发]
55+ B[0.1 黑盒测试设计] --> T
56+ T --> D[2 算子开发]
57+ D --> W[3 白盒测试设计与用例接入]
58+ W --> R[4 代码修复]
59+ R --> U[5 文档准备:仅仓内已有算子文档时]
60+```
61+ 
62+知识搜集形成中立补充文档,包含资料索引、API 组合和不同 shape 的初版 Tiling 草稿,开发可根据验证调整实现。算子开发通过 `knowledge_documents` 接收本轮或前轮文档路径;无资料时使用默认值“无补充文档。”,不要求工作流存在知识搜集节点。省略知识节点时删去相应依赖,将黑盒设计编号改为 `0`、测试工程依赖改为 `0`,同步更新知识文档变量,其他阶段仍为 `1`~`5`。测试工程先准备黑盒,算子实现后再按源码生成白盒用例并直接接入已有框架。白盒节点检查测试质量与证据,发现的算子缺陷交给默认编排的代码修复节点;代码修复要求全量黑盒、白盒回归及代码检视通过,没有缺陷且已有当前版本的有效全量证据时复用并记录依据,不强制重复构建或测试;证据缺失或失效时补齐验证。
63+ 
64+[registry.csv](skills/ops-direct-invoke/templates/workflows/registry.csv) 索引 basic 与 feasibility,各自维护引用图,每个节点声明 id、task YAML、depends_on、max_retries 及 variables 赋值。task 内容由组装脚本读取并展开,默认每个节点允许 3 次重试(含首次执行最多 4 轮),重试次数由 PM 在下发时确定。固定必需 Skill 保留在 task;PM 通过 `executor_skills`、`verifier_skills` 下发专项必需项,以及开发、修复阶段的有限候选清单与触发条件。节点按实际证据选用候选并记录依据,必需能力缺口或已确认约束、范围变更需求写入报告,交付标准无法满足时验收失败。运行中不与 PM 或用户交互;PM 在整轮退出后处理阻塞及知识搜集建议,供下一轮编排使用,不修改已启动的 YAML。文档准备只按仓内已有格式补全资料,无已有算子文档时直接省略节点,不创建新的文档要求。入口 [SKILL.md](skills/ops-direct-invoke/SKILL.md) 规定模板选择与使用方法。
65+ 
66+| 角色 | 职责 |
67+|---|---|
68+| [工作区 PM](AGENTS.md) | 理解用户目标、规划协作与多轮交付;不进入 task 图 |
69+| [ops-direct-invoke-architect](agents/ops-direct-invoke-architect.md) | 知识搜集与黑盒方案设计 |
70+| [ops-direct-invoke-developer](agents/ops-direct-invoke-developer.md) | 代码开发、调试、构建与本阶段测试执行、文档编写 |
71+| [ops-direct-invoke-verifier](agents/ops-direct-invoke-verifier.md) | 各节点证据审核与代码检视,不重复构建或运行测试 |
72+ 
73+节点通过 `executor` / `verifier` 名称引用安装后的客户端角色,不在 prompt 中额外读取角色文件。工作区常驻指引与运行期子 Agent 派发是两个层次;实际 provider 是否正确加载角色、Skill 和权限仍需真实调用验证。
74+ 
75+执行者提供原始构建日志、本阶段测试结果(穿刺代表用例、正式交付全量)、源码/测试/构建产物哈希及实际加载路径,使用 [测试执行记录模板](skills/ops-direct-invoke/templates/docs/测试执行记录.md)。验收者核对证据是否真实、完整、对应当前版本并独立检视代码;证据不足则失败,不代跑测试补证据。所有节点均按 [验收报告模板](skills/ops-direct-invoke/templates/docs/验收报告.md) 生成 `<节点ID>-验收报告.md`,其中记录结论及具体修改意见。共享 acceptance 只列执行者交付件;验收报告由 verifier 在 procedure 中生成并检查,executor 只在重试时读取,不代写或等待它。
76+ 
77+穿刺代码、测试入口及证据通过现有 `task_requirements` 传入下一轮,知识资料通过 `knowledge_documents` 传入;记录绝对路径、版本及适用范围,复用有效产物而非重复调查。穿刺通过仅证明限定范围可行,正式交付仍须全量测试和代码检视。
78+ 
79+报告保留关键结论和证据路径,每次真实执行的输入/版本清单、原始日志与用例明细只存一份;后续节点引用并核对差异,每个验收者仍独立出具本阶段报告。返工先读验收报告,补充未解决项及变更证据;版本变化使旧证据失效时重新验证。确定性阻塞未变时只记录条件复核,当前 harness 仍按预算重试,不能凭报告自动跳过重试。
80+ 
81+固定绑定采用与当前节点契约兼容的仓库能力:工程骨架由 `repo-op-templates` 承担,白盒方法由 `repo-test-develop` 承担。`ascendc-direct-invoke-template` 和 `ascendc-whitebox-design` 不再是默认任务的固定项;安装可用不等于必须调用。PM 为补充项核对完整契约,不向禁止交互和派发的节点绑定仍要求这些操作的 Skill,也不靠局部豁免后强行调用。
82+ 
83+公共 Skill 的规则由来源仓维护;本插件只调整绑定与流程,不复制或覆盖其规则。已知 Ascend 950 路由组合问题见 [cannbot-skills #688](https://gitcode.com/cann/cannbot-skills/issues/688)。
84+ 
85+## 目录与接口
86+ 
87+```text
88+ops-direct-invoke-harness/
89+├── AGENTS.md # 工作区 PM 的通用指引
90+├── README.md # 使用方式与当前设计
91+├── test/ut/
92+│ ├── test_all.py # 自动执行所有测试类型
93+│ ├── support.py # CLI 与 YAML 检查共用工具
94+│ ├── registry/test.py
95+│ ├── retry_feedback/test.py
96+│ ├── variables/test.py
97+│ ├── workflow_generation/test.py
98+│ └── workflow_execution/test.py
99+├── agents/ # architect / developer / verifier
100+├── init.sh # 统一安装器的薄入口
101+├── plugin-sources.json # 公共 Skill 来源与安装方式
102+├── plugin-install.json # 外部依赖仓声明
103+└── skills/
104+ ├── repo-env-check/ # PM 的启动前环境检查
105+ ├── repo-requirement/
106+ │ ├── SKILL.md
107+ │ └── references/requirement-checklist.md
108+ ├── ops-direct-invoke/
109+ │ ├── SKILL.md # 按注册文件选用模板
110+ │ ├── scripts/
111+ │ │ ├── assemble_workflow.py
112+ │ │ └── run_workflow.py
113+ │ ├── tasks/ # <步骤名>.yaml,不带编号
114+ │ └── templates/
115+ │ ├── docs/ # 文档名称.md,不带编号
116+ │ └── workflows/
117+ │ ├── registry.csv # 模板索引与适用条件
118+ │ ├── basic.yaml # 正式开发:task 引用图、依赖和重试预算
119+ │ └── feasibility.yaml # 独立技术穿刺
120+ ├── repo-knowledge/
121+ ├── repo-build-guide/
122+ ├── repo-op-templates/
123+ ├── repo-coding-rules/
124+ └── repo-test-develop/
125+```
126+ 
127+## 任务、模板与运行接口
128+ 
129+必须加载 [ops-direct-invoke](skills/ops-direct-invoke/SKILL.md) Skill,按其中的要求执行。
130+ 
131+- [任务定义](skills/ops-direct-invoke/tasks/)
132+- [模板注册文件](skills/ops-direct-invoke/templates/workflows/registry.csv)
133+- [文档模板](skills/ops-direct-invoke/templates/docs/)
134+- [组装脚本](skills/ops-direct-invoke/scripts/assemble_workflow.py)
135+- [启动脚本](skills/ops-direct-invoke/scripts/run_workflow.py)
136+ 
137+## 知识与范围
138+ 
139+Skill 正文及 references 仅包含自身职责,不互相调用或路由;跨 Skill 组合由 PM 或 task 的 approach/procedure 显式声明。引用处只保留加载条件、Skill 名称及按其要求执行,不复制内部步骤或规则。节点输入、产物路径和验收结果由 task 声明;资源目录引用用于定位文件,不代表调用其所属 Skill。公共领域 Skill 来自 vendor,harness 和统一安装器作为公共基础设施使用。
140+ 
141+角色、task、脚本、仓库知识及交付模板均由本插件独立维护,安装与运行使用本目录声明的资产及公共依赖。
142+ 
143+本仓 `repo-*` 知识按 CANN Bench 的直调工程与评测契约组织,包含需求、环境、接口、模板、构建、测试和编码规则。初始化会获取 `cann-bench` 到 `.cannbot/dependencies/ops-direct-invoke/cann-bench/`,实际运行记录所用 commit;已有 checkout 可作为任务输入复用。跨仓定制继续通过同名 `repo-*` Skill 覆写,不将仓库知识复制进 task。
144+ 
145+当前范围为本地开发、功能验收与交付文档,不包含性能采集、性能迭代及回归复核、性能验收、回顾、经验总结、PR、外部 CI 或合并。需求阶段仍需如实记录性能诉求;用户要求的硬门槛超出当前执行范围时,先对齐交付安排,不能承诺本流程已验证性能。引用业务知识时不启用其中遗留的 PM 派发、状态维护或回退指令。
146+ 
147+## 已知限制与验证
148+ 
149+harness 按黑盒使用,只通过公开 CLI 调用并检查输出。已验证同节点重试及失败阻断;重试耗尽后直接重启相同 work_dir 不能清除耗尽状态。
150+ 
151+Codex provider 的 CLI 替身黑盒测试已确认:当前重试执行提示词与首次相同,不自动附带 verifier 的失败意见;落盘的验收报告保留且下一次执行可读。task 因此明确要求读取该报告返工,不增加调度脚本或修改框架。此测试验证的是 CLI 传参和报告可访问性,不证明真实模型的遵从性,也不代表其他 provider 行为。
152+ 
153+以下能力尚无本流程已验证的完整公开契约:跨节点返工、下游结果失效、运行中问卷等待与恢复。需求问卷在启动前解决;运行中不发问卷或等待 PM。必要输入或确认缺失时记录阻塞,验收失败按 harness 既定重试与耗尽策略处理;PM 在整轮退出后读取结果并组织下一轮,不自行改状态或用私有脚本补齐框架能力。
154+ 
155+工作流 UT 位于 test/ut/,各测试类型统一以 test.py 为入口。test_all.py 自动发现直接子目录的 test.py,执行全部类型并汇总;任一类型失败、缺少入口或没有测试类型时返回非零退出码。新增类型沿用此目录约定即可纳入总入口。
156+ 
157+在 cannbot 根目录运行所有工作流 UT:
158+ 
159+```bash
160+python3 plugins-community/ops-direct-invoke-harness/test/ut/test_all.py
161+```
162+ 
163+可从任意目录调用;测试使用临时工作目录,结束后自动清理。依赖 Python 3.9+、PyYAML 和本仓公共 harness,使用前台模拟执行,不需要 tmux、真实 Agent CLI 或 NPU。harness 位于其它位置时传 `--harness-skill /absolute/workflow-orchestrator`,总入口会透传给每个测试类型。单独执行某类时使用相同参数约定,例如:
164+ 
165+```bash
166+python3 plugins-community/ops-direct-invoke-harness/test/ut/workflow_execution/test.py
167+```
168+ 
169+| 测试类型 | 看护内容 |
170+|---|---|
171+| retry_feedback | 真实 harness 公开 CLI 配合 Codex 替身,验证失败→重试→通过、提示词是否携带失败意见、验收报告可读取;不调用真实模型 |
172+| registry | 注册清单完整且唯一;每项适用条件、引用模板路径、task 路径、节点编号顺序、依赖引用及无环性 |
173+| workflow_generation | 遍历注册项,调用 assemble_workflow.py 生成临时 workflow.yaml;检查顶层及节点字段、类型、字符串 ID 和依赖图,并与引用图、下发预算及原始 task 逐项比对 |
174+| variables | 默认值与必填校验、节点隔离、多行文本及字面替换;拒绝未知变量、非法声明和空提示项 |
175+| workflow_execution | 对每个注册项分别调用 run_workflow.py --template 和 --yaml,后者使用本轮生成的 workflow.yaml;通过 harness --dry-run 验证退出码为 0、预期节点全部通过,且引用模板未被修改、完整 YAML 已落盘并可用于恢复 |
176+ 
177+注册项由 registry.csv 自动读取,不写死基础模板名。新增工作流自动接受相同检查。执行测试只能证明标准 YAML 被框架接受且模拟调度能完成,不证明真实 Agent 执行、业务验收或 NPU 实测通过。测试只通过公开 CLI 与落盘状态观察 harness,不读取内部脚本实现。
178+ 
179+安装与打包集成检查仍可在 cannbot 根目录运行:
180+ 
181+```bash
182+npm --prefix script run build:plugins
183+node --test script/test/harness.test.js
184+npm --prefix script run pack:smoke
185+```
186+ 
187+检查覆盖源码与打包安装、工作区 PM 指引与重复初始化、客户端角色配置、模板注册资源、模板与 task 一致性、引用模板展开及完整 YAML 两种启动方式、外部 task 与不同顺序组装、并行汇合、成功路径、同节点重试、验收失败阻断、耗尽后重启、多轮 Workflow 状态隔离、前后台参数与退出结果,以及独立源码布局下的安装运行。实际 npm 包还会安装后直接选择内置模板并模拟执行。格式与模拟检查不证明问卷交互、真实 provider 角色权限或 NPU 功能实测已经通过。
@@ -0,0 +1,33 @@
1+---
2+name: ops-direct-invoke-architect
3+description: 架构师,负责知识搜集与方案设计
4+mode: all
5+---
6+ 
7+# 架构师
8+ 
9+## 工作目录
10+ 
11+本角色产生的所有文档与分析记录,必须放在 `$WORK_DIR` 路径下。
12+ 
13+阶段中间报告文件名必须以当前节点 ID 加 `-` 开头,具体路径以当前任务为准;引用上游报告时保留其产出节点的 ID。
14+ 
15+## 职责
16+ 
17+### 负责
18+ 
19+知识搜集与方案设计。
20+ 
21+### 不负责
22+ 
23+代码编写。
24+ 
25+## 权限
26+ 
27+### 可以写
28+ 
29+`$WORK_DIR` 下当前任务授权的知识记录、方案草稿与分析记录。
30+ 
31+### 不可以写
32+ 
33+算子代码、测试实现、需求清单、其他角色的验收报告及调度状态。
@@ -0,0 +1,33 @@
1+---
2+name: ops-direct-invoke-developer
3+description: 开发者,负责代码开发、调试
4+mode: all
5+---
6+ 
7+# 开发者
8+ 
9+## 工作目录
10+ 
11+本角色产生的所有中间产物,必须放在 `$WORK_DIR` 路径下。算子代码、测试代码及算子使用文档等交付件,放在目标仓约定目录中。
12+ 
13+阶段中间报告文件名必须以当前节点 ID 加 `-` 开头,具体路径以当前任务为准;引用上游报告时保留其产出节点的 ID。
14+ 
15+## 职责
16+ 
17+### 负责
18+ 
19+代码开发、调试、测试执行及文档编写。按 task 完成构建和指定范围的测试,提供当前源码、测试与构建产物版本对应的原始证据;不把自测记录写成验收者结论。
20+ 
21+### 不负责
22+ 
23+需求确认、方案决策、独立验收及流程调度。不能更改已确认的需求;知识搜集草稿可依据实现与验证结果调整,不得放宽指标或阈值,不得派发其他 Agent。
24+ 
25+## 权限
26+ 
27+### 可以写
28+ 
29+目标仓约定目录中当前任务授权的算子代码、测试代码及使用文档;`$WORK_DIR` 下当前任务授权的调试记录、临时构建产物及报告。
30+ 
31+### 不可以写
32+ 
33+已确认的需求清单、上游方案文档、验收者报告、调度状态及当前任务范围以外的文件。
@@ -0,0 +1,34 @@
1+---
2+name: ops-direct-invoke-verifier
3+description: 验收者,负责所有环节的验收
4+mode: all
5+---
6+ 
7+# 验收者
8+ 
9+## 工作目录
10+ 
11+本角色产生的所有文件,必须放在 `$WORK_DIR` 路径下。
12+ 
13+阶段中间报告文件名必须以当前节点 ID 加 `-` 开头,具体路径以当前任务为准;引用上游报告时保留其产出节点的 ID。
14+ 
15+## 职责
16+ 
17+### 负责
18+ 
19+验收及代码检视。核对执行者的原始日志、本阶段要求的用例结果与当前源码/测试/构建产物版本、运行时加载路径;不重复构建或执行测试。所有结论都需要给出证据,所有违反规范、条款的内容,需要指出对应内容的位置。
20+核对真实产物和可复核证据,给出结论、问题位置、依据和修改建议;证据缺失、版本不符、缺少必要确认或存在未解决的阻断问题时不得通过。所有节点都必须产出当前节点 ID 前缀的验收报告;失败时给出具体修改意见,验收者独立核对产物,不用执行者的自述代替证据。
21+ 
22+### 不负责
23+ 
24+任何开发与修复、构建安装、测试执行、需求和方案决策及流程调度。不得放宽验收标准,不派发其他 Agent。
25+ 
26+## 权限
27+ 
28+### 可以写
29+ 
30+`$WORK_DIR` 下当前任务授权的验收或检视报告、复现记录、临时探针及验证临时文件。
31+ 
32+### 不可以写
33+ 
34+被验收的算子代码、测试实现、需求清单、设计文档及其他交付件,其他角色的报告及调度状态。
@@ -0,0 +1,17 @@
1+#!/usr/bin/env bash
2+# ----------------------------------------------------------------------------
3+# Copyright (c) 2026 Huawei Technologies Co., Ltd.
4+# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
5+# CANN Open Software License Agreement Version 2.0 (the "License").
6+# Please refer to the License for details. You may not use this file except in compliance with the License.
7+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
8+# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
9+# See LICENSE in the root of the software repository for the full text of the License.
10+# ----------------------------------------------------------------------------
11+ 
12+set -euo pipefail
13+PLUGIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
14+if [[ -f "${PLUGIN_DIR}/../../script/bin/source-plugin-init.sh" ]]; then
15+ exec bash "${PLUGIN_DIR}/../../script/bin/source-plugin-init.sh" "${PLUGIN_DIR}" "$@"
16+fi
17+exec bash "${PLUGIN_DIR}/../../../bin/source-plugin-init.sh" "${PLUGIN_DIR}" "$@"
@@ -0,0 +1,24 @@
1+{
2+ "dependencies": [
3+ {
4+ "name": "asc-devkit",
5+ "repository": "https://gitcode.com/cann/asc-devkit.git",
6+ "ref": "master",
7+ "cleanMarkdownWithSkill": "ascendc-docs-search"
8+ },
9+ {
10+ "name": "cann-samples",
11+ "repository": "https://gitcode.com/cann/cann-samples.git"
12+ },
13+ {
14+ "name": "ops-tensor",
15+ "repository": "https://gitcode.com/cann/ops-tensor.git",
16+ "recursive": true
17+ },
18+ {
19+ "name": "cann-bench",
20+ "repository": "https://gitcode.com/cann/cann-bench.git",
21+ "ref": "master"
22+ }
23+ ]
24+}
@@ -0,0 +1,29 @@
1+{
2+ "skillsRepository": ".",
3+ "skillInstallMode": "symlink",
4+ "skills": [
5+ "harness/workflow-orchestrator",
6+ "vendor/cannbot-skills/ops/ascendc-api-best-practices",
7+ "vendor/cannbot-skills/ops/ascendc-blaze-best-practice",
8+ "vendor/cannbot-skills/ops/ascendc-crash-debug",
9+ "vendor/cannbot-skills/ops/ascendc-direct-invoke-template",
10+ "vendor/cannbot-skills/ops/ascendc-docs-gen",
11+ "vendor/cannbot-skills/ops/ascendc-docs-search",
12+ "vendor/cannbot-skills/ops/ascendc-env-check",
13+ "vendor/cannbot-skills/ops/ascendc-mc2-best-practice",
14+ "vendor/cannbot-skills/ops/ascendc-performance-best-practices",
15+ "vendor/cannbot-skills/ops/ascendc-precision-debug",
16+ "vendor/cannbot-skills/ops/ascendc-regbase-best-practice",
17+ "vendor/cannbot-skills/ops/ascendc-simt-best-practices",
18+ "vendor/cannbot-skills/ops/ascendc-simt-tiling-design",
19+ "vendor/cannbot-skills/ops/ascendc-st-design",
20+ "vendor/cannbot-skills/ops/ascendc-tiling-design",
21+ "vendor/cannbot-skills/ops/ascendc-ut-develop",
22+ "vendor/cannbot-skills/ops/ascendc-whitebox-design",
23+ "vendor/cannbot-skills/ops/cann-env-setup",
24+ "vendor/cannbot-skills/ops/npu-arch",
25+ "vendor/cannbot-skills/ops/ops-precision-standard",
26+ "vendor/cannbot-skills/ops/ops-profiling",
27+ "vendor/cannbot-skills/ops/ops-simulator"
28+ ]
29+}
@@ -0,0 +1,225 @@
1+---
2+name: ops-direct-invoke
3+description: 根据已确认的需求清单选择直调算子工作流模板,组装 workflow YAML 并通过脚本启动 harness 执行。
4+---
5+ 
6+# 直调算子开发
7+ 
8+本 Skill 根据模板注册文件选择引用模板,将 tasks 展开为完整 workflow YAML 后启动执行。每个 `tasks/<步骤名>.yaml` 只收录节点的 9 个必填任务字段、可选 procedure 与 variables 声明(当前均提供),不包含 id、depends_on 或 max_retries。模板提供节点引用、依赖与下发时确定的重试次数;task 决定具体执行和验收内容。组装完成后,调度交给 harness。
9+ 
10+## 启动前置条件
11+ 
12+本 Skill 接收调用方已对齐的需求清单 `work_dir/需求分析.md` 和 PM 从仓库级缓存复制的只读环境记录 `work_dir/环境信息.md`。启动前确认内容完整、无待决阻断项,且用户答复覆盖当前版本;已有有效清单与确认可直接复用。仓库级环境结果固定为 `<目标仓>/.cannbot/环境信息.md`,存在通过记录时直接复用,不因新算子重复校验;首次检查与缓存规则由调用方执行。
13+ 
14+需求分析与环境检查不属于 tasks。存在未答问卷或缺失信息时,将缺项报告给调用方,不组装或启动工作流,不用 silent 或默认选项代替用户拍板。
15+ 
16+## 运行输入
17+ 
18+沿用用户已经提供的目标代码仓绝对路径、算子名、原始需求、目标芯片、相关资料路径、已明确的架构选择与确认记录。把这些业务信息和已确认需求清单、环境检查记录的绝对路径、版本及确认摘要组织成传给 harness 的原始任务 prompt,不增加运行时私有输入文件或环境变量。任务提示中引用文件时使用绝对路径。
19+ 
20+确认 provider、work_dir 和所选 workflow 模板的绝对路径。缺少启动所需信息时先向用户询问。work_dir 必须设为目标仓下 `.cannbot/<任务名>/workflow<序号>/` 的绝对路径,目录由调用方按任务与执行轮次分配。除仓库级环境缓存与首次检查日志外,所有本轮开发中间产物(需求、设计、报告、日志、临时探针、构建临时文件和框架状态)必须放在此目录下;代码、测试和使用文档等算子交付件写入目标代码仓约定目录。使用独立工作目录及 checkout 隔离不同任务,避免覆盖已有运行。
21+ 
22+工作流启动后不与 PM 或用户交互。各节点只使用已确认输入、固定 Skill 和本阶段下发清单,不发问卷、不等待答复,也不修改本轮 YAML。必要输入、确认或能力缺失时,executor 停止受阻操作,将证据写入本阶段报告并按 harness 原生执行协议结束;verifier 无法确认交付标准满足时判定失败,由 harness 按既定预算和耗尽策略处理。记录阻塞不代表交付通过。
23+ 
24+PM 仅在启动前确定输入与清单、整轮退出后读取结果并处理补充确认或下一轮编排。运行中可以只读观察日志、向用户汇报进度,不向节点补发指令。
25+ 
26+## 先查注册文件,再选择调度模板
27+ 
28+**每次启动前先读取 [templates/workflows/registry.csv](templates/workflows/registry.csv),确认当前有哪些工作流模板,按已确认的需求核对 use_when 中的建议使用场景,再选择其中一个。** 不凭记忆假定模板存在,也不直接把 tasks 目录的文件全部拼起来。选择后向用户说明模板名称及匹配理由;用户已授权开发且条件明确时无需额外审批。
29+ 
30+注册文件采用 CSV,仅包含 file(模板文件)与 use_when(建议使用场景)两列。节点图只在 file 指向的引用模板内维护,不在注册文件重复。file 相对 templates/workflows/;模板中的节点 yaml 路径相对该模板文件。
31+ 
32+当前注册 [basic](templates/workflows/basic.yaml)(正式开发)和 [feasibility](templates/workflows/feasibility.yaml)(独立技术穿刺)。PM 在需求确认与环境核对后,按证据选择:
33+ 
34+- 路线已有适用实现或有效设备证据、无关键技术疑点:启动 basic。
35+- API 组合、目标芯片适配或关键端到端链路尚无运行证据:先独立启动 feasibility,不同时展开完整黑盒矩阵与测试工程。判断依据是技术缺口,不是算子名字或复杂程度标签。
36+- 已知 Skill 规则冲突、必要权限或平台能力缺失:启动前先处理。不能靠穿刺绕过规则,也不能把资料调查通过当作路线验证通过。
37+ 
38+PM 用 feasibility 的 `spike_scope` 明确候选路线、关键疑点和代表用例范围,`task_requirements` 指定可复用资产及授权路径,分别绑定执行/验收 Skill。默认穿刺验证完整关键组合;例如 GQA 须覆盖 QK→Softmax→PV 的组合与同步,不以各 API 分别存在替代。范围可缩小,用户确认的接口、架构、精度和单 Kernel 等约束不降低。
39+ 
40+穿刺验收通过后,PM 新建下一轮目录,复制有效需求和环境输入;在 basic 相关节点的 `task_requirements` 中填入前轮代码、测试入口、证据的绝对路径、版本和适用范围,保留前轮原始证据。测试工程复用入口并扩展覆盖,算子开发复用有效实现;本轮仍完成正式全量验收。已有知识文档通过 `knowledge_documents` 传入,可省略重复搜集。穿刺失败时不启动完整开发;根据原因处理规则/环境阻塞或调整已授权候选,新一轮仍需真实穿刺证据。
41+ 
42+PM 在下发前确定各节点的 max_retries,模板默认允许 3 次重试(首次执行加重试,最多 4 轮);需要调整时在本轮引用图中修改,不改 task。仓内无已有算子文档时,从本轮引用图移除最后的文档准备节点,保留其他节点及验收;不新增模板或凭空创建文档。PM 编排时检查目标仓当前文档,不将历史环境缓存中的文档现状当成永久事实。
43+ 
44+basic 默认知识搜集与黑盒测试设计并行;两者通过后依次进行测试工程开发、算子开发、白盒测试设计、代码修复、文档准备。代码修复是 basic 的默认节点,没有待修复缺陷且已有当前版本的有效全量证据时,核对并复用,记录无需修改;证据不满足条件时补齐验证。每个节点已包含执行与验收,不另设 CP。
45+ 
46+知识搜集是可选步骤。PM 可移除本轮图中的知识搜集节点及依赖边,将黑盒测试设计改为 `0`,测试工程依赖 `0`,后续仍为 `1`~`5`。算子开发通过 `knowledge_documents` 接收中立补充文档的路径;可以引用前轮产物,也可以为“无补充文档。”,不再要求同图知识搜集上游。basic 的默认值指向 `$WORK_DIR/0.0-知识搜集.md`;删去节点或改变编号时,PM 同步清空或更新该变量。
47+ 
48+知识搜集产物是可溯源的资料与初版实现草稿,开发可根据验证调整 API、Tiling 和分支处理,不要求照搬草稿;已确认需求仍是约束。测试工程先准备黑盒用例,算子开发由 executor 构建并执行全量黑盒,verifier 核对证据和检视代码。白盒在实现后依据源码生成可执行用例并接入已有框架。
49+ 
50+白盒节点验收的是用例质量、框架接入及真实证据;正确用例暴露的算子缺陷记录后交下游修复,不能将该节点通过表述为算子功能通过。测试或框架自身问题仍会阻断。代码修复验收要求最终全量黑盒、白盒回归与代码检视通过,之后才能进入文档交付。
51+ 
52+若没有适用模板,说明具体差异,不擅自套用模板或删除验收。在用户已授权范围内,按本轮交付缺口选择任务、明确依赖与预算,在当前 work_dir 组装并验证一次性 YAML。只有要发布为可复用模板时,才更新 tasks、模板及注册文件;运行期不修改已安装的共享资源。
53+ 
54+## 维护工作流模板
55+ 
56+引用具体 Skill 时,只写“必须加载 `<skill-name>` Skill,按其中的要求执行”,不复制其内部步骤、规则或知识。固定必需项写在 task;PM 选定与芯片、架构及已知问题匹配的专项必需项,分别绑定 `executor_skills`、`verifier_skills`。设计和文档任务以明确加载为主;算子开发、代码修复可在同一变量中接收有限候选清单及可观察的触发条件,按实际证据选择,task 不重复维护具体场景路由。节点输入、交付件和验收标准仍由 task 声明。引用文档模板只是读取资源。
57+ 
58+知识搜集可以记录有依据的 Skill 建议及适用节点、执行/验收阶段,供 PM 在整轮退出后编排下一轮时参考;本轮下游仍使用启动前绑定的清单,不从报告自动加载新增 Skill。资料不足时可先独立组织知识搜集;该节点只交付中立参考。关键路线需要实测时选择 feasibility,不能连续用资料调查替代编译和设备验证。节点可在已下发候选内按证据选择;清单外能力仅有帮助时记为建议,缺少它导致交付标准无法满足时记录阻塞并验收失败。
59+ 
60+**task 编写原则:具体流程步骤集中在 approach(执行)和 procedure(验收);acceptance 只写简短的结果标准,明确交付件,不放资料读取、操作顺序、检查方法或异常处理。涉及文件交付件时,acceptance 先列 `test -s` 非空检查,再列内容与质量结果。** 固定报告使用明确的 `$WORK_DIR/<产出节点ID>-<文件名>`;源码、测试和使用文档沿用已确认的项目布局,其检查命令所需小写 shell 变量在 approach/procedure 中用实际绝对路径赋值,不新增 harness 输入字段。多文件交付逐文件检查,不能用目录或任意非空文件代替。共享 acceptance 只列执行者交付件与质量结果;验收报告不放入 executor 的交付清单。所有节点的 procedure 明确由 verifier 写入 `$WORK_DIR/<id>-验收报告.md` 后执行 `test -s`,通过、失败及阻塞均落盘。executor 不生成或等待验收报告,只在重试开始时读取已有报告的修改意见。
61+ 
62+引用模板格式如下;goal、approach、procedure、acceptance、角色及其它任务内容都从 task YAML 读取,不能复制进模板:
63+ 
64+```yaml
65+workflow: ops-direct-invoke
66+max_parallel: 2
67+nodes:
68+- id: '0'
69+ yaml: ../../tasks/知识搜集.yaml
70+ depends_on: []
71+ max_retries: 3
72+ variables:
73+ research_focus: 重点搜集目标芯片的 API 组合和小 shape 的 Tiling 依据。
74+```
75+ 
76+- 节点提供 id、yaml、depends_on、max_retries,可选 variables;max_retries 必须是非负整数,由下发方明确决定,不从 task 获取或隐式补默认值。
77+- id 和 depends_on 使用字符串。节点 id 按最长依赖路径分层,单节点层使用数字,同层并行节点使用数字.分支序号;按编号排序。组装器生成 ID 并核对其与模板声明一致,发现重复、未知依赖、环或编号不符时拒绝生成。
78+- `scripts/assemble_workflow.py --template <引用模板路径> --output <本轮完整YAML路径>` 按模板文件的位置解析 task 路径,展开具体内容与报告编号。输出只包含 harness 标准字段,不包含 yaml 引用或 variables 声明。
79+- PM 需修改预算、设置变量或省略文档节点时,将选中的引用图存为本轮 `workflow<序号>.template.yaml`,其中 task 路径转换为实际绝对路径,再调整本轮图并组装为 `workflow<序号>.yaml`。不修改已安装的共享模板或 task。
80+- 脚本也接受按任意顺序提供的 task 文件位置,必须同时传 `--max-retries N` 为本次所有输入设置明确预算;不同节点预算和变量值用引用模板声明。默认顺序串行,`--depends-on N:M,K` 覆盖第 N 个输入的依赖,`N:` 表示无依赖,位置从 1 开始。重复 task 可出现在不同节点,产物编号分别展开。
81+- task 的 procedure 若提供,必须为非空字符串列表。goal 写简短目标,approach 为执行步骤,procedure 为独立验收步骤,acceptance 为双方共享的结果标准。
82+- 更新 task 后,无需手工同步模板正文;下次组装读取最新 task 内容。已经生成的运行 YAML 保持不变,避免改变正在执行或恢复中的流程。
83+- 所有组装输出都使用新文件,拒绝覆盖。恢复使用原完整 YAML 和 work_dir;新一轮使用新目录,保留前轮状态与证据。
84+ 
85+## task 提示词变量
86+ 
87+每个 task YAML 顶部用 `variables` 声明变量;正文在需要填入提示词的固定位置写 `{{var:变量名}}`。变量在该节点内全局可见,不跨节点共享。相同 task 被引用多次时分别绑定。所有 task 提供以下三个变量;技术穿刺额外提供必填的 `spike_scope`,知识搜集提供 `research_focus`,算子开发提供可选的 `knowledge_documents`,代码修复提供必填的 `repair_requirements`。
88+ 
89+| 变量 | 注入位置 | 填写内容 |
90+|---|---|---|
91+| `task_requirements` | approach、procedure | 执行与验收共同遵守的本轮补充要求 |
92+| `executor_skills` | 仅 approach | 执行阶段专项必需项;开发、修复可附有限候选与触发条件 |
93+| `verifier_skills` | 仅 procedure | 验收阶段专项必需项;必要时附仅用于证据分析的候选与触发条件 |
94+| `spike_scope` | 技术穿刺的 approach、procedure | 本轮候选路线、关键疑点及代表用例范围;引用模板提供默认范围,PM 下发前具体化 |
95+| `knowledge_documents` | 算子开发的 approach | 中立补充知识文档路径;无资料时为“无补充文档。”,允许引用前轮文件 |
96+ 
97+补充 Skill 变量填写完整指令,例如“必须加载 `ascendc-simt-tiling-design` Skill,按其中的要求执行。”;多项可用多行文本。无补充项明确填写“无补充 Skill。”,也是 task 的默认值。专项必需项不留待节点重新决定;候选项必须逐项给出 Skill 名称和可观察的触发条件,不写“自行寻找合适 Skill”。命中才加载,未命中无需加载,多个独立条件有证据时可分别命中。加载项及选择依据写入当前阶段已有报告,无加载则记无;不新增报告文件或调度状态。不把阶段专用 Skill 放入双方共享的 `task_requirements`。
98+ 
99+PM 核对 task 固定项与补充必需项、候选均已安装、适用当前平台且符合角色权限,不重复下发固定 Skill。组合还须核对公开调用入口与产物契约:含完整开发流程的 Skill 不作为普通知识补充;只有明确支持资料查询入口时才限定使用该入口,否则按完整契约编排或报告阻塞。引用仍只写加载要求,不复制 Skill 内部步骤,不用本仓提示词豁免其规则。候选使用不扩大写入权限、不改变任务、验收标准、依赖或重试;verifier 只分析证据和判定,不修复对象、不重新构建或运行测试。必需能力超出清单、所需 Skill 不可用或能力不足时,按上述运行阻塞规则处理,不等待补发。
100+ 
101+basic 只在算子开发、代码修复的 `executor_skills` 中提供精度错误和卡死/崩溃的候选,默认不为 verifier 或其他节点添加决策树。PM 在本轮引用图中核对、增删候选;使用自定义变量会整体替换该节点的原值,需要保留的候选须一并写入。
102+ 
103+代码修复 task 的声明与正文示例(节选):
104+ 
105+```yaml
106+variables:
107+ task_requirements: 无额外要求。
108+ repair_requirements: null
109+ executor_skills: 无补充 Skill。
110+ verifier_skills: 无补充 Skill。
111+approach:
112+- '{{var:executor_skills}}'
113+- '本轮修复要求:{{var:repair_requirements}}'
114+procedure:
115+- '{{var:verifier_skills}}'
116+- '本轮修复要求:{{var:repair_requirements}}'
117+```
118+ 
119+PM 在引用该 task 的 workflow 节点中赋值;例如单独组织一轮修复时:
120+ 
121+```yaml
122+workflow: ops-direct-invoke
123+max_parallel: 1
124+nodes:
125+- id: '0'
126+ yaml: /absolute/skills/ops-direct-invoke/tasks/代码修复.yaml
127+ depends_on: []
128+ max_retries: 3
129+ variables:
130+ executor_skills: |
131+ 必需:必须加载 `ascendc-precision-debug` Skill,按其中的要求执行。
132+ 候选:复现出现卡死、超时或崩溃时,必须加载 `ascendc-crash-debug` Skill,按其中的要求执行。
133+ verifier_skills: 无补充 Skill。
134+ repair_requirements: |
135+ 修复 /absolute/repo/op_kernel/abs_kernel.cpp 的尾块结果错误。
136+ 复现证据:/absolute/repo/.cannbot/abs/workflow1/3-验收报告.md。
137+ 使用已有 ST 框架回归,不修改精度阈值。
138+```
139+ 
140+- 变量名只允许字母、数字和下划线,首字符不能是数字。默认值为字符串时可以省略赋值;默认值为 null 时必须提供非空字符串。显式赋值仅接受字符串,多行内容使用 YAML `|`。
141+- 只在 goal、approach、procedure、acceptance、out_of_scope 的文本项中替换。角色、依赖、预算等字段不使用变量;模板仍需显式声明调度信息。
142+- 未声明引用、未知赋值、必填缺失、非文本值、重复 YAML 键、错误占位符或替换后空提示项都会拒绝组装,不输出部分 workflow。
143+- 先展开 task 正文里的报告 ID,再一次性替换变量。变量值作为普通文本原样插入,不再解释其中的占位符、shell 表达式或 Python 代码;需引用前轮报告时由 PM 填写实际路径。
144+- variables 只用于组装,展开后从完整 YAML 移除。harness 接收标准节点字段,无需改动框架。运行中的 YAML 保持冻结,后续变量调整只能用于新的组装输出。
145+ 
146+## 中间报告编号
147+ 
148+所有节点输出的中间报告按 `<产出节点ID>-<报告名>` 命名。同一节点的执行报告与验收报告使用同一 ID;引用上游报告时使用产出节点的 ID。文档模板源文件保持无编号,启动前的 `需求分析.md` 和 `环境信息.md` 作为运行输入沿用原名。
149+ 
150+子 task 不写死数字:自身报告路径使用 `$WORK_DIR/{{id}}-报告名.md`;上游报告路径使用 `$WORK_DIR/{{id:上游任务title}}-报告名.md`。组装脚本在分配节点 ID 后展开这些标记,所有说明和 `test -s` 引用同步替换。传给 harness 的 YAML 只含具体编号,不新增运行时变量或 harness 字段。
151+ 
152+知识补充文档通过 `knowledge_documents` 按路径输入,不使用上游 ID 占位符;其他必需上游引用按依赖关系解析,重跑同名上游任务时取依赖链中最新的一次;有多个并行同名产出者或缺少产出者时拒绝组装。局部或后续轮次引用外部报告时,在本轮 task 中明确填写已存在的实际路径。改变节点顺序或依赖后重新组装,不手工修改生成模板中的编号。
153+ 
154+例如基础模板输出 `0.0-知识搜集.md`、`0.1-黑盒测试设计.md`、`1-测试工程说明.md`、`2-实现记录.md`、`2-测试执行记录.md`、`3-白盒测试设计.md`、`3-测试执行记录.md`、`4-修复记录.md` 和 `4-测试执行记录.md`。全部节点另由 verifier 产出 `<id>-验收报告.md`;算子开发还产出 `2-代码检视报告.md`。
155+ 
156+## 报告与返工范围
157+ 
158+报告按当前阶段交付标准填写:知识搜集保留关键引用、建议与未知项;穿刺复用测试执行记录,提交最小代码和代表用例设备证据;正式开发保留全量测试证据与代码检视。报告只列关键结论、变更和证据路径,原始输出、用例明细与文件哈希清单单独保存,不在多份报告中重复全文。知识节点不要求所有检索文件的哈希或与关键结论无关的网络快照。
159+ 
160+每次真实构建或测试只维护一份带节点 ID 和执行轮次的证据清单,记录输入版本与原始结果索引;其格式与复用判据见测试执行记录模板。后续节点引用具体清单与结果,并记录差异核对,不抄录整份明细。代码修复节点始终执行,但满足复用条件时无需重复构建和测试,verifier 仍独立出具本节点报告。
161+ 
162+重试先读同节点验收报告,只修复未解决项。输入与产物版本未变且证据有效的内容可引用复用;源码、测试、golden、构建配置或环境变化导致执行证据失效时,按当前 task 重新验证,正式交付仍要求全量通过。verifier 复核当前版本与受影响项,追加结论并保留历史,不重新开展整轮资料搜集或构建测试。
163+ 
164+已知规则冲突等确定性阻塞条件未变时,执行者仅记录复核与条件缺口,验收者保持失败,不重复完整调查。当前公开接口只有 pass/fail,此约定不会跳过 harness 的重试;默认仍最多重试 3 次,耗尽后由 PM 处理,不新增失败类型或私有调度器。
165+ 
166+## 文档模板
167+ 
168+文档模板统一存放在本 Skill 的 templates/docs/,文件名只使用文档名称,不带步骤编号。执行和验收角色按 task 中给出的 `ops-direct-invoke/templates/docs/<文档名>.md` 定位已安装的资源并直接读取,不为使用模板重新执行入口或启动工作流。
169+ 
170+| 文档 | 模板 |
171+|---|---|
172+| 知识搜集 | [知识搜集](templates/docs/知识搜集.md) |
173+| 黑盒测试设计 | [黑盒测试设计](templates/docs/黑盒测试设计.md) |
174+| 白盒测试设计 | [白盒测试设计](templates/docs/白盒测试设计.md) |
175+| 测试执行记录(executor) | [测试执行记录](templates/docs/测试执行记录.md) |
176+| 验收报告(verifier,全部节点) | [验收报告](templates/docs/验收报告.md) |
177+| 功能证据核对参考(verifier) | [功能验收报告](templates/docs/功能验收报告.md) |
178+| 代码检视报告 | [代码检视报告](templates/docs/代码检视报告.md) |
179+ 
180+模板规定交付格式,验收标准在 task 的 acceptance 中。文档和报告按已组装 task 声明的带阶段 ID 的 $WORK_DIR 路径落盘,算子文档按仓内已有格式写入既定目录,无已有算子文档时不创建;需求清单由调用方维护。产物须与当前需求、实际代码和精度口径一致;知识草稿的假设、建议及后续实现调整须如实区分,问题及依据写入对应报告;超出当前任务范围的失效产物列明问题,不自行派发或批准继续。未开展的性能测量、回顾和经验总结不得填成已完成。
181+ 
182+## 交给 harness 执行
183+ 
184+先按注册场景完成路线判断,准备本轮需求、环境记录与任务 prompt,核对选中模板的 Skill 清单、范围、预算及节点。以下以 basic 启动为例;独立穿刺将模板改为 feasibility.yaml。需要调整 Skill 清单或节点图时,使用下方的本轮自定义引用图方式。脚本先在 work_dir 下生成与目录同名的完整 YAML,例如 `workflow1/workflow1.yaml`,再通过 harness 公开 CLI 执行:
185+ 
186+```bash
187+python3 scripts/run_workflow.py \
188+ --template basic.yaml \
189+ --work-dir /absolute/operator-repo/.cannbot/abs/workflow1 --provider codex \
190+ --harness-skill /absolute/installed-skills/workflow-orchestrator \
191+ --prompt-file /absolute/operator-repo/.cannbot/abs/workflow1/original-task.txt
192+```
193+ 
194+`--template` 相对本 Skill 的 templates/workflows/,与当前目录无关;只能指向该目录内的引用模板。引用模板通过组装脚本展开,harness 始终收到完整 YAML。模板不因启动而修改,输出文件已存在时拒绝覆盖,并提示使用 `--yaml` 恢复。
195+ 
196+使用本轮自定义引用图时先组装,再启动;恢复同一轮也使用 `--yaml` 指向已经生成的完整文件:
197+ 
198+```bash
199+python3 scripts/assemble_workflow.py \
200+ --template /absolute/operator-repo/.cannbot/abs/workflow1/workflow1.template.yaml \
201+ --output /absolute/operator-repo/.cannbot/abs/workflow1/workflow1.yaml
202+python3 scripts/run_workflow.py \
203+ --yaml /absolute/operator-repo/.cannbot/abs/workflow1/workflow1.yaml \
204+ --work-dir /absolute/operator-repo/.cannbot/abs/workflow1 --provider codex \
205+ --harness-skill /absolute/installed-skills/workflow-orchestrator \
206+ --prompt-file /absolute/operator-repo/.cannbot/abs/workflow1/original-task.txt
207+```
208+ 
209+`--yaml` 与 `--template` 互斥且必选其一。`--yaml` 只接受完整 harness YAML,不展开引用或修改预算。脚本不自动选择模板、决定重试次数或判断文档是否需要;这些由 PM 在下发前确定。
210+ 
211+`--prompt-file` 的 UTF-8 内容原样作为 harness 的 `--prompt` 参数传递,也可直接使用 `--prompt '任务内容'`,二者互斥。首次运行必须提供原始任务;再次调用已有运行时可省略,由 harness 决定恢复行为。省略 prompt 不会清除耗尽状态。
212+ 
213+`--harness-skill` 默认取启动脚本调用路径所在安装 Skill 的同级 workflow-orchestrator 目录;直接从源码目录调用或布局不同时显式指定。脚本只调用该目录下公开的 orchestrator.py CLI,不读取或修改内部实现。
214+ 
215+默认使用 tmux 后台启动,返回会话名及 work_dir/orchestrator.log。启动成功不代表任务执行成功:用脚本打印的 tmux has-session 命令检查会话,结束后完整回传日志及其中的 exit status。同一 work_dir 使用固定会话名,已有活动会话时启动失败,不覆盖其运行。
216+ 
217+加 `--foreground` 可前台运行,直接输出 harness 日志并返回其退出码;加 `--dry-run` 透传原 harness 的模拟执行选项。启动脚本不自行重试或读写调度状态。
218+ 
219+每个普通节点先由 executor 执行,再由 verifier 按 acceptance 验收。harness 把 goal、acceptance 和 out_of_scope 发给两者,把 approach 仅发给 executor,把 procedure 仅发给 verifier。executor 据共享标准交付,负责构建与本阶段规定的测试范围(穿刺为代表用例,正式交付为全量),按测试执行模板保存命令、退出码、源码/测试/构建产物哈希、加载路径及逐用例原始结果。verifier 只读核对证据有效性及交付物质量,并独立检视代码;不重复构建或测试,不接受只有通过自述的证据。验收报告只由 verifier 交付。执行器最终回复 executed,验证器最终回复 pass/fail;调度、同节点重试和耗尽处理均使用框架原生机制。
220+ 
221+整轮退出后,PM 读取日志、退出结果和真实产物,汇总已完成步骤及阻塞证据。交付目标未满足时,使用 workflow2 等新目录规划下一轮必要的修复与验收;前轮确认有效的输入可复制到本轮固定路径并记录来源,前轮状态不得复制或重置。已通过 Codex CLI 替身黑盒探测:当前 harness 重试时下发相同的执行提示词,不自动注入 verifier 的修改意见。因此所有 task 在执行开始时读取已有 `<id>-验收报告.md`;verifier 在返回 pass/fail 前落盘具体意见,报告作为普通任务产物,不参与调度状态。该测试不证明真实模型一定遵守读取指令。跨节点回退、下游失效及用户待答恢复仍无本流程已验证的契约,不另写状态机或调度脚本。
222+ 
223+入口由工作区 PM 在当前用户会话中承接;PM 不进入调度图。节点角色仅使用 ops-direct-invoke-architect(方案)、ops-direct-invoke-developer(代码、调试与文档)及 ops-direct-invoke-verifier(验收与检视)。角色信息由安装后的客户端角色配置和 executor/verifier 名称衔接,不在任务里额外要求读取 agents 文件。真实 provider 的角色和 Skill 加载仍需验证,模拟执行通过不代表角色权限或 NPU 实测通过。
224+ 
225+范围包含本地开发与交付;不包含性能采集、迭代、回归复核、性能验收、回顾、经验总结、PR、外部 CI 和合并。Skill 正文和参考资料只描述自身职责,不调用或路由到其他 Skill;跨 Skill 的组合由 Agent 或 task 的 approach/procedure 显式声明。
@@ -0,0 +1,296 @@
1+#!/usr/bin/env python3
2+# ----------------------------------------------------------------------------
3+# Copyright (c) 2026 Huawei Technologies Co., Ltd.
4+# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
5+# CANN Open Software License Agreement Version 2.0 (the "License").
6+# Please refer to the License for details. You may not use this file except in compliance with the License.
7+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
8+# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
9+# See LICENSE in the root of the software repository for the full text of the License.
10+# ----------------------------------------------------------------------------
11+ 
12+"""Assemble task files, assigning numeric IDs by dependency layer and parallel branch."""
13+import argparse
14+import logging
15+import re
16+import sys
17+from pathlib import Path
18+ 
19+import yaml
20+ 
21+LOGGER = logging.getLogger(__name__)
22+ 
23+TASK_FIELDS = {'task_type', 'title', 'goal', 'approach', 'acceptance',
24+ 'out_of_scope', 'executor', 'verifier', 'on_exhaust'}
25+ 
26+ 
27+VARIABLE_NAME = re.compile(r'[A-Za-z_][A-Za-z0-9_]*')
28+VARIABLE_REFERENCE = re.compile(r'\{\{var:([A-Za-z_][A-Za-z0-9_]*)\}\}')
29+ 
30+ 
31+class UniqueLoader(yaml.SafeLoader):
32+ """Reject duplicate YAML keys instead of silently losing task instructions."""
33+ 
34+ 
35+def unique_mapping(loader, node):
36+ result = {}
37+ for key_node, value_node in node.value:
38+ key = loader.construct_object(key_node)
39+ if not isinstance(key, str) or key in result:
40+ raise ValueError(f'non-string or duplicate YAML key: {key!r}')
41+ result[key] = loader.construct_object(value_node)
42+ return result
43+ 
44+ 
45+UniqueLoader.add_constructor(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, unique_mapping)
46+ 
47+ 
48+def load_yaml(path):
49+ """Use only SafeLoader constructors, with duplicate-key validation."""
50+ loader = UniqueLoader(path.read_text(encoding='utf-8'))
51+ try:
52+ return loader.get_single_data()
53+ finally:
54+ loader.dispose()
55+ 
56+ 
57+def bind_variables(declarations, supplied):
58+ """Bind task-local string variables; null declarations require a value."""
59+ if not isinstance(declarations, dict) or not isinstance(supplied, dict):
60+ raise ValueError('variables must be a mapping')
61+ if any(not isinstance(key, str) or not VARIABLE_NAME.fullmatch(key) for key in declarations):
62+ raise ValueError('variable names must be identifiers')
63+ unknown = set(supplied) - set(declarations)
64+ if unknown:
65+ raise ValueError(f'undeclared variables: {sorted(unknown)}')
66+ values = {**declarations, **supplied}
67+ for key, default in declarations.items():
68+ if default is not None and not isinstance(default, str):
69+ raise ValueError(f'variable {key}: default must be a string or null')
70+ value = values.get(key)
71+ if not isinstance(value, str) or (default is None and not value.strip()):
72+ raise ValueError(f'variable {key}: a string value is required (null declarations require nonempty input)')
73+ return values
74+ 
75+ 
76+def expand_variables(text, values):
77+ """Replace only explicit placeholders once, without evaluating supplied text."""
78+ if '{{var' in VARIABLE_REFERENCE.sub('', text):
79+ raise ValueError('malformed variable placeholder')
80+ 
81+ def replace(match):
82+ name = match.group(1)
83+ if name not in values:
84+ raise ValueError(f'undeclared variable reference: {name}')
85+ return values[name]
86+ 
87+ result = VARIABLE_REFERENCE.sub(replace, text)
88+ if not result.strip():
89+ raise ValueError('variable expansion produced an empty prompt item')
90+ return result
91+ 
92+ 
93+def dependency_overrides(dependencies, count):
94+ overrides = {}
95+ for specification in dependencies:
96+ target, separator, sources = specification.partition(':')
97+ if not separator:
98+ raise ValueError('--depends-on requires N:M,K or N: for an independent task')
99+ index = int(target)
100+ parents = [int(value) for value in sources.split(',')] if sources else []
101+ if index not in range(1, count + 1) or any(value not in range(1, count + 1) for value in parents):
102+ raise ValueError(f'dependency positions must be between 1 and {count}')
103+ if index in overrides or len(set(parents)) != len(parents):
104+ raise ValueError(f'duplicate dependency specification: {specification}')
105+ overrides[index] = parents
106+ return overrides
107+ 
108+ 
109+def read_task(source, supplied):
110+ task = load_yaml(source)
111+ if not isinstance(task, dict) or set(task) - {'procedure', 'variables'} != TASK_FIELDS:
112+ raise ValueError(f'{source}: require 9 task fields and optional procedure/variables; '
113+ 'id, depends_on and max_retries are supplied during assembly')
114+ values = bind_variables(task.pop('variables', {}), supplied)
115+ if task['task_type'] != 'normal':
116+ raise ValueError(f'{source}: assembly currently accepts normal tasks')
117+ for key in ['title', 'executor', 'verifier']:
118+ if not isinstance(task[key], str) or not task[key].strip():
119+ raise ValueError(f'{source}: {key} must be a nonempty string')
120+ for key in ['goal', 'approach', 'acceptance', 'out_of_scope'] + (['procedure'] if 'procedure' in task else []):
121+ value = task[key]
122+ if not isinstance(value, list) or not value or any(not isinstance(x, str) or not x.strip() for x in value):
123+ raise ValueError(f'{source}: {key} must be a nonempty list of nonempty strings')
124+ if task['on_exhaust'] not in ('exit', 'continue'):
125+ raise ValueError(f'{source}: on_exhaust must be exit or continue')
126+ return task, values
127+ 
128+ 
129+def assign_node_ids(nodes):
130+ by_id = {node['id']: node for node in nodes}
131+ depths, visiting = {}, set()
132+ 
133+ def depth(tid):
134+ if tid in visiting:
135+ raise ValueError(f'dependency cycle at input position {int(tid) + 1}')
136+ if tid in depths:
137+ return depths[tid]
138+ visiting.add(tid)
139+ depths[tid] = 1 + max((depth(parent) for parent in by_id[tid]['depends_on']), default=-1)
140+ visiting.remove(tid)
141+ return depths[tid]
142+ 
143+ for tid in by_id:
144+ depth(tid)
145+ # Preserve branch order across layers even when task inputs list the other branch first.
146+ ranks = {}
147+ for layer in sorted(set(depths.values())):
148+ peers = [tid for tid in by_id if depths[tid] == layer]
149+ peers.sort(key=lambda tid: (tuple(sorted(ranks.get(parent) for parent in by_id[tid]['depends_on'])),
150+ int(tid)))
151+ for branch, tid in enumerate(peers):
152+ ranks[tid] = (layer, branch) if len(peers) > 1 else (layer,)
153+ identifiers = {tid: '.'.join(map(str, rank)) for tid, rank in ranks.items()}
154+ for node in nodes:
155+ node['id'] = identifiers[node['id']]
156+ node['depends_on'] = [identifiers[parent] for parent in node['depends_on']]
157+ 
158+ 
159+def resolve_report_references(nodes, bindings):
160+ # Resolve report path IDs before handing the standard YAML to harness.
161+ by_id = {node['id']: node for node in nodes}
162+ ancestors = {}
163+ 
164+ def upstream(tid):
165+ if tid not in ancestors:
166+ ancestors[tid] = set(by_id[tid]['depends_on'])
167+ for parent in by_id[tid]['depends_on']:
168+ ancestors[tid].update(upstream(parent))
169+ return ancestors[tid]
170+ 
171+ for node, values in zip(nodes, bindings):
172+ expand_node_prompts(node, values, by_id, upstream)
173+ 
174+ 
175+def expand_node_prompts(node, values, by_id, upstream):
176+ def resolve_id(match):
177+ title = match.group(1)
178+ if title is None:
179+ return node['id']
180+ candidates = {tid for tid in upstream(node['id']) if by_id[tid]['title'] == title}
181+ # A later run of the same producer supersedes its earlier ancestor.
182+ nearest = candidates - {tid for candidate in candidates for tid in upstream(candidate)}
183+ if len(nearest) != 1:
184+ raise ValueError(f"node {node['id']}: report producer {title!r} must resolve to one upstream node")
185+ return next(iter(nearest))
186+ 
187+ for field in ['goal', 'approach', 'procedure', 'acceptance', 'out_of_scope']:
188+ if field in node:
189+ node[field] = [re.sub(r'\{\{id(?::([^{}]+))?\}\}', resolve_id, item) for item in node[field]]
190+ if any('{{id' in item for item in node[field]):
191+ raise ValueError(f"node {node['id']}: malformed report ID placeholder")
192+ node[field] = [expand_variables(item, values) for item in node[field]]
193+ 
194+ 
195+def assemble(files, dependencies, retries, variables=None):
196+ count = len(files)
197+ if not count:
198+ raise ValueError('at least one task is required')
199+ if len(retries) != count or any(type(value) is not int or value < 0 for value in retries):
200+ raise ValueError('max_retries must be a nonnegative integer for every task')
201+ supplied = [{} for _ in files] if variables is None else variables
202+ if len(supplied) != count:
203+ raise ValueError('variables must be supplied for each task position')
204+ overrides = dependency_overrides(dependencies, count)
205+ nodes, bindings = [], []
206+ for index, source in enumerate(files, 1):
207+ task, values = read_task(source, supplied[index - 1])
208+ bindings.append(values)
209+ parents = overrides.get(index, [index - 1] if index > 1 else [])
210+ nodes.append({'id': str(index - 1), **task, 'max_retries': retries[index - 1],
211+ 'depends_on': [str(value - 1) for value in parents]})
212+ assign_node_ids(nodes)
213+ resolve_report_references(nodes, bindings)
214+ return {'workflow': 'ops-direct-invoke', 'max_parallel': 2, 'nodes': nodes}
215+ 
216+ 
217+def template_positions(nodes):
218+ positions = {}
219+ for index, node in enumerate(nodes, 1):
220+ if not isinstance(node, dict) or set(node) - {'variables'} != {'id', 'yaml', 'depends_on', 'max_retries'}:
221+ raise ValueError('template nodes require id, yaml, depends_on and max_retries; optional variables')
222+ identifier = node['id']
223+ if not isinstance(identifier, str) or not re.fullmatch(r'\d+(?:\.\d+)?', identifier):
224+ raise ValueError('template id must be a numeric string')
225+ if identifier in positions:
226+ raise ValueError(f'duplicate template id: {identifier}')
227+ positions[identifier] = index
228+ if not isinstance(node['yaml'], str) or not node['yaml'].strip():
229+ raise ValueError('task yaml must be a nonempty path')
230+ return positions
231+ 
232+ 
233+def assemble_template(path):
234+ """Expand a reference graph using paths relative to the template file."""
235+ template = load_yaml(path)
236+ if not isinstance(template, dict) or set(template) != {'workflow', 'max_parallel', 'nodes'}:
237+ raise ValueError('template requires workflow, max_parallel and nodes')
238+ if not isinstance(template['workflow'], str) or not template['workflow'].strip():
239+ raise ValueError('workflow must be a nonempty string')
240+ if type(template['max_parallel']) is not int or template['max_parallel'] < 1:
241+ raise ValueError('max_parallel must be a positive integer')
242+ nodes = template['nodes']
243+ if not isinstance(nodes, list) or not nodes:
244+ raise ValueError('template nodes must be a nonempty list')
245+ positions = template_positions(nodes)
246+ dependencies = []
247+ for index, node in enumerate(nodes, 1):
248+ parents = node['depends_on']
249+ if (not isinstance(parents, list)
250+ or any(not isinstance(parent, str) or parent not in positions for parent in parents)):
251+ raise ValueError('depends_on must reference template node IDs')
252+ dependencies.append(f"{index}:" + ','.join(str(positions.get(parent)) for parent in parents))
253+ definition = assemble([path.parent / node['yaml'] for node in nodes], dependencies,
254+ [node['max_retries'] for node in nodes], [node.get('variables', {}) for node in nodes])
255+ if [node['id'] for node in definition['nodes']] != list(positions):
256+ raise ValueError('template IDs must match dependency layers and branch order')
257+ definition.update(workflow=template['workflow'], max_parallel=template['max_parallel'])
258+ return definition
259+ 
260+ 
261+def write_workflow(definition, output):
262+ """Freeze a complete harness input without overwriting an existing run."""
263+ rendered = yaml.safe_dump(definition, allow_unicode=True, sort_keys=False, width=110)
264+ output.parent.mkdir(parents=True, exist_ok=True)
265+ with output.open('x', encoding='utf-8') as stream:
266+ stream.write(rendered)
267+ 
268+ 
269+def main():
270+ logging.basicConfig(level=logging.INFO, format="%(message)s", stream=sys.stdout)
271+ parser = argparse.ArgumentParser(description=__doc__)
272+ parser.add_argument('tasks', nargs='*', type=Path, help='task YAML paths; positions start at 1')
273+ parser.add_argument('--template', type=Path, help='reference workflow template path')
274+ parser.add_argument('--max-retries', type=int, help='required with task paths; retry budget for each task')
275+ parser.add_argument('--output', required=True, type=Path, help='new workflow.yaml path; never overwritten')
276+ parser.add_argument('--depends-on', action='append', default=[], metavar='N:M,K',
277+ help='override dependencies of input N with M,K; N: means none; repeat for multiple tasks')
278+ args = parser.parse_args()
279+ try:
280+ if args.template is not None:
281+ if args.tasks or args.depends_on or args.max_retries is not None:
282+ raise ValueError('--template cannot be combined with task paths, --depends-on or --max-retries')
283+ definition = assemble_template(args.template.resolve(strict=True))
284+ else:
285+ if args.max_retries is None:
286+ raise ValueError('--max-retries is required with task paths')
287+ definition = assemble(args.tasks, args.depends_on, [args.max_retries] * len(args.tasks))
288+ output = args.output.absolute()
289+ write_workflow(definition, output)
290+ except (OSError, ValueError, yaml.YAMLError) as error:
291+ parser.error(str(error))
292+ LOGGER.info("%s (%s tasks)", output, len(definition["nodes"]))
293+ 
294+ 
295+if __name__ == '__main__':
296+ main()
@@ -0,0 +1,121 @@
1+#!/usr/bin/env python3
2+# ----------------------------------------------------------------------------
3+# Copyright (c) 2026 Huawei Technologies Co., Ltd.
4+# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
5+# CANN Open Software License Agreement Version 2.0 (the "License").
6+# Please refer to the License for details. You may not use this file except in compliance with the License.
7+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
8+# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
9+# See LICENSE in the root of the software repository for the full text of the License.
10+# ----------------------------------------------------------------------------
11+ 
12+"""Launch the unchanged workflow-orchestrator CLI, in tmux by default."""
13+import argparse
14+import hashlib
15+import logging
16+import shlex
17+import shutil
18+import subprocess
19+import sys
20+from pathlib import Path
21+ 
22+import yaml
23+ 
24+from assemble_workflow import assemble_template, write_workflow
25+ 
26+LOGGER = logging.getLogger(__name__)
27+ 
28+ 
29+def argument_parser():
30+ parser = argparse.ArgumentParser(description=__doc__)
31+ definitions = parser.add_mutually_exclusive_group(required=True)
32+ definitions.add_argument('--yaml', type=Path, help='path to a complete workflow YAML')
33+ definitions.add_argument('--template', type=Path,
34+ help='workflow template path relative to this Skill templates/workflows directory')
35+ parser.add_argument('--work-dir', required=True, type=Path)
36+ parser.add_argument('--provider', required=True)
37+ prompts = parser.add_mutually_exclusive_group()
38+ prompts.add_argument('--prompt', help='original task text; required by harness on first run')
39+ prompts.add_argument('--prompt-file', type=Path, help='UTF-8 task text, passed unchanged as --prompt')
40+ parser.add_argument('--harness-skill', type=Path,
41+ help='workflow-orchestrator directory; defaults to installed sibling Skill')
42+ parser.add_argument('--foreground', action='store_true', help='stream output and return harness exit code directly')
43+ parser.add_argument('--dry-run', action='store_true', help='forward the public harness simulation flag')
44+ return parser
45+ 
46+ 
47+def resolve_workflow(args):
48+ if args.template is not None:
49+ template_root = (Path(__file__).absolute().parents[1] / 'templates/workflows').resolve()
50+ workflow = (template_root / args.template).resolve(strict=True)
51+ if not workflow.is_relative_to(template_root):
52+ raise ValueError('--template must stay inside templates/workflows; use --yaml for external files')
53+ else:
54+ workflow = args.yaml.resolve(strict=True)
55+ if not workflow.is_file():
56+ raise ValueError('workflow must be a file')
57+ return workflow
58+ 
59+ 
60+def launch_background(command, work, tmux):
61+ session = 'ops-direct-invoke-' + hashlib.sha256(str(work).encode()).hexdigest()[:12]
62+ log = work / 'orchestrator.log'
63+ # Only process launch and output capture; retries and workflow state belong to harness.
64+ shell_command = (shlex.join(command) + ' > ' + shlex.quote(str(log)) + ' 2>&1; '
65+ 'launch_exit=$?; printf "\\nexit status: %s\\n" "$launch_exit" >> '
66+ + shlex.quote(str(log)) + '; exit "$launch_exit"')
67+ result = subprocess.run([tmux, 'new-session', '-d', '-s', session, '-c', str(work), shell_command],
68+ capture_output=True, text=True)
69+ if result.returncode:
70+ raise ValueError(result.stderr.strip() or 'tmux failed to start workflow')
71+ LOGGER.info('session: %s\nlog: %s', session, log)
72+ LOGGER.info('Check completion with: %s', shlex.join([tmux, 'has-session', '-t', session]))
73+ return 0
74+ 
75+ 
76+def launch(args):
77+ workflow = resolve_workflow(args)
78+ # Keep the invocation path before resolving: source installations use Skill symlinks.
79+ harness = args.harness_skill or Path(__file__).absolute().parents[2] / 'workflow-orchestrator'
80+ orchestrator = (harness / 'scripts/orchestrator.py').resolve(strict=True)
81+ if not orchestrator.is_file():
82+ raise ValueError('workflow-orchestrator CLI not found; specify --harness-skill')
83+ definition = assemble_template(workflow) if args.template is not None else None
84+ prompt = args.prompt_file.read_text(encoding='utf-8') if args.prompt_file else args.prompt
85+ work = args.work_dir.resolve()
86+ tmux = None
87+ if not args.foreground:
88+ executable = shutil.which('tmux')
89+ if executable is None:
90+ raise ValueError('tmux is required for background execution; use --foreground to run directly')
91+ tmux = str(Path(executable).resolve(strict=True))
92+ if definition is not None:
93+ workflow = work / f'{work.name}.yaml'
94+ if workflow.exists():
95+ raise ValueError(f'workflow already exists; resume with --yaml {workflow}')
96+ write_workflow(definition, workflow)
97+ command = [sys.executable, str(orchestrator), '--yaml', str(workflow),
98+ '--work-dir', str(work), '--provider', args.provider]
99+ if prompt is not None:
100+ command += ['--prompt', prompt]
101+ if args.dry_run:
102+ command.append('--dry-run')
103+ work.mkdir(parents=True, exist_ok=True)
104+ if args.foreground:
105+ return subprocess.run(command, cwd=work).returncode
106+ return launch_background(command, work, tmux)
107+ 
108+ 
109+def main():
110+ logging.basicConfig(level=logging.INFO, format="%(message)s", stream=sys.stdout)
111+ parser = argument_parser()
112+ args = parser.parse_args()
113+ try:
114+ exit_code = launch(args)
115+ except (OSError, ValueError, yaml.YAMLError) as error:
116+ parser.error(str(error))
117+ return exit_code
118+ 
119+ 
120+if __name__ == '__main__':
121+ sys.exit(main())
@@ -0,0 +1,41 @@
1+variables:
2+ task_requirements: 无额外要求。
3+ repair_requirements: null
4+ executor_skills: 无补充 Skill。
5+ verifier_skills: 无补充 Skill。
6+task_type: normal
7+title: 代码修复
8+goal:
9+- 完成下发范围内的代码修复并通过回归与检视。
10+approach:
11+- 读取 $USER_PROMPT、$WORK_DIR/需求分析.md 和 $WORK_DIR/环境信息.md;必要输入缺失、失效或冲突时,停止依赖该输入的操作,在本阶段报告中记录阻塞证据,按 harness 原生协议结束执行。补充要求:{{var:task_requirements}}
12+- 重试先读已有 $WORK_DIR/{{id}}-验收报告.md,只处理未解决项并记录变更与证据路径;输入及产物未变时复用可核对记录,不重写整份调查。确定性阻塞条件未变时,仅记录复核结果并结束本次执行,不重复调查或伪造通过;仅改授权范围,不修改验收报告。
13+- 必须加载 `repo-coding-rules`、`repo-build-guide`、`repo-test-develop` Skill,按其中的要求执行。
14+- '{{var:executor_skills}}'
15+- 补充 Skill 中的必需项直接加载,候选项仅在实际证据满足所列条件时加载;未命中不加载。所需能力超出清单或需改变已确认约束、任务范围时,记录阻塞,不自行扩展。
16+- 本轮修复要求:{{var:repair_requirements}}。读取问题证据、目标代码和测试入口,确认授权路径、预期行为及回归范围;必要信息缺失时记录阻塞,不猜测修复目标。
17+- 定位根因并修复授权代码,补齐用例;实现分支改变时同步白盒用例和覆盖记录。按已安装的 ops-direct-invoke/templates/docs/测试执行记录.md 中的证据复用规则,确定重建、回归或复用范围,写入 $WORK_DIR/{{id}}-测试执行记录.md。没有待修复缺陷且已有当前版本的有效全量证据时,记录无需修改与复用依据,不重复构建或测试;不满足复用条件时补齐验证。
18+- 将修复目标、改动摘要、测试证据路径及补充 Skill 使用依据写入 $WORK_DIR/{{id}}-修复记录.md;将授权对象的实际绝对路径赋给 repair_file,多文件逐一检查。
19+procedure:
20+- 读取 $USER_PROMPT、$WORK_DIR/需求分析.md 和 $WORK_DIR/环境信息.md;必要输入缺失、失效或冲突时,记录阻塞证据并判定验收失败。补充要求:{{var:task_requirements}}
21+- 必须加载 `repo-coding-rules`、`repo-build-guide`、`repo-test-develop` Skill,按其中的要求执行。
22+- '{{var:verifier_skills}}'
23+- 补充 Skill 中的必需项直接加载,候选项仅在实际证据满足所列条件时加载;未命中不加载。所需能力超出清单或需改变已确认约束、任务范围时,记录阻塞,不自行扩展。诊断仅限已有证据分析与判定,不修改被验收对象。
24+- 本轮修复要求:{{var:repair_requirements}}。读取原问题证据、当前代码、测试入口及 $WORK_DIR/{{id}}-修复记录.md;给 repair_file 赋实际路径,多文件逐一检查。
25+- 只读核对 $WORK_DIR/{{id}}-测试执行记录.md、原问题复现及当前版本的全量黑盒/白盒原始日志、当前源码/测试/构建产物哈希和加载路径,确认问题解决且无遗漏或跳过;检视全部修复变更及受影响分支覆盖。按测试执行记录模板核对证据复用条件、版本差异及受影响项;无代码改动也核对完整证据,不重复构建或运行测试。
26+- 由 verifier 按已安装的 ops-direct-invoke/templates/docs/验收报告.md 写入 $WORK_DIR/{{id}}-验收报告.md,执行 test -s "$WORK_DIR/{{id}}-验收报告.md";通过、失败或阻塞均记录逐项结论与证据路径。重试仅追加问题处理和受影响项复核结果;当前版本缺少有效证据即失败,不补造或重跑测试。
27+acceptance:
28+- test -s "$repair_file"
29+- test -s "$WORK_DIR/{{id}}-修复记录.md"
30+- test -s "$WORK_DIR/{{id}}-测试执行记录.md"
31+- 下发问题已修复,变更范围明确,相关源码与用例一致。
32+- 现有全量回归与代码检视通过,证据及补充 Skill 使用依据完整,未放宽需求或测试标准。
33+out_of_scope:
34+- 改动已确认需求或放宽精度标准、以篡改 golden/用例掩盖失败、伪造确认或验证证据。
35+- 加载固定项及当前阶段下发清单以外的 Skill、向 PM 或用户发起交互、等待其答复、派发 Agent、修改 harness 或调度状态、重置或回退其他节点。
36+- 将中间产物写出 $WORK_DIR,或使用不以 {{id}}- 开头的中间报告名;算子交付件按目标仓约定路径写入。
37+- 性能采集与优化验收、回顾与经验总结、PR、外部 CI 或合并事务。
38+- executor 编写或修改验收者报告、为等待验收报告而停止交付;verifier 重新构建、安装或运行测试、替执行者补造执行证据。
39+executor: ops-direct-invoke-developer
40+verifier: ops-direct-invoke-verifier
41+on_exhaust: exit
@@ -0,0 +1,42 @@
1+variables:
2+ task_requirements: 无额外要求。
3+ spike_scope: null
4+ executor_skills: 无补充 Skill。
5+ verifier_skills: 无补充 Skill。
6+task_type: normal
7+title: 技术穿刺
8+goal:
9+- 用最小可运行实现验证关键技术路线。
10+approach:
11+- 读取 $USER_PROMPT、$WORK_DIR/需求分析.md 和 $WORK_DIR/环境信息.md;必要输入缺失、失效或冲突时,停止依赖该输入的操作,在本阶段报告中记录阻塞证据,按 harness 原生协议结束执行。补充要求:{{var:task_requirements}}
12+- 重试先读已有 $WORK_DIR/{{id}}-验收报告.md,只处理未解决项并记录变更与证据路径;输入及产物未变时复用可核对记录,不重写整份调查。确定性阻塞条件未变时,仅记录复核结果并结束本次执行,不重复调查或伪造通过;仅改授权范围,不修改验收报告。
13+- 必须加载 `repo-knowledge`、`repo-op-templates`、`repo-build-guide`、`repo-test-develop`、`repo-coding-rules` Skill,按其中的要求执行。
14+- '{{var:executor_skills}}'
15+- 穿刺范围:{{var:spike_scope}}。只验证下发路线及关键疑点;代表用例覆盖关键组合,不展开完整测试矩阵、白盒工程或交付文档。
16+- 复用目标仓已有工程和测试入口,编写最小实现及精度断言;临时实现、用例和构建文件放在 $WORK_DIR/{{id}}-穿刺/ 下,保留工程要求的文件名,明确授权的项目交付件按目标仓路径写入。将实现及测试入口实际文件路径赋给 spike_source、spike_test_entry,多文件逐一检查。
17+- 在目标芯片真实编译并运行代表用例,覆盖待验证的端到端关键组合;保持已确认接口、架构、精度与单 Kernel 等约束。只查到 API、各子步骤分别可用、CPU 自检或模拟执行不能代替设备证据。
18+- 按已安装的 ops-direct-invoke/templates/docs/测试执行记录.md 写入 $WORK_DIR/{{id}}-测试执行记录.md,记录疑点、采用路线、代码/测试/构建产物版本、真实编译和设备原始日志、代表用例及结果、未验证范围和下一轮复用路径;不另写长篇方案。缺少设备、规则冲突或路线不可行时保存阻塞证据,停止受阻操作,不宣称穿刺成功。
19+procedure:
20+- 读取 $USER_PROMPT、$WORK_DIR/需求分析.md 和 $WORK_DIR/环境信息.md;必要输入缺失、失效或冲突时,记录阻塞证据并判定验收失败。补充要求:{{var:task_requirements}}
21+- 必须加载 `repo-coding-rules` Skill,按其中的要求执行。
22+- '{{var:verifier_skills}}'
23+- 穿刺范围:{{var:spike_scope}}。读取实现、测试入口及 $WORK_DIR/{{id}}-测试执行记录.md,给 spike_source、spike_test_entry 赋实际文件路径,逐一核对;静态检视关键组合、调用真实性及已确认约束,并检视本节点实现、测试和脚本代码的编码规范。
24+- 只读核对当前源码/测试/构建产物哈希、实际加载路径、目标设备、编译退出码及代表用例精度结果;不重新构建或运行。验收本次关键疑点是否有设备证据闭合,不要求未下发的全量覆盖或正式文档。
25+- 未验证关键组合、只有资料推导或 CPU/模拟证据、规则冲突未解时判失败;明确记录失败条件及未验证范围。通过仅证明穿刺范围可行,不证明完整算子已交付。
26+- 由 verifier 按已安装的 ops-direct-invoke/templates/docs/验收报告.md 写入 $WORK_DIR/{{id}}-验收报告.md,执行 test -s "$WORK_DIR/{{id}}-验收报告.md";通过、失败或阻塞均记录逐项结论与证据路径。重试仅追加问题处理和受影响项复核结果;当前版本缺少有效证据即失败,不补造或重跑测试。
27+acceptance:
28+- test -s "$spike_source"
29+- test -s "$spike_test_entry"
30+- test -s "$WORK_DIR/{{id}}-测试执行记录.md"
31+- 关键技术组合在目标芯片编译和运行成功,代表用例满足已确认的精度及架构约束。
32+- 实现、测试和脚本代码符合编码规则;证据对应当前版本,已验证范围、剩余风险及可复用路径明确。
33+out_of_scope:
34+- 改动已确认需求或放宽精度标准、以篡改 golden/用例掩盖失败、伪造确认或验证证据。
35+- 加载固定项及当前阶段下发清单以外的 Skill、向 PM 或用户发起交互、等待其答复、派发 Agent、修改 harness 或调度状态、重置或回退其他节点。
36+- 将中间产物写出 $WORK_DIR,或使用不以 {{id}}- 开头的中间报告名;算子交付件按目标仓约定路径写入。
37+- 性能采集与优化验收、回顾与经验总结、PR、外部 CI 或合并事务。
38+- executor 编写或修改验收者报告、为等待验收报告而停止交付;verifier 重新构建、安装或运行测试、替执行者补造执行证据。
39+- 把少量代表用例通过当作完整交付,展开与穿刺疑点无关的资料搜集或全量测试工程。
40+executor: ops-direct-invoke-developer
41+verifier: ops-direct-invoke-verifier
42+on_exhaust: exit
@@ -0,0 +1,34 @@
1+variables:
2+ task_requirements: 无额外要求。
3+ executor_skills: 无补充 Skill。
4+ verifier_skills: 无补充 Skill。
5+task_type: normal
6+title: 文档准备
7+goal:
8+- 按仓内已有算子文档规范补全本算子的相关资料。
9+approach:
10+- 读取 $USER_PROMPT、$WORK_DIR/需求分析.md 和 $WORK_DIR/环境信息.md;必要输入缺失、失效或冲突时,停止依赖该输入的操作,在本阶段报告中记录阻塞证据,按 harness 原生协议结束执行。补充要求:{{var:task_requirements}}
11+- 重试先读已有 $WORK_DIR/{{id}}-验收报告.md,只处理未解决项并记录变更与证据路径;输入及产物未变时复用可核对记录,不重写整份调查。确定性阻塞条件未变时,仅记录复核结果并结束本次执行,不重复调查或伪造通过;仅改授权范围,不修改验收报告。
12+- 必须加载 `repo-knowledge` Skill,按其中的要求执行。
13+- '{{var:executor_skills}}'
14+- 读取当前实现、测试及 $WORK_DIR/{{id:代码修复}}-修复记录.md、$WORK_DIR/{{id:代码修复}}-验收报告.md,以修复后版本为准。
15+- 对照仓内已有同类算子文档,确定路径、章节与示例;若无已有文档,记录本节点前置条件不满足的证据,不凭空创建格式或文档要求。
16+- 按仓内格式补全接口、参数、约束和使用资料,写入约定位置;给 operator_doc 赋实际绝对路径,多文件逐一检查。
17+procedure:
18+- 读取 $USER_PROMPT、$WORK_DIR/需求分析.md 和 $WORK_DIR/环境信息.md;必要输入缺失、失效或冲突时,记录阻塞证据并判定验收失败。补充要求:{{var:task_requirements}}
19+- '{{var:verifier_skills}}'
20+- 读取本次文档、仓内同类文档、当前代码/测试和 $WORK_DIR/{{id:代码修复}}-验收报告.md;给 operator_doc 赋实际路径,多文件逐一检查。
21+- 核对格式、内容完整性及接口/约束/示例与最终交付的一致性,不要求未开展的性能产物。
22+- 由 verifier 按已安装的 ops-direct-invoke/templates/docs/验收报告.md 写入 $WORK_DIR/{{id}}-验收报告.md,执行 test -s "$WORK_DIR/{{id}}-验收报告.md";通过、失败或阻塞均记录逐项结论与证据路径。重试仅追加问题处理和受影响项复核结果;当前版本缺少有效证据即失败,不补造或重跑测试。
23+acceptance:
24+- test -s "$operator_doc"
25+- 算子相关资料符合仓内已有格式和内容要求,与当前交付实现及验收证据一致。
26+out_of_scope:
27+- 改动已确认需求或放宽精度标准、以篡改 golden/用例掩盖失败、伪造确认或验证证据。
28+- 加载固定项及当前阶段下发清单以外的 Skill、向 PM 或用户发起交互、等待其答复、派发 Agent、修改 harness 或调度状态、重置或回退其他节点。
29+- 将中间产物写出 $WORK_DIR,或使用不以 {{id}}- 开头的中间报告名;算子交付件按目标仓约定路径写入。
30+- 性能采集与优化验收、回顾与经验总结、PR、外部 CI 或合并事务。
31+- executor 编写或修改验收者报告、为等待验收报告而停止交付;verifier 重新构建、安装或运行测试、替执行者补造执行证据。
32+executor: ops-direct-invoke-developer
33+verifier: ops-direct-invoke-verifier
34+on_exhaust: exit
@@ -0,0 +1,40 @@
1+variables:
2+ task_requirements: 无额外要求。
3+ executor_skills: 无补充 Skill。
4+ verifier_skills: 无补充 Skill。
5+task_type: normal
6+title: 测试工程开发
7+goal:
8+- 准备可执行的 ST 测试工程与完整黑盒用例。
9+approach:
10+- 读取 $USER_PROMPT、$WORK_DIR/需求分析.md 和 $WORK_DIR/环境信息.md;必要输入缺失、失效或冲突时,停止依赖该输入的操作,在本阶段报告中记录阻塞证据,按 harness 原生协议结束执行。补充要求:{{var:task_requirements}}
11+- 重试先读已有 $WORK_DIR/{{id}}-验收报告.md,只处理未解决项并记录变更与证据路径;输入及产物未变时复用可核对记录,不重写整份调查。确定性阻塞条件未变时,仅记录复核结果并结束本次执行,不重复调查或伪造通过;仅改授权范围,不修改验收报告。
12+- 必须加载 `repo-test-develop`、`repo-coding-rules` Skill,按其中的要求执行。
13+- '{{var:executor_skills}}'
14+- 读取 $WORK_DIR/{{id:黑盒测试设计}}-黑盒测试设计.md;环境记录中的框架信息仅作线索,检查目标仓当前测试入口,复用已有 ST 框架,仅在不存在框架时按目标仓布局搭建,必要信息不足时记录阻塞,不猜测框架布局。
15+- 本轮补充要求提供穿刺测试入口时,核对当前接口后复用并扩展,不重新搭建已有可用框架;穿刺的少量用例不代替完整黑盒覆盖。
16+- 复用现有 golden、数据生成、精度判定与统一入口,补齐目标任务和全部黑盒用例;缺失内容按已确认规格实现,保留方案用例 ID,并支持后续白盒接入。将入口及用例文件的实际绝对路径赋给 test_entry、test_cases,多文件逐一检查。
17+- 先按仓库测试契约完成代表用例的任务发现、golden 参数绑定、数据生成与报告输出自检,再补齐全部用例并核对发现数;提交前检查本节点新增或修改的代码符合编码规则。写入 $WORK_DIR/{{id}}-测试工程说明.md,记录框架位置、复用或新建依据、文件与用例映射、代码哈希、自检命令、退出码及原始日志路径。
18+procedure:
19+- 读取 $USER_PROMPT、$WORK_DIR/需求分析.md 和 $WORK_DIR/环境信息.md;必要输入缺失、失效或冲突时,记录阻塞证据并判定验收失败。补充要求:{{var:task_requirements}}
20+- 必须加载 `repo-test-develop`、`repo-coding-rules` Skill,按其中的要求执行。
21+- '{{var:verifier_skills}}'
22+- 读取黑盒方案、测试工程及 $WORK_DIR/{{id}}-测试工程说明.md,核对框架复用情况和全部用例的参数、预期结果及断言;给 test_entry、test_cases 赋实际路径,多文件逐一检查。
23+- 检视本节点新增或修改的测试与脚本代码是否符合编码规则;核对 golden 参数绑定、数据生成、用例发现、报告输出与比对逻辑的代码及自检日志,证据应对应当前文件哈希;不代跑执行者的测试。本节点只验收测试工程就绪,不要求执行尚未实现的算子,也不宣称算子全量通过。
24+- 由 verifier 按已安装的 ops-direct-invoke/templates/docs/验收报告.md 写入 $WORK_DIR/{{id}}-验收报告.md,执行 test -s "$WORK_DIR/{{id}}-验收报告.md";通过、失败或阻塞均记录逐项结论与证据路径。重试仅追加问题处理和受影响项复核结果;当前版本缺少有效证据即失败,不补造或重跑测试。
25+acceptance:
26+- test -s "$test_entry"
27+- test -s "$test_cases"
28+- test -s "$WORK_DIR/{{id}}-测试工程说明.md"
29+- ST 框架可用,已有框架得到复用;黑盒用例完整符合方案,入口支持后续白盒用例接入。
30+- golden、参数绑定、数据生成与精度断言可运行,报告可生成,发现数与预期一致。
31+- 本节点交付的测试与脚本代码符合编码规则,无遗留阻断项。
32+out_of_scope:
33+- 改动已确认需求或放宽精度标准、以篡改 golden/用例掩盖失败、伪造确认或验证证据。
34+- 加载固定项及当前阶段下发清单以外的 Skill、向 PM 或用户发起交互、等待其答复、派发 Agent、修改 harness 或调度状态、重置或回退其他节点。
35+- 将中间产物写出 $WORK_DIR,或使用不以 {{id}}- 开头的中间报告名;算子交付件按目标仓约定路径写入。
36+- 性能采集与优化验收、回顾与经验总结、PR、外部 CI 或合并事务。
37+- executor 编写或修改验收者报告、为等待验收报告而停止交付;verifier 重新构建、安装或运行测试、替执行者补造执行证据。
38+executor: ops-direct-invoke-developer
39+verifier: ops-direct-invoke-verifier
40+on_exhaust: exit
@@ -0,0 +1,41 @@
1+variables:
2+ task_requirements: 无额外要求。
3+ executor_skills: 无补充 Skill。
4+ verifier_skills: 无补充 Skill。
5+task_type: normal
6+title: 白盒测试设计
7+goal:
8+- 依据实际代码生成白盒用例并纳入现有测试框架。
9+approach:
10+- 读取 $USER_PROMPT、$WORK_DIR/需求分析.md 和 $WORK_DIR/环境信息.md;必要输入缺失、失效或冲突时,停止依赖该输入的操作,在本阶段报告中记录阻塞证据,按 harness 原生协议结束执行。补充要求:{{var:task_requirements}}
11+- 重试先读已有 $WORK_DIR/{{id}}-验收报告.md,只处理未解决项并记录变更与证据路径;输入及产物未变时复用可核对记录,不重写整份调查。确定性阻塞条件未变时,仅记录复核结果并结束本次执行,不重复调查或伪造通过;仅改授权范围,不修改验收报告。
12+- 必须加载 `repo-test-develop`、`repo-coding-rules` Skill,按其中的要求执行。
13+- '{{var:executor_skills}}'
14+- 读取当前源码、$WORK_DIR/{{id:算子开发}}-实现记录.md、$WORK_DIR/{{id:黑盒测试设计}}-黑盒测试设计.md 和 $WORK_DIR/{{id:测试工程开发}}-测试工程说明.md,按实际代码枚举有效控制流与边界。
15+- 按需求允许范围生成触发用例,直接写入现有 ST 框架并接入统一入口;沿用已确认的 golden、预期错误和阈值,不另建框架、不修改算子。将全部用例文件路径赋给 whitebox_cases,多文件逐一检查。
16+- 运行全量黑盒与白盒用例,按已安装的 ops-direct-invoke/templates/docs/测试执行记录.md 写入 $WORK_DIR/{{id}}-测试执行记录.md,保存原始日志与问题归属证据;按已安装的 ops-direct-invoke/templates/docs/白盒测试设计.md
17+ 写入 $WORK_DIR/{{id}}-白盒测试设计.md,记录源码位置/条件、用例映射、文件和执行命令。暴露的算子缺陷连同复现证据交下游修复。
18+procedure:
19+- 读取 $USER_PROMPT、$WORK_DIR/需求分析.md 和 $WORK_DIR/环境信息.md;必要输入缺失、失效或冲突时,记录阻塞证据并判定验收失败。补充要求:{{var:task_requirements}}
20+- 必须加载 `repo-test-develop`、`repo-coding-rules` Skill,按其中的要求执行。
21+- '{{var:verifier_skills}}'
22+- 读取源码、ST 框架与 $WORK_DIR/{{id}}-白盒测试设计.md,独立核对有效分支、触发用例和接入情况;给 whitebox_cases 赋实际路径,多文件逐一检查。
23+- 只读核对 $WORK_DIR/{{id}}-测试执行记录.md、全量黑盒与白盒原始日志及当前源码/测试哈希,区分设计覆盖、实际命中与受阻路径;不重复构建或运行用例。
24+- 检视本节点新增或修改的测试与脚本代码是否符合编码规则;本节点验收用例及接入质量:测试/框架错误或设计遗漏导致失败;正确用例暴露的算子缺陷须有归属证据,连同受影响覆盖交下游修复,不将节点通过表述为算子功能通过。
25+- 由 verifier 按已安装的 ops-direct-invoke/templates/docs/验收报告.md 写入 $WORK_DIR/{{id}}-验收报告.md,执行 test -s "$WORK_DIR/{{id}}-验收报告.md";通过、失败或阻塞均记录逐项结论与证据路径。重试仅追加问题处理和受影响项复核结果;当前版本缺少有效证据即失败,不补造或重跑测试。
26+acceptance:
27+- test -s "$whitebox_cases"
28+- test -s "$WORK_DIR/{{id}}-白盒测试设计.md"
29+- test -s "$WORK_DIR/{{id}}-测试执行记录.md"
30+- 白盒用例已进入现有框架,覆盖全部已识别的有效源码分支,测试实现符合需求、精度标准与编码规则。
31+- 运行记录真实、问题归属与证据完整,算子缺陷及受影响覆盖明确;无未解决的测试实现或框架接入问题。
32+out_of_scope:
33+- 改动已确认需求或放宽精度标准、以篡改 golden/用例掩盖失败、伪造确认或验证证据。
34+- 加载固定项及当前阶段下发清单以外的 Skill、向 PM 或用户发起交互、等待其答复、派发 Agent、修改 harness 或调度状态、重置或回退其他节点。
35+- 将中间产物写出 $WORK_DIR,或使用不以 {{id}}- 开头的中间报告名;算子交付件按目标仓约定路径写入。
36+- 性能采集与优化验收、回顾与经验总结、PR、外部 CI 或合并事务。
37+- 修改被测算子实现;算子缺陷交下游代码修复。
38+- executor 编写或修改验收者报告、为等待验收报告而停止交付;verifier 重新构建、安装或运行测试、替执行者补造执行证据。
39+executor: ops-direct-invoke-developer
40+verifier: ops-direct-invoke-verifier
41+on_exhaust: exit
@@ -0,0 +1,38 @@
1+variables:
2+ task_requirements: 无额外要求。
3+ research_focus: 目标芯片、算子专项资料、可组合 API 与需求 shape 范围的初版 Tiling。
4+ executor_skills: 无补充 Skill。
5+ verifier_skills: 无补充 Skill。
6+task_type: normal
7+title: 知识搜集
8+goal:
9+- 形成可溯源的算子知识资料与初版实现草稿。
10+approach:
11+- 读取 $USER_PROMPT、$WORK_DIR/需求分析.md 和 $WORK_DIR/环境信息.md;必要输入缺失、失效或冲突时,停止依赖该输入的操作,在本阶段报告中记录阻塞证据,按 harness 原生协议结束执行。补充要求:{{var:task_requirements}}
12+- 重试先读已有 $WORK_DIR/{{id}}-验收报告.md,只处理未解决项并记录变更与证据路径;输入及产物未变时复用可核对记录,不重写整份调查。确定性阻塞条件未变时,仅记录复核结果并结束本次执行,不重复调查或伪造通过;仅改授权范围,不修改验收报告。
13+- 必须加载 `repo-knowledge`、`npu-arch`、`ascendc-docs-search` Skill,按其中的要求执行。
14+- '{{var:executor_skills}}'
15+- 按 {{var:research_focus}} 检索目标仓、Skill 库和可用资料库,仅记录与本轮重点相关的关键资料、路径、版本和适用范围;不遍历无关资料,不给所有读过的文件逐一计算哈希;新增 Skill 建议注明适用任务、执行/验收阶段及依据,仅供整轮结束后的编排参考,不改变本轮 Skill
16+ 清单。
17+- 归纳算法路线、API 签名与组合、数据流及平台约束;按需求中的代表性 shape 分组给出多核、块大小、Buffer 和尾块处理草稿,区分证据、推导和待验证项;非关键资料未命中或无法复核时,删去无依据断言并标注未知。
18+- 按已安装的 ops-direct-invoke/templates/docs/知识搜集.md 写入 $WORK_DIR/{{id}}-知识搜集.md;草稿供实现尝试,不作为必须照搬的方案。
19+procedure:
20+- 读取 $USER_PROMPT、$WORK_DIR/需求分析.md 和 $WORK_DIR/环境信息.md;必要输入缺失、失效或冲突时,记录阻塞证据并判定验收失败。补充要求:{{var:task_requirements}}
21+- 必须加载 `ascendc-docs-search`、`npu-arch` Skill,按其中的要求执行。
22+- '{{var:verifier_skills}}'
23+- 读取 $WORK_DIR/{{id}}-知识搜集.md,按 {{var:research_focus}} 核对决定路线和 API 使用的关键引用、芯片/版本/dtype 适用范围;不重新执行全库检索,不扩展本轮搜集范围。
24+- 核对 API 组合与代表性 shape 分组的 Tiling 草稿具有可尝试的方向;关键引用虚构、证据矛盾或遗漏搜集要求时失败。非关键资料未命中或无法复核但已标注未知且未被当作事实使用时,不以其单独阻断;残留无依据断言时指出位置并要求执行者修正;待验证假设不等于路线已验证。
25+- 由 verifier 按已安装的 ops-direct-invoke/templates/docs/验收报告.md 写入 $WORK_DIR/{{id}}-验收报告.md,执行 test -s "$WORK_DIR/{{id}}-验收报告.md";通过、失败或阻塞均记录逐项结论与证据路径。重试仅追加问题处理和受影响项复核结果;当前版本缺少有效证据即失败,不补造或重跑测试。
26+acceptance:
27+- test -s "$WORK_DIR/{{id}}-知识搜集.md"
28+- 资料及专项 Skill 检索记录可溯源,结论与适用条件准确。
29+- API 组合与代表性 shape 分组的初版 Tiling 草稿齐备,事实、建议和待验证项区分清楚。
30+out_of_scope:
31+- 改动已确认需求或放宽精度标准、以篡改 golden/用例掩盖失败、伪造确认或验证证据。
32+- 加载固定项及当前阶段下发清单以外的 Skill、向 PM 或用户发起交互、等待其答复、派发 Agent、修改 harness 或调度状态、重置或回退其他节点。
33+- 将中间产物写出 $WORK_DIR,或使用不以 {{id}}- 开头的中间报告名;算子交付件按目标仓约定路径写入。
34+- 性能采集与优化验收、回顾与经验总结、PR、外部 CI 或合并事务。
35+- executor 编写或修改验收者报告、为等待验收报告而停止交付;verifier 重新构建、安装或运行测试、替执行者补造执行证据。
36+executor: ops-direct-invoke-architect
37+verifier: ops-direct-invoke-verifier
38+on_exhaust: exit
@@ -0,0 +1,49 @@
1+variables:
2+ task_requirements: 无额外要求。
3+ executor_skills: 无补充 Skill。
4+ verifier_skills: 无补充 Skill。
5+ knowledge_documents: 无补充文档。
6+task_type: normal
7+title: 算子开发
8+goal:
9+- 完成满足已确认需求的直调算子实现。
10+approach:
11+- 读取 $USER_PROMPT、$WORK_DIR/需求分析.md 和 $WORK_DIR/环境信息.md;必要输入缺失、失效或冲突时,停止依赖该输入的操作,在本阶段报告中记录阻塞证据,按 harness 原生协议结束执行。补充要求:{{var:task_requirements}}
12+- 重试先读已有 $WORK_DIR/{{id}}-验收报告.md,只处理未解决项并记录变更与证据路径;输入及产物未变时复用可核对记录,不重写整份调查。确定性阻塞条件未变时,仅记录复核结果并结束本次执行,不重复调查或伪造通过;仅改授权范围,不修改验收报告。
13+- 必须加载 `repo-op-templates`、`repo-coding-rules`、`repo-build-guide`、`repo-knowledge`、`ascendc-api-best-practices`、`ascendc-docs-search`
14+ Skill,按其中的要求执行。
15+- 补充知识文档:{{var:knowledge_documents}}。有则读取,作为中立参考,区分证据、建议与待验证项;无则直接依据需求、固定 Skill 和测试工程开发,不要求图中存在知识搜集节点。
16+- '{{var:executor_skills}}'
17+- 补充 Skill 中的必需项直接加载,候选项仅在实际证据满足所列条件时加载;未命中不加载。所需能力超出清单或需改变已确认约束、任务范围时,记录阻塞,不自行扩展。
18+- 读取 $WORK_DIR/{{id:黑盒测试设计}}-黑盒测试设计.md 和 $WORK_DIR/{{id:测试工程开发}}-测试工程说明.md,复用资料及测试入口。
19+- 本轮补充要求提供前轮穿刺代码或证据时,核对其路径、版本与适用范围,复用有效实现和测试入口,仅补齐正式交付缺口;穿刺通过不代替本节点全量黑盒与代码检视。
20+- 按目标仓布局实现算子,可根据验证调整草稿中的 API、Buffer、Tiling 与分支;已确认接口、芯片、架构和精度仍是约束。将源码、注册封装和构建入口的实际路径赋给 operator_source、registration_source、build_entry,多文件逐一检查。
21+- 独立构建当前代码并运行全量黑盒用例;将实现路线、关键分支、变更摘要及补充 Skill 使用依据写入 $WORK_DIR/{{id}}-实现记录.md。按已安装的 ops-direct-invoke/templates/docs/测试执行记录.md 写入
22+ $WORK_DIR/{{id}}-测试执行记录.md,保存构建及全量测试原始日志;实现记录仅引用证据路径,不再抄录命令输出和逐用例明细。代码检视由 verifier 执行,白盒由后续节点生成。
23+procedure:
24+- 读取 $USER_PROMPT、$WORK_DIR/需求分析.md 和 $WORK_DIR/环境信息.md;必要输入缺失、失效或冲突时,记录阻塞证据并判定验收失败。补充要求:{{var:task_requirements}}
25+- 必须加载 `repo-build-guide`、`repo-test-develop`、`repo-knowledge`、`repo-coding-rules` Skill,按其中的要求执行。
26+- '{{var:verifier_skills}}'
27+- 补充 Skill 中的必需项直接加载,候选项仅在实际证据满足所列条件时加载;未命中不加载。所需能力超出清单或需改变已确认约束、任务范围时,记录阻塞,不自行扩展。诊断仅限已有证据分析与判定,不修改被验收对象。
28+- 读取当前代码、$WORK_DIR/{{id}}-实现记录.md、黑盒方案与测试工程说明;给 operator_source、registration_source、build_entry 赋实际路径,多文件逐一检查。
29+- 读取 $WORK_DIR/{{id}}-测试执行记录.md 与原始构建、测试日志,核对当前源码、测试、构建产物的哈希与运行时加载路径一致;全量黑盒生成数、执行数及结果可核对,无缺失、跳过、待验或失败,不虚构白盒覆盖。只读核验现有证据,不重新构建或运行测试。
30+- 检视全部算子变更与关联接口,核对需求、硬件约束、编码规则及实现记录;草稿仅作参考。按已安装的 ops-direct-invoke/templates/docs/代码检视报告.md 写入 $WORK_DIR/{{id}}-代码检视报告.md,两个维度均通过才通过本节点;验收报告记录本阶段实际加载的补充
31+ Skill 与选择依据(未加载记无)。
32+- 由 verifier 按已安装的 ops-direct-invoke/templates/docs/验收报告.md 写入 $WORK_DIR/{{id}}-验收报告.md,执行 test -s "$WORK_DIR/{{id}}-验收报告.md";通过、失败或阻塞均记录逐项结论与证据路径。重试仅追加问题处理和受影响项复核结果;当前版本缺少有效证据即失败,不补造或重跑测试。
33+acceptance:
34+- test -s "$operator_source"
35+- test -s "$registration_source"
36+- test -s "$build_entry"
37+- test -s "$WORK_DIR/{{id}}-实现记录.md"
38+- test -s "$WORK_DIR/{{id}}-测试执行记录.md"
39+- 黑盒用例全量通过,当前代码构建成功,接口与精度满足需求,无缺失、跳过或待验项。
40+- 代码检视通过,当前实现满足需求与编码规则,无阻塞或高级问题;记录和报告与实际交付一致,补充 Skill 使用及依据可追溯。
41+out_of_scope:
42+- 改动已确认需求或放宽精度标准、以篡改 golden/用例掩盖失败、伪造确认或验证证据。
43+- 加载固定项及当前阶段下发清单以外的 Skill、向 PM 或用户发起交互、等待其答复、派发 Agent、修改 harness 或调度状态、重置或回退其他节点。
44+- 将中间产物写出 $WORK_DIR,或使用不以 {{id}}- 开头的中间报告名;算子交付件按目标仓约定路径写入。
45+- 性能采集与优化验收、回顾与经验总结、PR、外部 CI 或合并事务。
46+- executor 编写或修改验收者报告、为等待验收报告而停止交付;verifier 重新构建、安装或运行测试、替执行者补造执行证据。
47+executor: ops-direct-invoke-developer
48+verifier: ops-direct-invoke-verifier
49+on_exhaust: exit
@@ -0,0 +1,34 @@
1+variables:
2+ task_requirements: 无额外要求。
3+ executor_skills: 无补充 Skill。
4+ verifier_skills: 无补充 Skill。
5+task_type: normal
6+title: 黑盒测试设计
7+goal:
8+- 形成覆盖算子规格的黑盒测试方案。
9+approach:
10+- 读取 $USER_PROMPT、$WORK_DIR/需求分析.md 和 $WORK_DIR/环境信息.md;必要输入缺失、失效或冲突时,停止依赖该输入的操作,在本阶段报告中记录阻塞证据,按 harness 原生协议结束执行。补充要求:{{var:task_requirements}}
11+- 重试先读已有 $WORK_DIR/{{id}}-验收报告.md,只处理未解决项并记录变更与证据路径;输入及产物未变时复用可核对记录,不重写整份调查。确定性阻塞条件未变时,仅记录复核结果并结束本次执行,不重复调查或伪造通过;仅改授权范围,不修改验收报告。
12+- 必须加载 `repo-test-develop`、`ascendc-st-design` Skill,按其中的要求执行。
13+- '{{var:executor_skills}}'
14+- 依据已确认规格设计 golden、L0/L1/L2 用例、覆盖矩阵、预期错误及逐输出精度标准;按已安装的 ops-direct-invoke/templates/docs/黑盒测试设计.md 写入 $WORK_DIR/{{id}}-黑盒测试设计.md。
15+procedure:
16+- 读取 $USER_PROMPT、$WORK_DIR/需求分析.md 和 $WORK_DIR/环境信息.md;必要输入缺失、失效或冲突时,记录阻塞证据并判定验收失败。补充要求:{{var:task_requirements}}
17+- 必须加载 `repo-test-develop` Skill,按其中的要求执行。
18+- '{{var:verifier_skills}}'
19+- 对照需求和已安装的 ops-direct-invoke/templates/docs/黑盒测试设计.md,检查 $WORK_DIR/{{id}}-黑盒测试设计.md 的规格覆盖、golden、预期结果及精度口径,记录缺口与依据。
20+- 由 verifier 按已安装的 ops-direct-invoke/templates/docs/验收报告.md 写入 $WORK_DIR/{{id}}-验收报告.md,执行 test -s "$WORK_DIR/{{id}}-验收报告.md";通过、失败或阻塞均记录逐项结论与证据路径。重试仅追加问题处理和受影响项复核结果;当前版本缺少有效证据即失败,不补造或重跑测试。
21+acceptance:
22+- test -s "$WORK_DIR/{{id}}-黑盒测试设计.md"
23+- golden 与测试方案符合已确认需求。
24+- L0/L1/L2 覆盖完整,覆盖矩阵、补充用例和预期错误明确。
25+- 逐输出精度口径完整、权威且可执行,无未说明的差异。
26+out_of_scope:
27+- 改动已确认需求或放宽精度标准、以篡改 golden/用例掩盖失败、伪造确认或验证证据。
28+- 加载固定项及当前阶段下发清单以外的 Skill、向 PM 或用户发起交互、等待其答复、派发 Agent、修改 harness 或调度状态、重置或回退其他节点。
29+- 将中间产物写出 $WORK_DIR,或使用不以 {{id}}- 开头的中间报告名;算子交付件按目标仓约定路径写入。
30+- 性能采集与优化验收、回顾与经验总结、PR、外部 CI 或合并事务。
31+- executor 编写或修改验收者报告、为等待验收报告而停止交付;verifier 重新构建、安装或运行测试、替执行者补造执行证据。
32+executor: ops-direct-invoke-architect
33+verifier: ops-direct-invoke-verifier
34+on_exhaust: exit
@@ -0,0 +1,70 @@
1+# {算子名称} 代码检视报告
2+ 
3+> 算子开发节点的 verifier 产出,与该节点的全量黑盒验收共同构成放行条件。对全部变更文件做多维度检视。本仓采用 direct launch 工程架构,须额外核对提交反作弊红线(当前任务指定的 A 类条款,违反 = 提交无效)。不通过时列出具体问题和证据,不自行回退上游任务。
4+ 
5+## 检视摘要
6+ 
7+- 产出节点 ID:{节点 ID}
8+- 被检视代码版本:{提交号或变更快照标识}
9+ 
10+| 维度 | 结果 | 详情 |
11+|------|------|------|
12+| 提交反作弊(A 类) | {通过/有问题} | A1–A7 全部通过,附代码证据 |
13+| 代码规范(B 类) | {通过/有问题} | B 类编码规则全部通过,附代码证据 |
14+| 需求与实现 | {通过/有问题} | 满足已确认需求和硬件约束,schema 对齐;不要求照搬知识搜集草稿 |
15+| 文档与实现同步 | {通过/有问题} | 见下方核对表 |
16+| 潜在风险 | {通过/有问题} | 越界、精度、并发等 |
17+| 冗余清理 | {通过/有问题} | |
18+ 
19+## 文档与实现同步核对
20+ 
21+> 算子开发阶段尚未生成白盒用例,不要求预先交付;尚未执行的文档准备不作为缺失产物。经历过回退迭代的交付件为重点核对对象——代码多轮更新而文档停留在早期快照。
22+ 
23+| 文档 | 声明内容 | 代码实际 | 是否一致 | 应刷新点 |
24+|------|----------|----------|----------|----------|
25+| {分支覆盖说明} | | | {一致 / 不一致} | |
26+| {当前实现记录与调整依据} | | | | |
27+| {交付说明 / 算子文档} | | | | |
28+ 
29+## 提交反作弊核对(A 类,零容忍)
30+ 
31+| 红线编号 | 条款 | 结果 |
32+|----------|------|------|
33+| A1 | 不调 PyTorch/torch_npu 计算代算 | {通过/违规} |
34+| A2 | 不用 PyTorch/torch_npu 处理输入输出 tensor | {通过/违规} |
35+| A3 | 不路由 CANN 内置同名算子 | {通过/违规} |
36+| A4 | 不 CPU fallback | {通过/违规} |
37+| A5 | 不缓存/固定/按地址命中输出 | {通过/违规} |
38+| A6 | 不篡改 profiler/timing API | {通过/违规} |
39+| A7 | 不返回 FakeTensor/懒求值包装器 | {通过/违规} |
40+ 
41+## 变更范围
42+ 
43+| 文件 | 变更类型 | 说明 |
44+|------|----------|------|
45+ 
46+## 问题清单
47+ 
48+### {编号}. {问题标题}
49+ 
50+- **维度**:{规范/一致性/风险}
51+- **严重程度**:{阻塞/高/中/低}
52+- **位置**:{文件:行}
53+- **描述**:{问题表现}
54+- **建议**:{修改建议}
55+ 
56+## 总结
57+ 
58+{整体质量评价}
59+ 
60+## 检视结论
61+ 
62+**结论**:{通过 / 不通过}
63+ 
64+{不通过时汇总结构化修改意见,指明 算子实现中的具体修改点}
65+ 
66+## 附录:修订记录
67+ 
68+| 版本 | 日期 | 修改内容 |
69+|------|------|----------|
70+| v1.0 | {YYYY-MM-DD} | 初始检视 |
@@ -0,0 +1,80 @@
1+# {算子名称} 功能验收报告
2+ 
3+> verifier 核对 executor 提供的本阶段真实用例运行证据,不重复构建或执行测试。算子开发节点检查全量黑盒;白盒测试节点记录黑盒回归与白盒运行,用例正确但暴露的算子缺陷交给代码修复。测试任务通过不代表所有算子用例通过,必须分别记录。
4+ 
5+## 验证摘要
6+ 
7+- 产出节点 ID:{节点 ID}
8+- 被验收代码与测试版本:{提交号或变更快照标识}
9+- 验收范围:{本阶段已确认的完整用例集}
10+ 
11+| 验证项 | 结果 | 详情 |
12+|--------|------|------|
13+| 编译验证 | {通过/失败} | {构建命令、退出码和日志路径} |
14+| schema 注册 | {通过/失败} | {与需求接口一致,`torch.ops.<pkg>.<op>` 可调用} |
15+| 精度验证 | {通过/失败} | {通过数}/{总数} 用例通过 |
16+| 白盒覆盖 | {通过/失败/本阶段未生成} | 源码路径与用例对应,实际命中、失败及受阻项分别列证据 |
17+ 
18+## 关键指标
19+ 
20+| 指标 | 值 |
21+|------|----|
22+| 评测/测试报告 | {测试入口输出和比对结果路径} |
23+| 用例总数 | {全量用例表条目数,含补充用例} |
24+| 通过率 | |
25+| golden 实现 | {测试方案约定的 golden 文件路径与版本} |
26+| 执行计数一致性 | {生成数 == 用例数 == 执行数} |
27+ 
28+## 测试明细
29+ 
30+| 用例编号 | 名称 | 结果 | 说明 |
31+|----------|------|------|------|
32+ 
33+## 源码与白盒用例对应
34+ 
35+| 源码分支 ID | 白盒设计条目 | 源码位置与条件 | 用例 ID | 实际命中证据 | 结论 |
36+|-------------|--------------------|----------------|---------|--------------|------|
37+ 
38+> 白盒用例覆盖以实际源码为准,不要求与知识搜集草稿一致。区分测试问题与被测算子缺陷,不能伪造覆盖;受算子缺陷影响的覆盖交给修复节点验证。
39+ 
40+## 失败用例
41+ 
42+{逐条列失败用例、现象、初步定位(附测试报告失败明细);无则填"无"}
43+ 
44+## 精度说明
45+ 
46+> 按测试方案精度判定口径表逐**输出张量**填写。实测值从 executor 提供的原始结果核对,并核验其对应当前源码、测试与构建产物版本(不只采信自述结论),最差用例指该输出张量上指标最差的那条用例。
47+ 
48+| 输出张量 | dtype | 判定指标 | 阈值 | 最差用例 | 实测值 | 权威源出处 | 结论 |
49+|----------|-------|----------|------|----------|--------|------------|------|
50+| | | | | | | | {达标 / 不达标} |
51+ 
52+| 项目 | 内容 |
53+|------|------|
54+| 比对基准 | {测试方案约定的 golden 文件路径与版本} |
55+| 权威口径实例化方式 | {口径断言的执行位置与本次执行方式} |
56+| 交叉核对(自建容差) | {结论;与权威口径不一致时标注该分叉,并说明以权威口径为准} |
57+| 口径一致性 | {口径表取值与权威源逐项一致 / 差异项及处理} |
58+ 
59+## 验收结论
60+ 
61+**用例运行结论**:{通过 / 不通过 / 本阶段未执行的范围}
62+ 
63+**当前任务结论**:{通过 / 不通过;白盒任务按用例质量与框架接入判定,算子缺陷列入修复交接}
64+ 
65+{不通过时给出结构化修改意见,标注问题语义归属并指明问题所在环节(算子实现 / 测试方案的精度判定口径)的具体修改点}
66+ 
67+## 测试环境
68+ 
69+| 项目 | 内容 |
70+|------|------|
71+| 目标芯片/架构 | {芯片} / {ascend910b / ascend910_93 / ascend950} |
72+| CANN 版本 | {版本} |
73+| 执行方式 | {测试入口命令及运行目录} |
74+| 测试依赖 | {实际使用的依赖和版本} |
75+ 
76+## 附录:修订记录
77+ 
78+| 版本 | 日期 | 修改内容 |
79+|------|------|----------|
80+| v1.0 | {YYYY-MM-DD} | 初始版本 |
@@ -0,0 +1,73 @@
1+# {节点 ID} {步骤名称} 测试执行记录
2+ 
3+> executor 产出,不代写验收结论。技术穿刺记录下发范围的代表用例;算子开发提供全量黑盒证据,白盒测试与代码修复提供全量黑盒和已接入白盒的证据;符合下述条件时可引用已有有效执行结果。原始输出、哈希清单和逐用例结果独立保存,本报告只给摘要与路径,不复制全文。
4+ 
5+## 验证范围
6+ 
7+- 本节点要验证的目标、关键疑点与采用路线:
8+- 本次范围及未验证范围:
9+- 下一轮可复用的代码、测试入口及证据绝对路径与版本:
10+ 
11+穿刺必须记录关键端到端组合在目标设备的运行结果;资料推导、CPU 自检或模拟执行不能代替。只对穿刺范围给结论,不宣称正式全量交付。
12+ 
13+## 证据清单与引用
14+ 
15+- 执行或复用:{本次新执行 / 复用;复用不计为新增设备执行}
16+- 输入与版本清单绝对路径:{每次真实执行生成一次 `<节点ID>-证据-r<轮次>/<节点ID>-清单.json` 或清单文本}
17+- 原始结果索引:{构建日志、测试命令及退出码、逐用例结果、加载记录的路径与哈希}
18+- 本次变更及复用判断:{差异路径、受影响项、复用来源与适用范围}
19+ 
20+清单覆盖需求、源码、注册/打包/构建配置、测试及用例 ID、golden、checker/阈值配置、随机种子、实际工具链/设备环境、wheel 和加载库。大清单单独保存,下文引用路径与条目,不重复抄写哈希或用例明细。清单与日志保留原版本,变更生成新的清单,引用必须落到具体执行轮次,不能使用会被覆盖的 latest 路径。只记录决定本次结果的输入,不对所有阅读资料重复计算哈希。
21+ 
22+## 版本与构建
23+ 
24+- 需求及测试方案版本:
25+- 源码、测试、golden 和构建入口的路径与哈希(包含未提交变更):
26+- 构建命令、工作目录、环境及退出码:
27+- 原始构建日志绝对路径:
28+- 构建产物绝对路径与哈希:
29+- 运行时实际加载模块路径与哈希(应与本次构建一致):
30+ 
31+## 本阶段运行
32+ 
33+- 测试入口、实际命令、运行目录及退出码:
34+- 原始输出、机器可读结果与逐用例明细路径:
35+- 本阶段用例清单及版本(正式交付全量;穿刺列代表用例):
36+- 实际设备型号与执行位置:
37+ 
38+| 范围 | 应执行数 | 实际执行数 | 通过 | 失败 | 跳过 | 未执行 |
39+|------|----------|------------|------|------|------|--------|
40+| 穿刺代表用例(正式开发不适用) | | | | | | |
41+| 黑盒(正式开发) | | | | | | |
42+| 白盒(未生成时不适用) | | | | | | |
43+ 
44+计数应与原始结果逐条一致,不能只给汇总通过率。逐输出记录精度指标、阈值、实测值及判定结果;源码分支覆盖区分设计覆盖、实际命中与受阻路径。复用与重跑按以下规则确定;不能使用旧版本日志掩盖当前失败。
45+ 
46+## 证据复用规则
47+ 
48+| 当前变化 | 必须完成的验证 |
49+|----------|----------------|
50+| 无待修复缺陷;决定结果的输入、版本、配置及设备环境一致;已有本阶段要求的全量成功记录 | 引用原始证据并核对当前交付与清单一致,不重复构建或测试 |
51+| 仅报告文字或许可注释变化 | 核对完整差异确实不影响执行,保留新旧哈希及映射;符合条件时复用,不声称重新构建或重跑 |
52+| Python logging 等可执行语句变化 | 不能按纯注释处理;验证受影响的输出、计数、退出码与异常行为。只有证实计算、参数、断言、控制流和执行环境未受影响时,才能复用原设备结果,否则重跑 |
53+| 算子计算、注册/包装、打包、编译配置或工具链变化 | 重建并运行本阶段要求的全量回归,复核实际加载路径和二进制 |
54+| 用例、golden、checker/阈值、数据生成、种子或测试逻辑变化 | 重新运行本阶段全量回归;候选构建输入未变时可复用 wheel。不得放宽标准消除失败 |
55+| 设备或运行环境变化;原证据缺失、不完整、含失败或无法对应当前版本 | 补齐当前环境下的完整验证;不能证明构建仍适用时重建 |
56+ 
57+穿刺代表用例不能替代正式全量;上一阶段黑盒通过不能替代新增白盒的执行。后续节点仍核对全量用例 ID 与结果,不能只引用上一份报告的 pass。复用时在本阶段报告记录来源及差异判断,verifier 独立确认复用条件;有疑点即要求执行者补证据,不由验收者代跑。
58+ 
59+## 失败与归属
60+ 
61+| 用例 ID | 现象与复现命令 | 原始证据 | 算子 / 测试 / 框架问题 | 影响范围 |
62+|---------|----------------|----------|-------------------------|----------|
63+ 
64+白盒阶段允许如实记录被正确用例暴露的算子缺陷,供下一节点修复;算子开发与修复交付要求本阶段全量通过。不能删测、放宽阈值或隐藏失败来取得通过。
65+ 
66+## 重试记录
67+ 
68+- 对应验收报告的问题编号及修复内容:
69+- 本次证据目录:{使用节点 ID 前缀及不同轮次后缀,保留前次日志}
70+- 修改后的文件与新哈希:
71+- 复用证据路径及有效性依据,或阻塞条件未变的复核结果:
72+ 
73+重试只补差异;失败、未运行和未验证项如实记录,不以重复生成报告替代修复。
@@ -0,0 +1,37 @@
1+# {算子名称} 白盒测试设计与用例接入
2+ 
3+> 算子实现后,developer 依据真实源码生成用例,直接写入已有 ST 框架。本文记录设计依据和接入结果,不能代替可执行用例。
4+ 
5+## 输入与版本
6+ 
7+- 算子源码及当前版本:
8+- 已确认需求与黑盒方案:
9+- 现有测试框架、入口与版本:
10+ 
11+## 源码分支清单
12+ 
13+| 分支 ID | 文件/函数/行号或条件原文 | 触发条件 | 边界及适用依据 |
14+|---------|-------------------------|----------|----------------|
15+ 
16+> 枚举全部有效的尾核、尾块、非对齐、多核、dtype 与 tilingkey 等分支;不适用项给出源码依据。知识搜集草稿不限制实际分支。
17+ 
18+## 白盒用例与框架接入
19+ 
20+| 用例 ID | 源码分支 | shape/dtype/参数 | 数据构造与预期结果 | 测试文件/入口 | 复用的黑盒用例 |
21+|---------|----------|-----------------|--------------------|---------------|----------------|
22+ 
23+- 全量执行命令:
24+- 新增/修改文件与用例发现方式:
25+- golden、精度及预期异常依据:
26+ 
27+## 覆盖记录
28+ 
29+| 源码分支 | 对应用例 | 设计覆盖依据 | 实际命中或受阻状态 | 证据路径 |
30+|----------|----------|--------------|--------------------|----------|
31+ 
32+## 问题交接
33+ 
34+| 问题 | 算子缺陷/测试问题/框架问题 | 复现步骤与证据 | 受影响路径 | 修复要求 |
35+|------|--------------------------|----------------|------------|----------|
36+ 
37+> 测试与框架问题须在本节点修正;用例正确但暴露的算子缺陷交给下游代码修复。没有缺陷时如实记录,无需制造问题。
@@ -0,0 +1,25 @@
1+# {算子名称} 知识搜集与实现草稿
2+ 
3+> 中立参考,不是锁定方案或路线可行性证明。只记录本轮重点,引用需求文件而非复述全文;不要求遍历资料库或给全部阅读文件计算哈希。
4+ 
5+## 关键资料与结论
6+ 
7+| 要解决的问题 | 关键结论 | 来源路径/链接、版本与位置 | 适用条件及限制 |
8+|-------------|----------|--------------------------|----------------|
9+ 
10+决定路线或 API 使用的引用须可核对。非关键资料未找到时记录未知,删除无依据断言;不为凑齐参考资料展开无关检索。新增 Skill 建议注明适用节点与阶段,仅供整轮结束后编排,不改变本轮清单。
11+ 
12+## 初版实现草稿
13+ 
14+| 候选路线及 API 组合/数据流 | 代表性 shape 分组 | 多核/块大小/Buffer/尾块设想 | 依据与待验证项 |
15+|---------------------------|------------------|----------------------------|----------------|
16+ 
17+区分资料已证实、推导建议和待验证假设;不逐个展开完整 shape 笛卡尔积,不宣称已实测或已完成性能验证。
18+ 
19+## 关键风险与下一步
20+ 
21+- 建议优先验证的关键组合与理由:
22+- 未确认限制或规则冲突及依据:
23+- 本次未覆盖的范围:
24+ 
25+重试只追加问题编号、修正结论及证据变化;保留历史,不重写未变内容。
@@ -0,0 +1,39 @@
1+# {节点 ID} {步骤名称} 验收报告
2+ 
3+> 仅 verifier 编写。通过、失败及阻塞均须落盘。验收者核对当前产物和执行证据,不代替执行者构建、运行全量测试或补造日志。
4+ 
5+## 验收对象与证据
6+ 
7+- 本轮节点及验收次数:
8+- 需求及输入版本:
9+- 当前交付件路径、源码/测试哈希或变更快照:
10+- 执行报告、固定版本的证据清单与原始结果索引路径:
11+- 本次变更及复用核对:{新执行 / 复用来源;当前版本差异与有效性判断}
12+- 实际加载的补充 Skill 与依据(无则记无):
13+ 
14+## 逐项结论
15+ 
16+| 验收项 | 通过 / 失败 / 阻塞 / 不适用 | 事实依据与文件位置 |
17+|--------|--------------------------|--------------------|
18+ 
19+涉及执行结果时,核对命令、工作目录、退出码、源码/测试/构建产物哈希、运行时加载路径和当前阶段用例计数、逐项结果。穿刺只要求下发范围的关键组合与代表用例真实设备证据;正式交付要求全量,二者不能互相代替。执行者自述通过不足以证明通过;缺失或无法核对的证据判失败。知识和文档节点按其交付标准审阅,不要求构建日志;知识搜集重点核对关键引用,不重做全库检索或要求所有阅读文件的哈希。报告只列结论和证据位置,不复制原始输出或已有哈希清单。按测试执行记录模板的证据复用规则核对当前版本及差异,原始日志与结果仍须可读取,不能只信上游 pass;复用结果不记为本次新执行。
20+ 
21+涉及代码检视时,列明检查范围、规则、问题位置和结论,可引用本节点的代码检视报告。白盒节点分别给出测试质量与算子功能结论:正确用例暴露算子缺陷时列出证据和下游修复要求,不宣称算子功能通过。
22+ 
23+## 问题与修改意见
24+ 
25+| 问题编号 | 严重程度 | 位置与证据 | 要求修正的内容 | 完成判据 |
26+|----------|----------|------------|----------------|----------|
27+ 
28+无问题写“无”。失败时给出可执行的修改要求,不只写 fail;超出本节点授权范围的缺口明确记录,不要求执行者越权修改。
29+ 
30+## 最终结论
31+ 
32+- 本节点:{pass / fail;阻塞属于 fail,并说明依据}
33+- 本阶段测试:{通过 / 不通过 / 本节点不适用;注明穿刺代表用例或正式全量范围}
34+- 代码检视:{通过 / 不通过 / 本节点不适用}
35+- 下游修复事项(仅已有流程允许时):
36+ 
37+同节点重试时,执行者只读本报告;验收者核对当前产物版本,复用未变且仍有效的证据,仅复核受影响项并追加本次结论,保留此前问题与处理记录,旧通过结论不能批准新版本。
38+ 
39+确定性阻塞条件未变时注明条件与依据,维持失败;不要求执行者重复同一完整调查,也不把阻塞标为通过。
@@ -0,0 +1,130 @@
1+# {算子名称} 黑盒测试设计
2+ 
3+> 黑盒测试设计阶段产出。本仓采用 direct launch 工程架构。architect 依据已确认需求设计 golden、分级用例与覆盖矩阵,复用符合契约的测试资产并补齐覆盖缺口。
4+> 本模板规定方案文档的格式与填写要求,覆盖维度分解、用例设计、精度口径及覆盖矩阵。
5+ 
6+## 1. 概述
7+ 
8+### 1.1 算子信息
9+ 
10+| 项目 | 内容 |
11+|------|------|
12+| 算子名称 | {算子名} |
13+| 接口原型 | `{签名}` |
14+| 支持数据类型 | {dtype 列表} |
15+| 目标芯片/架构 | {芯片} / {archXX} |
16+ 
17+### 1.2 算子功能
18+ 
19+{一句话描述算子功能}
20+ 
21+## 2. Golden 对齐方案
22+ 
23+### 2.1 Golden 计算方案
24+ 
25+| 项目 | 内容 |
26+|------|------|
27+| golden 实现位置 | {现有或计划实现的文件路径、调用入口} |
28+| Golden 计算路径 | {与需求数学定义一致,独立于被测 Kernel} |
29+| 精度比对方式 | {逐元素 / 统计指标;具体判定指标与阈值填 2.3 口径表} |
30+ 
31+### 2.2 测试工程与执行入口
32+ 
33+| 项目 | 内容 |
34+|------|------|
35+| 用例文件 | {实际或计划交付的用例文件路径} |
36+| 数据生成 | {输入生成入口、随机种子及预期输出生成方式} |
37+| 测试入口 | {编译、运行和比对命令,包含全量用例和补充用例} |
38+| 结果记录 | {用例计数、逐输出误差与判定的报告路径} |
39+ 
40+### 2.3 精度判定口径表(权威源对齐)
41+ 
42+> **本节记录精度判定的生效取值及权威来源,不得留「参考 XXX 标准」式引用**。逐**输出张量**填写:不同输出可能走不同口径(如整型输出按逐元素误差、浮点输出按相对误差统计量),不合并、不省略。逐项记录需求依据、指标定义和实际断言位置。
43+>
44+> 指标和阈值以已确认需求为准,逐项记录出处;资料或判定实现与需求冲突时记录差异及阻塞证据,不自行选取或放宽标准。
45+ 
46+| 输出张量 | dtype | 判定指标(公式或名称) | 阈值 | 权威源出处(文件路径 / 字段) | 实际 checker / 附加断言位置 |
47+|----------|-------|------------------------|------|------------------------------|------------------|
48+| | | | | | |
49+ 
50+**辅助交叉核对**(可选,不作通过依据):
51+ 
52+| 输出张量 | 辅助容差(atol / rtol 等) | 用途 |
53+|----------|---------------------------|------|
54+| | | 交叉核对,与权威口径结论不一致时以权威口径为准 |
55+ 
56+**口径一致性声明**:{本地判定口径与权威源逐项一致 / 存在差异——逐条列出差异项、差异原因、风险评估,并明确该差异对当前验收的阻塞影响}
57+ 
58+## 3. 覆盖维度分解
59+ 
60+> 把每个输入/属性拆成正交因子,逐因子列出取值集,作为下方场景与用例的推导源与覆盖矩阵的行。
61+ 
62+### 3.1 参数因子表
63+ 
64+| 参数 | 因子(存在性/format/rank/dtype/取值域/长度/值) | 取值集 | 来源(需求文档条目) |
65+|------|------|------|------|
66+ 
67+### 3.2 边界与特殊值清单
68+ 
69+> 按算子语义勾选适用项,删不适用带(如非负输入删负值)。
70+ 
71+- 数值边界:{ dtype min/max / 最小正规 / 次正规 }
72+- shape 边界:{ 最小 shape [1] / 单元素 / 末维非对齐 / 空 tensor / 0 维 }
73+- 特殊值:{ ±0 / +inf / -inf / nan }
74+- 广播(如适用):{ 等长 / 少维 / 多维 / 含 1 维 / 扩 1 轴 }
75+ 
76+## 4. 测试场景
77+ 
78+### 4.1 正常场景
79+ 
80+| 编号 | 场景描述 | 参数 |
81+|------|----------|------|
82+ 
83+### 4.2 边界场景
84+ 
85+| 编号 | 场景描述 | 参数 |
86+|------|----------|------|
87+ 
88+### 4.3 异常场景(参数校验)
89+ 
90+| 编号 | 异常输入 | 预期行为 |
91+|------|----------|----------|
92+ 
93+### 4.4 特殊值场景
94+ 
95+| 编号 | 场景描述 | 参数 |
96+|------|----------|------|
97+ 
98+## 5. 分级用例设计
99+ 
100+> L0 门槛(单因子最小覆盖,常规 shape/dtype,快,开发时验证);L1 功能(离散因子 pairwise + 典型/竞品 shape);L2 异常(每异常场景一条 + 空 tensor 派生)。逐项记录选值及其覆盖的需求维度。
101+ 
102+### 5.1 L0 门槛用例
103+ 
104+| 编号 | 描述 | 参数 | 预期结果 |
105+|------|------|------|----------|
106+ 
107+### 5.2 L1 功能用例
108+ 
109+| 编号 | 描述 | 参数 | 预期结果 |
110+|------|------|------|----------|
111+ 
112+### 5.3 L2 异常用例
113+ 
114+| 编号 | 描述 | 参数 | 预期结果 |
115+|------|------|------|----------|
116+ 
117+## 6. 覆盖矩阵
118+ 
119+> 从需求独立枚举声明维度,与全部用例逐维对照,供 verifier 核对。不得留「任意 / 不限」式开放上界;覆盖缺口在补充用例列标注。
120+ 
121+| 声明维度(dtype / shape 范围 / 边界 / 特殊值 / 广播) | 取值 | 命中用例编号 | 是否命中 | 补充用例编号(未命中时) |
122+|------|------|------|------|------|
123+ 
124+## 7. 汇总
125+ 
126+| 分级 | 用例数 |
127+|------|--------|
128+| L0 | |
129+| L1 | |
130+| L2 | |
@@ -0,0 +1,68 @@
1+# 仅在路线明确或穿刺通过后启动。PM 下发 Skill、复用路径和预算;task 路径相对本文件。
2+workflow: ops-direct-invoke
3+max_parallel: 2
4+nodes:
5+- id: '0.0'
6+ yaml: ../../tasks/知识搜集.yaml
7+ depends_on: []
8+ max_retries: 3
9+ variables:
10+ executor_skills: 无补充 Skill。
11+ verifier_skills: 无补充 Skill。
12+ research_focus: 重点搜集算子专项资料、目标芯片 API 组合和不同 shape 的初版 Tiling。
13+- id: '0.1'
14+ yaml: ../../tasks/黑盒测试设计.yaml
15+ depends_on: []
16+ max_retries: 3
17+ variables:
18+ executor_skills: 无补充 Skill。
19+ verifier_skills: 无补充 Skill。
20+- id: '1'
21+ yaml: ../../tasks/测试工程开发.yaml
22+ depends_on:
23+ - '0.0'
24+ - '0.1'
25+ max_retries: 3
26+ variables:
27+ executor_skills: 无补充 Skill。
28+ verifier_skills: 无补充 Skill。
29+- id: '2'
30+ yaml: ../../tasks/算子开发.yaml
31+ depends_on:
32+ - '1'
33+ max_retries: 3
34+ variables:
35+ executor_skills: |
36+ 候选 Skill(仅在实际证据命中时加载):
37+ - 自测或复现出现输出错误、精度不达标时,必须加载 `ascendc-precision-debug` Skill,按其中的要求执行。
38+ - 自测或复现出现卡死、超时、崩溃或内存访问异常时,必须加载 `ascendc-crash-debug` Skill,按其中的要求执行。
39+ verifier_skills: 无补充 Skill。
40+ knowledge_documents: $WORK_DIR/0.0-知识搜集.md
41+- id: '3'
42+ yaml: ../../tasks/白盒测试设计.yaml
43+ depends_on:
44+ - '2'
45+ max_retries: 3
46+ variables:
47+ executor_skills: 无补充 Skill。
48+ verifier_skills: 无补充 Skill。
49+- id: '4'
50+ yaml: ../../tasks/代码修复.yaml
51+ depends_on:
52+ - '3'
53+ max_retries: 3
54+ variables:
55+ executor_skills: |
56+ 候选 Skill(仅在实际证据命中时加载):
57+ - 自测或复现出现输出错误、精度不达标时,必须加载 `ascendc-precision-debug` Skill,按其中的要求执行。
58+ - 自测或复现出现卡死、超时、崩溃或内存访问异常时,必须加载 `ascendc-crash-debug` Skill,按其中的要求执行。
59+ verifier_skills: 无补充 Skill。
60+ repair_requirements: 根据本轮白盒测试设计节点的验收报告、测试执行记录与源码覆盖记录,修复暴露的算子代码缺陷;同步受影响的白盒用例,完成全量黑盒、白盒回归并提供证据供代码检视。没有待修复缺陷且当前版本已有有效全量证据时复用并记录依据,否则补齐验证。
61+- id: '5'
62+ yaml: ../../tasks/文档准备.yaml
63+ depends_on:
64+ - '4'
65+ max_retries: 3
66+ variables:
67+ executor_skills: 无补充 Skill。
68+ verifier_skills: 无补充 Skill。
@@ -0,0 +1,12 @@
1+# 路线有关键疑点时先独立穿刺;PM 下发前具体化范围和 Skill 清单,退出后再编排正式开发。
2+workflow: ops-direct-invoke
3+max_parallel: 1
4+nodes:
5+- id: '0'
6+ yaml: ../../tasks/技术穿刺.yaml
7+ depends_on: []
8+ max_retries: 3
9+ variables:
10+ spike_scope: 在已确认需求的芯片、架构和精度约束下,用最小代表 shape 验证待开发算子的关键端到端组合;覆盖原始任务中列出的技术疑点,记录未验证范围。不改变已确认的单 Kernel 或数据驻留要求。
11+ executor_skills: 无补充 Skill。
12+ verifier_skills: 无补充 Skill。
@@ -0,0 +1,3 @@
1+file,use_when
2+basic.yaml,一般算子开发任务
3+feasibility.yaml,快速验证方案有效性
@@ -0,0 +1,10 @@
1+---
2+name: repo-build-guide
3+description: 构建可供 CANN Bench 评测的 Ascend C 直调源码和 cann_bench wheel,检查真实加载路径与版本。编译、安装、调试构建问题时使用。
4+---
5+ 
6+# 仓库构建指南
7+ 
8+本仓采用 cann-bench `examples/direct_launch_example` 工程:bisheng 编译 kernel,g++ 编译注册包装,链接 `_C.abi3.so` 并生成 `dist/cann_bench*.whl`。评测器可从源码根目录调用 `bash build.sh`。
9+ 
10+读取 [构建与验证](references/build-guide.md),按当前环境、源码快照和目标芯片构建。构建成功、wheel 可导入与算子功能通过分别记录,不混为一个结论。
@@ -0,0 +1,42 @@
1+# 构建与版本核对
2+ 
3+## 构建输入
4+ 
5+记录 `source_dir`、cann-bench commit、Python 环境、CANN 路径和目标 SoC。环境信息来自本轮记录,不重复全面探测。构建在 `$WORK_DIR/<节点ID>-构建工程/` 的源码快照中执行,包含本次未提交代码,排除 `.cannbot/`、本轮工作目录、旧构建目录和二进制;记录与交付源码的对应哈希。算子计算、注册、打包代码、编译配置或工具链变化后更新快照并重建;仅测试用例变化不强制重建候选 wheel,但须记录与当前源码的对应关系。纯许可注释变更须核对完整差异、保留旧构建输入哈希及与当前源码的映射,不将旧 wheel 声称为新源码重新构建。
6+ 
7+官方脚本接受 `--soc=ascend910b`、`--soc=ascend910_93`、`--soc=ascend950`;前两者映射 `dav-2201`,950 映射 `dav-3510`。该值是编译平台名,不是性能 metadata 的硬件标签。根 `build.sh` 无参数时会自动检测;若检测无法确定平台,应先修正明确的环境/启动配置,保证评测器执行的 `bash build.sh` 也能复现,不能只验证一个外部手工命令。
8+ 
9+## 构建和导入
10+ 
11+在已选定的隔离 Python 环境中执行,以下 `build_dir` 为本轮快照绝对路径,`soc` 为已确认编译平台:
12+ 
13+```bash
14+cd "$build_dir"
15+bash build.sh --soc="$soc"
16+python3 -m pip install dist/cann_bench*.whl --force-reinstall --no-deps
17+```
18+ 
19+保留退出码和原始日志;wheel 应唯一且对应当前架构。示例 `build.sh --install` 也可安装,但须保证它调用的 pip 与评测 Python 是同一环境。不要在不同任务中并发重装同一个 `cann_bench` 包。
20+ 
21+从工程目录之外的新进程检查 `cann_bench.__file__`、`cann_bench._C.__file__`、目标 callable 与 schema,并记录实际加载文件哈希;不要让 `PYTHONPATH` 中旧工程或已安装 golden wheel 抢占导入。golden 自验证包与候选包同名,不能混用。Python 检查脚本使用 logging 输出。
22+ 
23+评测器发现预构建 wheel 时可能跳过编译;因此必须保存所用 wheel 的真实编译证据和源码→wheel→加载库的关联;有效复用时引用原构建轮次,不虚构本次编译。仅见到一个 dist 文件不代表它来自当前代码。不要使用 `--skip-install` 掩盖 wheel 更新遗漏。
24+ 
25+## 依赖与常见故障
26+ 
27+- 软件版本以当前 cann-bench 的 `pyproject.toml`、`uv.lock`、`requirements.txt` 和所选示例为依据;torch/torch_npu 必须匹配,不能单独升级 torch 破坏环境。
28+- 保留示例 CMake 的 `CMAKE_LINK_DEPENDS_USE_LINKER FALSE`,避免较新 CMake 给 bisheng linker 传入不支持的参数。
29+- 缺失 symbol、导入错误先核对目标架构、CANN 库路径、Python 环境和实际加载的 `_C`,不要把候选切换成 CPU/Torch 实现“修复”。
30+- cann-bench 的 `cann_bench_utils` 是独立的评测辅助扩展,不能把它当作候选 `cann_bench` 或删除它;缺失时按其官方构建入口在准备阶段处理。
31+- 官方评测会写编译日志并安装 wheel;使用快照和独立环境,避免污染交付源码或其它任务。构建失败直接保存原始错误,不临时挪走其它算子掩盖整批失败。
32+ 
33+构建记录包含命令、工作目录、环境来源、退出码、源码/测试清单及哈希、wheel 与实际加载库路径及哈希。功能结果另由真实设备评测提供,`test.sh` 的示例 pytest 不是完整验收。
34+ 
35+## 核对依据
36+ 
37+已核对 cann-bench `08d519c503843bce5fd4672ffa2259abeb22fb00`;运行时记录实际 checkout 版本,版本变化时核对相关接口。
38+ 
39+- [examples/direct_launch_example/build.sh](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/examples/direct_launch_example/build.sh)
40+- [examples/direct_launch_example/setup.py](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/examples/direct_launch_example/setup.py)
41+- [src/kernel_eval/data/package_manager.py](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/src/kernel_eval/data/package_manager.py)
42+- [docs/spec/submission_spec.md](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/docs/spec/submission_spec.md)
@@ -0,0 +1,10 @@
1+---
2+name: repo-coding-rules
3+description: CANN Bench 候选算子的实现真实性、包装边界、工程接口与 Ascend C 代码质量要求。编码、修复和检视时使用。
4+---
5+ 
6+# 仓库编码规则
7+ 
8+算子计算必须来自本工程的真实 NPU kernel,并符合 CANN Bench 的提交与运行接口。读取 [编码检查表](references/red-lines.md),按实际代码和证据检视;不要把静态规则套到测试 golden 上,也不把样例结构当作所有算子都适用的算法方案。
9+ 
10+违规项给出位置、影响和修正要求。规则只定义代码与交付质量,不持有调度状态、不指定流程回退。
@@ -0,0 +1,42 @@
1+# 编码检查表
2+ 
3+## A 类:候选实现真实性
4+ 
5+对应官方 `SUB-BEH-001`~`SUB-BEH-007`,违反时不能作为有效候选交付。适用范围是候选执行路径;独立 golden 和测试输入生成可以使用 Torch,不得因此被误判为候选代算。
6+ 
7+| 本仓编号 / 官方规则 | 检视内容 | 修正方向 |
8+|--------------------|----------|----------|
9+| A1 / SUB-BEH-001 | 包装层是否把全部或部分计算交给 Torch/torch_npu 内置计算 API | 由提交 kernel 实现;kernel 内 Ascend C 原语不属于包装层代算 |
10+| A2 / SUB-BEH-002 | 是否在包装层通过 transpose/contiguous/cast 等完成实质性数据或布局变换 | 变换纳入 kernel;参数读取、Tiling 准备和输出分配可以保留 |
11+| A3 / SUB-BEH-003 | 是否只转发到 CANN 内置同名算子 | 提供自有实现,不把接口包装当开发完成 |
12+| A4 / SUB-BEH-004 | CPU fallback、没有实际执行提交的 NPU kernel | 在目标设备真实执行并记录证据 |
13+| A5 / SUB-BEH-005 | 缓存输出、固定结果或按公开 case/data pointer 命中 | 对每次合法输入真实计算;有依据的 shape 分派不是预置答案 |
14+| A6 / SUB-BEH-006 | 篡改 profiler、同步、计时或安全检查 | 保持评测器及环境接口完整 |
15+| A7 / SUB-BEH-007 | FakeTensor、伪对象、惰性结果或非法返回结构 | 返回实际计算的 Tensor,符合输出结构与连续性要求 |
16+ 
17+自动保护没有报错不代表所有规则都通过;I/O 变换等仍需代码检视。报告应引用具体违规位置,不能只凭关键字命中判定。
18+ 
19+## B 类:工程与代码质量
20+ 
21+| 检查项 | 要求 |
22+|--------|------|
23+| 提交接口 | 根 build.sh 可复现生成 cann_bench wheel,Python callable、schema、C++ 注册与 proto 一致 |
24+| 版本与载入 | 当前源码、测试、构建 wheel 和实际加载库一致;没有旧包或 golden wheel 冒充候选 |
25+| 硬件资源 | 核数、UB/Buffer 与分块满足目标平台;动态资源查询或固定参数的适用依据明确,不无依据写死硬件假设 |
26+| 搬运与边界 | 用目标平台支持的 API 处理对齐、尾块和边界,地址/长度计算无溢出或越界;不以强制 wrapper 拷贝隐藏不支持输入 |
27+| 并发与同步 | 当前 stream/设备正确,依赖有对应同步,分配与释放、队列生产与消费成对;不把数调用次数当完整正确性证明 |
28+| 类型与数值 | dtype 分派与计算精度符合规格,未初始化变量、非法转换及未覆盖分支有检查 |
29+| API 可用性 | 关键 API 及变体有目标版本依据;不凭空推荐不存在的接口,不把一个示例的可用性推广到所有芯片 |
30+| 代码边界 | kernel 中不使用目标工具链不支持的动态分配、递归或库功能;具体支持情况按平台资料和编译证据核实 |
31+| 许可与输出 | 新增代码带仓库 license 头,保留上游来源许可;Python 日志使用 logging |
32+| 测试可信性 | 不改评测器、golden、阈值或删测掩盖失败;公开任务只读,新增用例和来源可追溯 |
33+ 
34+检视仅记录本次授权范围的问题与证据,不要求实现照搬知识搜集草稿,也不自行决定回退或放宽标准。
35+ 
36+## 核对依据
37+ 
38+已核对 cann-bench `08d519c503843bce5fd4672ffa2259abeb22fb00`;按实际 checkout 记录版本和差异。
39+ 
40+- [docs/guide/submission_rules.md](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/docs/guide/submission_rules.md)
41+- [docs/spec/submission_spec.md](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/docs/spec/submission_spec.md)
42+- [examples/direct_launch_example/README.md](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/examples/direct_launch_example/README.md)
@@ -0,0 +1,44 @@
1+---
2+name: repo-env-check
3+description: PM 检查 CANN Bench 直调算子开发及评测环境,持久化 .cannbot/环境信息.md;后续任务复用已有通过记录。
4+---
5+ 
6+# 仓库环境检查
7+ 
8+由 PM 在当前用户会话执行,不进入节点图。只检查环境,不安装、升级或修复依赖。首次需求缺项应先向用户发问,不等完整环境检查结束。
9+ 
10+## 复用与路径
11+ 
12+仓库级记录为 `<目标仓>/.cannbot/环境信息.md`。存在非空通过记录时直接复用,不因开发新算子重新运行 NPU、编译器或版本探测;复制为本轮 `$WORK_DIR/环境信息.md`,记录原始时间及来源,运行中只读。
13+ 
14+空记录、失败记录或当前任务超出记录支持范围时报告差异,不把文件存在当通过,也不自动重新校验。用户明确要求重新检查时保留旧版本,更新发生在工作流运行前或整轮退出后。
15+ 
16+## 首次检查清单
17+ 
18+仅在没有仓库级记录时执行;结果及原始日志放在 `.cannbot/环境检查/`,通过后按 [环境信息](references/环境信息.md) 发布仓库级记录。
19+ 
20+| 检查项 | 方法与通过依据 |
21+|--------|----------------|
22+| 评测源码 | 定位用户指定 checkout,或 `.cannbot/dependencies/ops-direct-invoke/cann-bench/`;记录 commit,确认 direct_launch_example、目标任务格式、kernel_eval CLI 可用 |
23+| NPU | `npu-smi info` 与所用 torch_npu 的设备信息;记录实际型号、可用设备 ID、状态及与需求目标的关系,不拿需求当检测结果 |
24+| CANN/编译器 | 已生效的 `ASCEND_HOME_PATH`、CANN 版本、bisheng/g++ 路径;核对当前 checkout 的要求与所选 SoC 映射 |
25+| Python/依赖 | 记录 Python 环境和版本、torch/torch_npu 的版本与导入;核对当前 pyproject/uv.lock/requirements 和示例依赖,不能盲目升级或重装 |
26+| 构建工具 | CMake、build/setuptools/wheel;直调示例要求 CMake ≥ 3.16,保留其新 CMake 链接兼容设置 |
27+| 评测组件 | 检查 kernel_eval CLI 的 help/任务发现、`cann_bench_utils` 是否可导入及其来源;缺失时报告准备项,不在检查中静默触发安装 |
28+| 仓库资产 | 记录候选源码目录、任务目录、已有 pytest/评测入口与算子文档线索;不把一次快照当作以后永久现状 |
29+ 
30+核对版本的官方快速入门要求 Python 3.10+、CANN 9.1.0+,实际依赖以当前 checkout 为准;torch/torch_npu 组合须按该版本的依赖和平台匹配。上述最低版本不等于任意版本组合都兼容,不宣称本次检查已完成 kernel 编译或设备精度验收。
31+ 
32+不要用 `scripts/run_evaluation.sh` 作无副作用探测:它可能构建辅助组件、安装候选包并运行评测。环境准备缺项由调用方安排修复,完成后再按授权复核;不得通过禁用保护组件绕过。
33+ 
34+## 完成条件
35+ 
36+缓存与本轮副本均非空,结论通过,包含 checkout/commit、Python 环境、设备、版本、支持范围和证据路径。后续源码构建、设备测试属于正常开发执行,不属于重复环境调查。
37+ 
38+## 核对依据
39+ 
40+已核对 cann-bench `08d519c503843bce5fd4672ffa2259abeb22fb00`;按实际 checkout 记录版本和差异。
41+ 
42+- [docs/guide/quick_start.md](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/docs/guide/quick_start.md)
43+- [requirements.txt](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/requirements.txt)
44+- [scripts/run_evaluation.sh](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/scripts/run_evaluation.sh)
@@ -0,0 +1,42 @@
1+# 仓库环境信息
2+ 
3+- 目标仓绝对路径:
4+- 检查时间、检查依据及日志目录:
5+- 结论:{通过 / 阻塞;仅通过版本发布为仓库级缓存}
6+ 
7+## CANN Bench 与工程
8+ 
9+| 项目 | 实际值与依据 |
10+|------|--------------|
11+| cann-bench checkout / commit | |
12+| direct_launch_example 路径 | |
13+| source_dir / 已有工程 | |
14+| 任务目录与版本 | |
15+| kernel_eval CLI / help或任务发现结果 | |
16+| cann_bench_utils 来源、版本与导入 | |
17+| 已安装 cann_bench 来源 | {候选 / golden / 未安装;不混用} |
18+ 
19+## 设备与软件
20+ 
21+| 项目 | 实际值 / 命令与结果 |
22+|------|--------------------|
23+| 实际 NPU 型号、数量、状态与可用 ID | |
24+| 目标 SoC 与实际设备是否对应 | |
25+| CANN 版本、ASCEND_HOME_PATH | |
26+| bisheng / g++ 路径与版本 | |
27+| Python 可执行文件与隔离环境 | |
28+| torch / torch_npu 版本与导入结果 | |
29+| CMake / build / setuptools / wheel | |
30+| 其它评测依赖与兼容性依据 | |
31+ 
32+## 资产线索与限制
33+ 
34+- 当前测试任务/入口与可复用内容:
35+- 当前算子文档目录与格式线索:{无则明确无}
36+- 支持的芯片、软件及用途范围:
37+- 未决问题及所需准备动作:
38+- 尚未执行的验证:{不得把检查包装成 kernel 编译或设备精度通过}
39+ 
40+## 复用
41+ 
42+仓库级路径为 `.cannbot/环境信息.md`,原始日志在 `.cannbot/环境检查/`。本轮复制到 `$WORK_DIR/环境信息.md`,记录原始时间和来源;不因换算子重新探测,也不改写运行中的副本。任务目录、代码和文档是否仍适用由使用者轻量核对当前文件。
@@ -0,0 +1,12 @@
1+---
2+name: repo-knowledge
3+description: CANN Bench 直调算子工程知识:评测任务、源码提交接口、精度与评分契约。理解本仓交付和评测要求时使用。
4+---
5+ 
6+# 仓库领域知识
7+ 
8+本仓开发通过 Ascend C `<<<>>>` 启动的算子,提交给 CANN Bench 的 CANN 评测后端。候选源码工程、评测任务数据与评测器是三个独立对象:源码实现算子,任务描述规格与 golden,用例由评测器加载并执行。
9+ 
10+源码交付保留 `cann_bench` 包及同名算子命名空间,以 `examples/direct_launch_example` 为工程基础。评测任务按 `proto.yaml`、`golden.py`、`cases.yaml`、`desc.md` 组织;同一评测接口承接黑盒、白盒和回归,不按用例来源划分工作模式。
11+ 
12+需要核对目录、接口发现、精度或评分含义时,读取 [评测契约](references/evaluation-contract.md)。本 Skill 只提供工程事实,不决定流程节点或替用户选择技术路线。
@@ -0,0 +1,48 @@
1+# CANN Bench 评测契约
2+ 
3+## 三个路径
4+ 
5+| 路径 | 内容 | 使用边界 |
6+|------|------|----------|
7+| `bench_root` | cann-bench checkout,含 `src/kernel_eval`、`scripts`、`examples` 与 `tasks` | 记录 commit;评测器、原始 golden 和公开用例不作为候选代码修改对象 |
8+| `source_dir` | 独立算子源码工程,含根 `build.sh`、`setup.py`、`cann_bench/`、`csrc/` | 构建产出 `dist/cann_bench*.whl`;不得依赖工作区外未交付的代码 |
9+| `task_dir` | 本次评测任务目录或其集合根 | 必须能发现实际目标算子和非空用例集;新增测试沿用相同格式 |
10+ 
11+插件依赖 checkout 位于 `<目标仓>/.cannbot/dependencies/ops-direct-invoke/cann-bench/`;已有用户指定 checkout 可直接使用,以本轮输入记录的绝对路径为准。CANN Bench 的 `kernel_eval` 是算子评测器,与负责 Agent 调度的 harness 不同。
12+ 
13+## 任务文件
14+ 
15+- `proto.yaml`:`operator.name/category/difficulty/formula/inputs/outputs/attrs/schema`,是接口和输入次序的依据;`desc.md` 补充语义。
16+- `golden.py`:与算子函数匹配的独立参考实现;评测器构造输入并调用它,候选执行路径不能调用它代算。
17+- `cases.yaml`:顶层 `cases` 列表,记录 `operator`、整数 `case_id`、`input_shape`、`dtype`、`attrs`、`value_range` 等;当前 CANN loader 读取此文件,只有 `cases.csv` 不足以执行。
18+- `metadata/<hardware>.json` 与 `metadata/VERSION`:对应硬件的性能锚点及版本。不能把示例 fixture 的零占位值当作真实基线。
19+- `tasks/level1`~`level4` 是算子难度分层,不是测试设计中的 L0/L1/L2 覆盖标签。
20+ 
21+`examples/tasks` 中 Add/Sqrt 用于验证评测链路,生产目标从当前评测任务中选择;名称匹配不证明 shape、dtype 和数学语义都匹配,需核对需求。
22+ 
23+## 源码、wheel 与接口
24+ 
25+1. 评测器接收已解包的 `source_dir`。没有 `dist/cann_bench*.whl` 时调用根目录 `bash build.sh`,要求返回 0 且生成 wheel。
26+2. wheel 必须可安装并 `import cann_bench`。本仓使用 `_C.abi3.so` 加载注册、`torch.ops.cann_bench.<schema函数>` 分派,`cann_bench/__init__.py` 必须导出目标同名 callable;只注册 C++ schema 而不导出 Python callable 不完整。
27+3. schema 的参数次序、类型、默认值与返回结构承接任务;不要把 `cann_bench` 当作任意可改的包名。用户要求另一外部接口时须保留评测适配契约并明确差异。
28+4. 原有 wheel 会影响评测是否重新构建。源码改变后不得用旧 wheel 冒充当前结果;交付目录中仅保留本次目标架构的有效产物。
29+5. 一份工程整体构建失败会影响该提交的所有算子;不能以只筛选某算子来掩盖工程其余编译错误。
30+ 
31+## 编译、精度与评分
32+ 
33+编译、功能精度、性能是不同结论。官方评测包含 HAP 性能评分;`--no-perf` 只证明相应功能精度与编译结果,不证明最终跑分或性能达标。输出报告需要保留实际评测版本、任务版本、目标硬件、源码和 wheel 版本。
34+ 
35+精度使用 CANN 后端的 `relative_error` checker,覆盖逐输出结构、整型精确比较、浮点正常值域、小值域和相消判定。指标取值来自当前评测器及算子配置;不得用 `allclose` 冒充整套判定,也不能修改评测器来迎合实现。
36+ 
37+性能以真实硬件 metadata 为锚点:`HAP = (T_baseline - T_HW) / ((T_cand - T_HW) + (T_baseline - T_HW))`。HAP 不是加速比;无效或缺失锚点不能推算可信分数。是否采集性能及采用什么交付门槛由任务明确,本 Skill 不擅自增加优化或提交步骤。
38+ 
39+网站上传规则与本地评测接口不同;未检查网站规则时不承诺打包目录可直接上传,也不执行 PR、上传或外部 CI。
40+ 
41+## 核对依据
42+ 
43+已核对 cann-bench `08d519c503843bce5fd4672ffa2259abeb22fb00`;运行时记录实际 checkout 版本,版本变化时核对相关接口。
44+ 
45+- [docs/spec/submission_spec.md](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/docs/spec/submission_spec.md)
46+- [examples/tasks/README.md](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/examples/tasks/README.md)
47+- [src/kernel_eval/benches/cann_loader.py](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/src/kernel_eval/benches/cann_loader.py)
48+- [README.md](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/README.md)
@@ -0,0 +1,15 @@
1+---
2+name: repo-op-templates
3+description: 从 cann-bench 的 direct_launch_example 复用直调工程骨架和算子模板;新建工程或新增算子时使用。
4+---
5+ 
6+# 算子工程模板
7+ 
8+工程来源为 cann-bench 的 `examples/direct_launch_example/`,保留它的构建、接口注册和 Python 导出约定。目标仓已经有兼容工程时就地扩展,不重建或覆盖已有代码。
9+ 
10+| 工作 | 参考 |
11+|------|------|
12+| 取得官方模板、建立工程骨架 | [工程骨架](references/project-skeleton.md) |
13+| 添加 kernel、launch、注册和 Python 接口 | [算子模板](references/operator-template.md) |
14+ 
15+模板是可运行工程的起点,不证明其 Add/Sqrt 的算法、dtype 或精度适合目标算子;按已确认规格完成实现。
@@ -0,0 +1,27 @@
1+# 新增直调算子
2+ 
3+以当前 checkout 中 `examples/direct_launch_example/csrc/ops/add/` 或 `sqrt/` 的真实文件为结构参考,复制到 `source_dir/csrc/ops/<op>/` 后调整名称与实现,保留许可头。
4+ 
5+| 文件 | 必须完成的内容 |
6+|------|----------------|
7+| `op_kernel/<op>_kernel.cpp` | Ascend C kernel、Tiling 与 `<<<>>>` 启动函数,bisheng 编译 |
8+| `op_kernel/<op>_launch.h` | g++ 可见的声明,保持参数、类型和 `extern "C"` 链接一致 |
9+| `op_plugin/<op>_plugin.cpp` | schema、Meta/输出分配、PrivateUse1 注册、当前设备 stream 与自有 kernel 调用 |
10+| `CMakeLists.txt` | 通过 `register_direct_launch_op` 注册源码和 include 目录 |
11+| `cann_bench/__init__.py` | 加载 `_C`,增加与目标函数匹配的 Python callable,转发到 `torch.ops.cann_bench` |
12+ 
13+注册宏有四个参数:kernel 源文件、kernel include 目录、plugin 源文件、plugin include 目录。使用官方同版本示例中的调用,不能把它缩写成只有两个源码参数的伪接口。
14+ 
15+schema 以本次任务 `proto.yaml` 的 `operator.schema` 为准:参数次序、可选值、attrs 默认值、输出结构都应一致。C++ 注册和 Python 导出同步更新;禁止保留示例的 Add/Sqrt 符号却声称实现了新算子。
16+ 
17+包装层可以查询 shape/dtype、做参数和 Tiling 计算、分配输出、获取 stream 并启动 kernel;不在这里调用 Torch/CANN 内置算子代算,也不对输入输出做实质性搬运、类型转换或布局变换。Meta 只定义输出元信息,不执行目标计算。
18+ 
19+API、Buffer、尾块、非对齐和 dtype 分派必须按目标算子验证。不能把示例只覆盖的类型和规模扩写成已支持范围;未知平台 API 用目标版本官方资料核实,缺少能力时记录限制。
20+ 
21+## 核对依据
22+ 
23+已核对 cann-bench `08d519c503843bce5fd4672ffa2259abeb22fb00`;运行时记录实际 checkout 版本,版本变化时核对相关接口。
24+ 
25+- [examples/direct_launch_example/csrc/ops/add/CMakeLists.txt](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/examples/direct_launch_example/csrc/ops/add/CMakeLists.txt)
26+- [examples/direct_launch_example/csrc/ops/add/op_plugin/add_plugin.cpp](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/examples/direct_launch_example/csrc/ops/add/op_plugin/add_plugin.cpp)
27+- [examples/direct_launch_example/cann_bench/__init__.py](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/examples/direct_launch_example/cann_bench/__init__.py)
@@ -0,0 +1,41 @@
1+# direct launch 工程骨架
2+ 
3+## 获取与复用
4+ 
5+优先使用本轮输入指定的 cann-bench checkout;插件依赖位置为 `<目标仓>/.cannbot/dependencies/ops-direct-invoke/cann-bench/`。读取其 commit 与 `examples/direct_launch_example/README.md`。来源缺失时,取得官方仓库到一个新目录并记录版本,不从文档中的省略代码拼造工程;下载和依赖准备不能阻塞首次需求问卷。
6+ 
7+新建工程时将 `examples/direct_launch_example/` 复制到已授权的 `source_dir`。现有工程只引入缺失部分,保留原来的算子和用户改动。官方示例源码与许可头一并保留;新增代码也带仓库 license 头,Python 输出使用 logging。
8+ 
9+## 应保留的文件
10+ 
11+```text
12+source_dir/
13+├── build.sh
14+├── setup.py
15+├── CMakeLists.txt
16+├── cmake/ # func、ascend、python、torch、torch_npu
17+├── scripts/build_wheel.sh
18+├── cann_bench/__init__.py # 加载 _C,导出候选函数
19+├── csrc/extension.cpp
20+├── csrc/CMakeLists.txt
21+├── csrc/ops/CMakeLists.txt # 自动发现算子目录
22+├── csrc/ops/<op>/
23+│ ├── CMakeLists.txt
24+│ ├── op_kernel/
25+│ └── op_plugin/
26+└── tests/ # pytest 仅作本地快速自检
27+```
28+ 
29+`cann_bench` 包名和导出接口是 CANN 评测输入的一部分,不做统一重命名。保留双编译器设置、平台映射、链接依赖和 ABI3 打包;不要用手写的近似 CMake/setup.py 取代现成工程。是否保留 Add/Sqrt 示例依据本次交付范围决定;在新复制的工程中去除示例时同步去除注册、Python 导出和对应测试,不能留下失效 import。
30+ 
31+构建和评测在 `$WORK_DIR/<节点ID>-构建工程/` 的本轮源码快照执行,避免官方脚本把 `build/`、`_compile.log` 等中间文件写到交付源码中。快照记录来源与哈希,排除 `.cannbot/`,不递归复制本轮工作目录,也不包含旧 `build/`、`dist/`、`*.egg-info` 或本地 `_C*.so`;已完成的源码仍交付在授权目录,构建快照不作为第二份源码继续独立修改。
32+ 
33+正式测试使用 cann-bench 任务目录与评测器;复制示例的 `tests/` 或执行其 `test.sh` 不能自动产生目标算子的完整评测用例。
34+ 
35+## 核对依据
36+ 
37+已核对 cann-bench `08d519c503843bce5fd4672ffa2259abeb22fb00`;运行时记录实际 checkout 版本,版本变化时核对相关接口。
38+ 
39+- [examples/direct_launch_example/README.md](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/examples/direct_launch_example/README.md)
40+- [examples/direct_launch_example/setup.py](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/examples/direct_launch_example/setup.py)
41+- [examples/direct_launch_example/CMakeLists.txt](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/examples/direct_launch_example/CMakeLists.txt)
@@ -0,0 +1,39 @@
1+---
2+name: repo-requirement
3+description: 收到算子开发需求后立即提取已知条件并填写 checklist,尽早对未决关键项发送简短问卷,形成可交接的需求清单。也用于后续需求修订。
4+---
5+ 
6+# 直调算子需求对齐
7+ 
8+在当前用户会话中完成,不作为 harness 节点执行。交付 `work_dir/需求分析.md`;work_dir 沿用调用方分配的 `.cannbot/<任务名>/workflow<序号>/`。内容按 [需求 checklist](references/requirement-checklist.md) 填写,任务是明确用户意图与开发边界,不替开发阶段完成技术方案或设备穿刺。
9+ 
10+## 首轮先识别缺项并提问
11+ 
12+开始需求对齐时,先向用户提示:“请先不要离开,我会先理解需求,可能需要和你对齐几个问题。”随后立即提取已知信息、识别关键缺项并发问,不等调查结束才提示。
13+ 
14+1. 从用户原话、已有答复和附件提取目标与限制;快速定位已有本地同名任务的 proto、golden 和接口说明,比较数学语义、布局、shape/dtype、attrs 及默认值,再提出候选规格。将影响交付的差异合并进首轮问卷,不先假定布局再返确认。只做可直接定位的读取;未找到或资料尚未下载时记录未知,及时提问,不先遍历源码、下载依赖或完成环境/API 调查。
15+2. 按 checklist 预填参数,给每项标明值、来源和状态。明确事实直接沿用;能由规格或仓库契约唯一推导的值填入并注明推导依据,不重复询问。名称相同但语义或范围可能不同的资料不能自动视为匹配。
16+3. 发现影响交付的未知项或冲突即整理首轮问卷,在深入调查前发出。不等所有技术细节查清才收集用户决定。优先确认算子语义/范围、接口、目标芯片和会改变交付标准的限制;每轮最多五题,工具限制更低时遵守工具限制。
17+4. 每题一句话说明待决事项,给出清晰且可区分的预设选项;能给出合理建议时推荐一项并简述依据,允许自由补充。不把整张 checklist 当问卷,不问用户已说明或仓库已有确定答案的字段。
18+ 
19+没有关键缺项时,不为凑问卷发问,直接进入清单核对。用户未提出且不会影响交付的用途背景、截止时间、偏好等记“未指定”,不为了填表逐一追问。
20+ 
21+## 推导边界
22+ 
23+- 本仓提交是 Ascend C `<<<>>>`、`cann_bench` Python 包与同名注册命名空间;已有目标 proto 的 schema、golden 和用例范围作为工程依据,保留具体来源与版本。不默认把所有 dtype/shape 都扩展到任意值。
24+- 精度承接当前 cann-bench CANN checker 及算子配置,记录取值和出处;用户没有额外精度要求时不要求用户重新选择每个阈值。标准冲突或用户提出另一指标时,说明区别并确认,不自行降低评测门槛。
25+- 芯片优先使用用户明确目标;没有指定时,可用已核对缓存中唯一可用目标作有依据的建议。目标与缓存不一致或存在多个可选目标时提问,不能将缓存事实写成用户已经选择。
26+- 技术路线只记录用户的硬约束和授权范围。未指定 SIMD/SIMT、Cube、框架或融合方式时记“未限定,在目标平台上按验证结果选择”,不强制用户预先拍板所有内部实现细节。不把技术可行性待验证误作需求缺失;是否需要穿刺交给调用方规划。
27+- 本地功能交付与实际跑分是不同结果。沿用用户的性能目标;仅要求开发算子且无额外性能门槛时,记录可评测源码及功能验证范围,不自行添加 HAP 阈值。用户明确要求实际分数或性能达标时,将其作为交付要求交调用方安排,不能因为现有模板没有性能节点就悄悄删去。
28+ 
29+## 答复、确认与交接
30+ 
31+问卷发出后保持待答,可并行核对不依赖答案的资料,但不启动依赖未决项的开发。真实答复回填对应条目;未答、预选项、超时或问卷消失都不算确认。问题工具不可继续使用时保留待答清单并在当前会话接续。
32+ 
33+向用户简短展示已提取的目标、关键范围及未决决定,让用户容易纠正。已有明确指令和答复足以覆盖当前需求时,记录确认依据,直接沿用,不再追加逐字段问卷或一次重复的总批准。存在影响实现或交付标准的推断/新取舍时,把它们汇入同一轮关键问题确认,不能把“推断”写成“用户已确认”。
34+ 
35+完成条件:必需规格有具体值或明确的授权范围,推导可追溯,关键冲突已解决,无需用户决定的内部技术选择明确留给后续验证。清单中没有阻断项后,返回绝对路径、版本、目标仓、算子及确认摘要。环境尚待检查、路线尚待穿刺分别交接,不宣称已验证,也不因这些调查延迟首轮问卷。
36+ 
37+全部需求已确认、问卷已答复且没有待用户决定的事项后,明确提示:“需求已确认,后续可以静默开发了,你可以先离开;完成后我会汇报结果,需要你决定的阻塞也会说明。”已有信息充分、无需发问时,在完成清单核对后同样提示。仍有待答问题时不得发出该提示;静默开发只在已确认的范围内推进,不把后续新增取舍视为已获批准。
38+ 
39+本 Skill 不编排 workflow、不调用其他 Skill、不修改 harness 状态。后续发现需求变更时,在当前用户会话中仅核对受影响条目并更新版本;旧确认不能批准新增限制或放宽标准。
@@ -0,0 +1,68 @@
1+# {算子名称} 需求清单
2+ 
3+## 基本记录
4+ 
5+- 清单版本与时间:
6+- 目标代码仓、source_dir 与 work_dir 绝对路径:
7+- cann-bench checkout/commit 与目标任务路径:{已定位则填写;未定位记待技术核对,不虚构}
8+- 用户目标摘要:
9+- 当前状态:{草稿待答 / 无阻断项可交接}
10+ 
11+## Checklist:先预填,再确认缺口
12+ 
13+每行记录实际值或可定位的规格引用,不把下表整份发送给用户。状态使用“用户明确 / 仓库契约 / 有依据推导 / 待用户决定 / 待技术核对 / 不适用”;只有需要用户选择的关键项未解决才构成需求阻断。
14+ 
15+| 完成 | ID | 核对项 | 预填来源与推导方法 | 何时需要提问 | 实际值、来源与状态 |
16+|------|----|--------|------------------|--------------|------------------|
17+| [ ] | R1 | 开发目标与范围 | 用户原话、已有实现;区分新建、修复或扩展 | 目标不同会改变产物或成功标准 | |
18+| [ ] | R2 | 算子数学语义 | 指定描述、proto、golden;核对同名任务 | 存在多个语义变体或资料冲突 | |
19+| [ ] | R3 | 接口与输出 | 沿用 schema、参数次序、attrs 默认值及输出结构 | 用户要求与现有接口不一致或必需字段未知 | |
20+| [ ] | R4 | shape/dtype/布局 | 提取用户范围及匹配规格;用例是覆盖依据,不自动扩大范围 | 支持范围、布局或边界语义存在影响实现的歧义 | |
21+| [ ] | R5 | 目标芯片及版本约束 | 用户目标优先;已有缓存给出事实与可选建议 | 多个目标可选、没有目标线索或软硬件要求冲突 | |
22+| [ ] | R6 | 精度标准 | cann-bench checker、thresholds 与 proto 配置 | 标准冲突、用户有额外要求或无有效依据 | |
23+| [ ] | R7 | 实现硬约束 | 用户指定的架构、单 Kernel、内存/依赖限制 | 存在需取舍的限制;未指定内部路线不必询问 | |
24+| [ ] | R8 | 交付与性能要求 | 源码、用例、证据、仓内文档及用户指定跑分目标 | 是否实际跑分/性能硬门槛不明确且影响交付 | |
25+| [ ] | R9 | 现有资产与路径 | 当前仓、匹配任务、源码及测试目录 | 授权修改范围冲突或存在多个无法判断的目标仓 | |
26+| [ ] | R10 | 原始要求与冲突 | 逐条映射原话到以上内容 | 仍有遗漏、矛盾或影响交付的新推断 | |
27+ 
28+## 已确定规格
29+ 
30+| 项目 | 内容与依据 |
31+|------|------------|
32+| 数学定义及特殊语义 | |
33+| schema/调用示例 | |
34+| 每个输入的 shape、dtype、layout | |
35+| 每个 attrs 的取值/缺省 | |
36+| 输出 shape/dtype/数量/结构 | |
37+| 广播、optional、空 tensor、异常输入约定 | {只填写适用范围,不凭空扩展} |
38+| 目标芯片与用户软件版本约束 | {要求与缓存实际值分开} |
39+| 架构及实现限制 | {未限定的内部技术选择注明由后续验证决定} |
40+| 代码/测试/文档交付位置 | |
41+| 性能目标与本轮验收范围 | {实际跑分、性能硬门槛或无额外门槛;不伪造测量结果} |
42+ 
43+### 精度依据
44+ 
45+| 输出/类型 | checker 与指标 | 实际阈值/生效配置 | 文件位置与版本 | 用户额外要求/冲突 |
46+|-----------|----------------|------------------|----------------|-------------------|
47+ 
48+常用标准已有来源时直接填入,不逐项问用户选数值;缺少技术取值时记待核对,启动相关任务前补齐。不能只写“参考某标准”,也不能用人工选定 atol/rtol 替代 cann-bench 判定。
49+ 
50+## 首轮待决项与答复
51+ 
52+| 问题 ID / 关联条目 | 简短问题与预设选项 | 推荐依据 | 用户答复/待答 | 对应版本 |
53+|-------------------|-------------------|----------|---------------|----------|
54+ 
55+只有真实需要选择的项放在此处。已明确内容不重复询问;未知但不影响交付的偏好记未指定。未回答的推荐值保留“待答”。
56+ 
57+## 原始要求与交接
58+ 
59+| 用户原话/答复位置 | 对应条目 | 沿用或变更说明 |
60+|------------------|----------|----------------|
61+ 
62+- 当前确认依据:{已给指令/真实答复及覆盖范围;不能将推断伪装成用户决定}
63+- 未解决的用户决定:{无则写无;存在则保持草稿}
64+- 后续技术核对项:{环境检查、路线证据等;不写成已通过}
65+- 源码/评测资产复用线索:
66+- 本轮交付与非目标:
67+ 
68+最终检查:原话无遗漏;关键参数有来源;范围明确;无未决关键取舍;内部技术选择有授权边界;源码与评测契约的冲突没有被静默忽略。
@@ -0,0 +1,17 @@
1+---
2+name: repo-test-develop
3+description: 基于 CANN Bench 组织 proto、golden、cases.yaml,复用 kernel_eval 执行直调算子的黑盒、白盒及回归测试。设计测试或接入评测工程时使用。
4+---
5+ 
6+# 仓库测试开发
7+ 
8+本仓使用 CANN Bench 的 CANN 任务格式与 `kernel_eval` 评测器。测试工程的工作是准备目标任务、补齐用例并接入评测入口,不另建一套 gen_data/run/精度比对框架。已有评测任务与代码可复用,全部需求范围内的用例统一验收。
9+ 
10+| 工作 | 参考 |
11+|------|------|
12+| 任务目录、用例格式、统一执行入口及证据 | [测试工程](references/test-framework.md) |
13+| 按规格设计黑盒覆盖与补充用例 | [黑盒设计](references/blackbox-design.md) |
14+| 将源码分支用例写入现有任务集 | [白盒设计](references/whitebox-design.md) |
15+| 精度 checker、阈值与评分含义 | [精度与性能](references/precision-and-perf.md) |
16+ 
17+任务决定执行代表用例还是全量回归;穿刺的局部通过不能代替正式全量交付。原始评测文件和候选工程分开,禁止改 golden、阈值、评测器或删测掩盖算子错误。
@@ -0,0 +1,30 @@
1+# 黑盒用例设计
2+ 
3+以确认规格及任务 `proto.yaml`、`desc.md`、`golden.py`、`cases.yaml` 为输入。核对已有用例与需求范围,补充真正的覆盖缺口;不把已有用例反向当作全部需求,也不盲目展开参数笛卡尔积。
4+ 
5+## 覆盖与规模
6+ 
7+| 维度 | 设计要点 |
8+|------|----------|
9+| 接口 | 参数次序、attrs 默认值、optional、输出数与 dtype |
10+| shape | rank、广播、归约轴、相等/不等约束、最小值、对齐与非对齐、典型规模 |
11+| 数值 | 需求范围内的正负、小值、极值、零与适用的 NaN/Inf 语义 |
12+| 交互 | 对会影响结果的跨参数依赖做代表组合,避免无依据的全组合 |
13+| 异常 | 只测试规格定义的拒绝行为,正常边界与非法输入分开 |
14+ 
15+L0 标记快速代表集,L1 标记常规功能组合,L2 标记边界或异常。它们是测试设计标签,可写在 `note` 和覆盖矩阵中,不改 proto 的算子难度 `L1`~`L4`,也不使用评测器的 `--level` 过滤测试标签。
16+ 
17+每个新增 case 保留唯一整数 ID、输入参数、预期语义和覆盖目的。需求中的不适用值域不强加,例如数学定义不接受的负数不能塞进正常精度用例。空 tensor 与 rank=0 标量是不同语义;是否支持依据需求和 golden,而非自动都加进范围。
18+ 
19+## 产物
20+ 
21+在本轮方案中列出规格→case ID 的覆盖矩阵、golden 函数与版本、逐输出 checker/阈值的实际取值和来源、评测命令及补充测试入口。测试工程将其物化为 `cases.yaml` 和必要测试代码,按 [测试工程](test-framework.md) 的格式与入口执行。
22+ 
23+公开原始用例保持只读;新任务或补充用例写入授权测试目录并记录来源。已有 golden 满足规格时直接复用,不为形式完整重新实现。只有资料冲突或无法确定语义时报告待决项,不修改预期结果配合当前 kernel。
24+ 
25+## 核对依据
26+ 
27+已核对 cann-bench `08d519c503843bce5fd4672ffa2259abeb22fb00`;实际运行记录所用版本。
28+ 
29+- [docs/spec/cases_yaml_spec.md](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/docs/spec/cases_yaml_spec.md)
30+- [examples/tasks/README.md](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/examples/tasks/README.md)
@@ -0,0 +1,75 @@
1+# CANN Bench 最小接入自检
2+ 
3+以下接口已按 `08d519c503843bce5fd4672ffa2259abeb22fb00` 核对。使用实际 checkout 时核对版本;不要根据类名猜接口。自检记录按当前节点编号放入工作目录,先跑代表用例,再做正式全量发现与验证。
4+ 
5+## 目录、签名与调用
6+ 
7+- 工程源码与评测任务分开。任务采用 `tests/cannbench/tasks/levelN/<op>/`;CLI `--task-dir` 指向 tasks 根目录,`--operator` 选择目标。直接使用官方任务时也以其 tasks 目录为根。
8+- `CannTaskLoader`、`CannCaseLoader`、`GoldenLoader` 均从 `kernel_eval.benches.cann_loader` 导入;当前没有 `CannGoldenLoader`。传任务根目录,方法参数使用 `levelN/<op>`。
9+- `proto.yaml` 提供 `operator.name`、`schema`、`difficulty`、有序 inputs、attrs 和 outputs;difficulty 使用官方枚举,目录 level 分类与 proto 难度字段分别保留,不凭名称推测。
10+- golden 函数名与 schema 一致。Tensor 参数必须有含 `Tensor` 的类型注解,例如 `x1: torch.Tensor`;TensorList、Optional 按实际接口标注,属性给出正确类型及默认值。`ParamBuilder.build_call_params` 用签名区分 Tensor 和 attrs,未标注的参数可能漏绑;函数能直接调用不等于 loader 接入成功。
11+- 用真实 `ParamBuilder` 生成参数并用 `inspect.signature(...).bind(**params)` 检查缺项;再实际调用 golden。输入和输出 dtype、shape、数量及结构按接口核对,FP16 输出合同不要求 FP64 中间结果 bit-exact。CPU 测试不能代替设备精度验收;golden 需要设备能力时记录限制并在相应环境验证。
12+- 报告冒烟必须包含非空算子条目及真实 `rel_path`,覆盖 JSON、Markdown、HTML 输出;空报告无法暴露 level 路径解析错误。报告中的模拟条目明确标为自检,不计作候选运行或通过证据。
13+ 
14+## 可运行的 Add 接入样例
15+ 
16+在已准备依赖的环境中,设置 `PYTHONPATH="$bench_root/src"`。下面的 Python 片段保存为当前工作目录下带节点 ID 的自检脚本;参数依次为 `$bench_root/examples/tasks`、本节点新建的自检输出目录、`<节点ID>-接入自检-r<轮次>` 报告前缀。它只调用官方 Add golden 的一个代表用例,并用一个标为 skipped 的占位条目检查报告输出链路(零设备执行),不安装候选包。
17+ 
18+```python
19+# Copyright (c) 2026 Huawei Technologies Co., Ltd.
20+# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
21+# CANN Open Software License Agreement Version 2.0 (the "License").
22+# Please refer to the License for details. You may not use this file except in compliance with the License.
23+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
24+# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
25+# See LICENSE in the root of the software repository for the full text of the License.
26+import inspect
27+import logging
28+import sys
29+from pathlib import Path
30+from kernel_eval.config import Config, set_config
31+ 
32+set_config(Config(device_type="cpu"))
33+from kernel_eval.benches.cann_loader import CannTaskLoader, CannCaseLoader, GoldenLoader
34+from kernel_eval.data.data_generator import DataGenerator
35+from kernel_eval.utils.param_builder import ParamBuilder
36+from kernel_eval.report.report_generator import EvalReport, EvalResult, OperatorReport, ReportGenerator
37+ 
38+logging.basicConfig(level=logging.INFO, format="%(message)s")
39+root, output, report_id = sys.argv[1:]
40+rel_path = "level2/add"
41+task = CannTaskLoader(root).get_task(rel_path)
42+cases = CannCaseLoader(root).scan_by_rel_path(rel_path)
43+assert task is not None and cases, "任务或用例未发现"
44+golden = GoldenLoader(root).get_golden_function(rel_path)
45+case = cases[0]
46+inputs = DataGenerator().generate_input_tensors_from_case(
47+ case.input_shapes, case.dtypes, case.value_ranges, seed=0)
48+params = ParamBuilder().build_call_params(golden, case, inputs)
49+inspect.signature(golden).bind(**params)
50+result = golden(**params)
51+assert result.device.type == "cpu"
52+assert result.shape == inputs[0].shape and result.dtype == inputs[0].dtype
53+logging.info("CPU golden 接入成功:发现 %d 例,执行 1 例;未运行候选 kernel", len(cases))
54+report = EvalReport(
55+ framework_version="selfcheck", tasks_version="selfcheck", eval_code=report_id,
56+ timestamp="selfcheck", device="cpu", total_operators=1, total_cases=1,
57+ passed_cases=0, failed_cases=0, overall_score=0,
58+ operators=[OperatorReport(rel_path=rel_path, operator="Add", total_cases=1,
59+ cases=[EvalResult(rel_path=rel_path, operator="Add", case_id="selfcheck",
60+ status="skipped", error_msg="仅报告接口自检,未执行候选")])],
61+ summary={"pass_rate": 0.0, "purpose": "报告接口自检,无候选执行"})
62+paths = ReportGenerator(output_dir=output, eval_code=report_id).save_all(report)
63+assert all(Path(path).stat().st_size for path in paths.values())
64+logging.info("JSON/Markdown/HTML 生成成功:%s", paths)
65+```
66+ 
67+实际目标任务自检必须替换为目标路径、代表用例及输出合同,不能以 Add 通过证明目标已接入。进一步核对完整用例 ID 和数量;使用同一 checker 做适用的正负对照,确保错误输出会失败,不能只比较 golden 自身得出精度结论。CPU 自检结果与 NPU 评测结果分别记录。
68+ 
69+## 核对来源
70+ 
71+- [官方 Add 任务](https://gitcode.com/cann/cann-bench/tree/08d519c503843bce5fd4672ffa2259abeb22fb00/examples/tasks/level2/add)
72+- [加载器](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/src/kernel_eval/benches/cann_loader.py)
73+- [参数绑定](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/src/kernel_eval/utils/param_builder.py)
74+- [目录解析](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/src/kernel_eval/utils/path_resolver.py)
75+- [报告生成](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/src/kernel_eval/report/report_generator.py)
@@ -0,0 +1,36 @@
1+# 精度与评分口径
2+ 
3+## 精度执行
4+ 
5+本仓用 CANN 后端注册的 `relative_error` checker。标准来源是所用版本的 `src/kernel_eval/utils/thresholds.py`、`compare.py`、`checkers/relative_error_checker.py` 及算子 proto 中的 `precision_thresholds` 配置;在测试方案中记录实际生效配置,不另写近似判定器。
6+ 
7+已核对版本的正常浮点值域采用 MERE 与 MARE 双条件,MARE 门槛是 threshold 的 10 倍,均使用严格小于;常用 dtype 基础 threshold 如下,算子覆写和实际配置必须另行核对:
8+ 
9+| dtype | threshold |
10+|-------|-----------|
11+| float16 | `2**-10` |
12+| bfloat16 | `2**-7` |
13+| float32 | `2**-13` |
14+| 整型 | 精确匹配 |
15+ 
16+这张表不构成完整判定。checker 还处理输出结构/连续性、小值域、相消、NaN/Inf 等;不能只实现上述两个指标或 `torch.allclose` 就宣布等价。浮点判定使用评测器提供的高精度 golden 与需要时的同精度 CPU 对照,输入生成和 dtype 处理交给现有实现。
17+ 
18+逐输出保留实际生效的指标、阈值、实测统计与 pass/fail;保留原始机器可读报告,不把内部 checker 结果改写为更宽松的自建结论。用户标准更严格时另做附加断言;与正式评测契约冲突时在需求阶段明确差异,不放宽 cann-bench 标准以换取通过。
19+ 
20+## 性能与跑分
21+ 
22+`--no-perf` 适用于功能验证;不能据此报告 HAP、性能通过或最终综合分达标。任务明确要求跑分时,使用同版本评测器开启性能采集,保留硬件标签、metadata 版本、每例候选耗时、baseline 与硬件锚点及真实报告。
23+ 
24+`metadata/<hardware>.json` 保存 `baseline_perf_us` 和 `t_hw_us`。`examples/tasks` 的零值 fixture 不能用于真实性能比较,补充黑盒/白盒缺少锚点时不能伪造得分;官方原始任务的跑分与扩展用例回归分别记录,不能用扩展集合冒充官方分数。
25+ 
26+HAP 是硬件锚定评分而非 speedup,不能擅自给所有算子添加 HAP ≥ 0.5、带宽差 20% 等门槛。是否有性能硬目标由需求决定,流程未安排性能测量时仅声明功能验证与可评测工程交付,不宣称性能达标。
27+ 
28+## 核对依据
29+ 
30+已核对 cann-bench `08d519c503843bce5fd4672ffa2259abeb22fb00`;实际运行记录所用版本。
31+ 
32+- [src/kernel_eval/utils/thresholds.py](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/src/kernel_eval/utils/thresholds.py)
33+- [src/kernel_eval/utils/compare.py](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/src/kernel_eval/utils/compare.py)
34+- [src/kernel_eval/checkers/relative_error_checker.py](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/src/kernel_eval/checkers/relative_error_checker.py)
35+- [docs/design/precision_comparison_design.md](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/docs/design/precision_comparison_design.md)
36+- [README.md](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/README.md)
@@ -0,0 +1,75 @@
1+# CANN Bench 测试工程
2+ 
3+## 目录与复用
4+ 
5+`bench_root` 为已记录版本的 cann-bench checkout;`source_dir` 为候选源码;`task_dir` 为本轮采用的任务根目录(`tests/cannbench/tasks/`),`rel_path` 为 `levelN/<op>`;`bench_root` 不与任务根目录混用。检查已有任务的算子名、schema、规格和用例,复用匹配资产;补充内容写入目标仓授权的 `tests/cannbench/tasks/levelN/<op>/`,使用同一文件格式与同一评测器,不更改上游任务。
6+ 
7+```text
8+tests/cannbench/tasks/levelN/<op>/
9+├── proto.yaml # operator、schema、输入输出和属性
10+├── desc.md # 数学及接口语义
11+├── golden.py # 与 schema 匹配的独立参考函数
12+└── cases.yaml # cases 列表:保留原用例并加入黑盒/白盒补充
13+```
14+ 
15+已有任务也保留 `tasks/levelN/<op>` 层次,CLI 的 `--task-dir` 传 tasks 根目录,并用 `--operator` 选择目标;loader 传同一根目录及相对路径。当前 HTML 报告器解析 `levelN/<op>`,不要把裸 `<op>` 目录当评测根目录。N 沿用已有分类或记录新的分类,不由算子名猜测。原始任务根目录可作为只读 `task_dir`;需要补充时创建上述可交付任务目录,保留原有用例 ID 和内容,记录来源 commit、新增 ID 与覆盖映射。没有目标任务时按确认规格创建完整目录。两者使用相同测试契约,不增加工作流分支。`metadata/` 只在确需真实性能锚点时按当前版本格式使用,不制造 baseline。
16+ 
17+## 先验证接入
18+ 
19+先按 [最小接入自检](cannbench-integration.md) 验证 loader、golden 签名与参数绑定、代表输入和报告生成,再展开全量用例。接入自检通过只证明测试工程能工作,不是 NPU 精度通过。
20+ 
21+## cases.yaml
22+ 
23+例为双输入 Add 的数据格式,不代表目标算子的完整测试集:
24+ 
25+```yaml
26+cases:
27+- operator: Add
28+ case_id: 1
29+ input_shape: [[17, 33], [17, 33]]
30+ dtype: [float32, float32]
31+ attrs: {}
32+ value_range: [[-1, 1], [-1, 1]]
33+ note: 黑盒边界;非对齐
34+```
35+ 
36+- `operator` 与 proto 一致,`case_id` 为目录内唯一整数;`input_shape`、`dtype`、`value_range` 按 proto 输入顺序对应。
37+- optional 缺省使用 `null` 占位;TensorList 用嵌套列表,不能靠省略位置改变参数绑定。
38+- 当前 loader 读取 `cases.yaml`,不是 `cases.csv`;如保留 CSV 展示文件要同步它,不能只改 CSV。
39+- 不添加评测器不认识的 `expected_exception` 等字段并假设会执行。异常输入若无法用当前 loader/checker 表达,使用明确的补充 pytest 检查接口异常,单独报告结果,不混入正常精度用例的通过数。
40+- 使用评测器的数据生成、golden 加载及 checker。特殊确定性输入若不能由现有字段表达,依据当前接口实现必要的补充测试,并复用相同 checker;不得默默退回 `allclose`。
41+ 
42+## 执行入口
43+ 
44+先确认 Python 环境及 `cann_bench_utils` 已准备好。官方 `scripts/run_evaluation.sh` 会准备辅助组件并安装候选包;本仓记录报告编号时直接使用同仓 CLI。以下路径均为绝对路径,`build_dir` 是位于 `$WORK_DIR` 的当前源码构建快照;`node_id`、`attempt` 和 `device_id` 来自本次任务,设备必须属于授权资源。
45+ 
46+```bash
47+PYTHONPATH="$bench_root/src${PYTHONPATH:+:$PYTHONPATH}" python3 -m kernel_eval.cli eval \
48+ --bench-name cann --source-dir "$build_dir" --task-dir "$task_dir" \
49+ --operator "$op" --device npu --device-id "$device_id" \
50+ --reports-dir "$WORK_DIR/$node_id-评测-r$attempt" \
51+ --eval-code "$node_id-精度-r$attempt" --eval-seed 0 --no-perf
52+```
53+ 
54+命令完整保留原始日志和退出码;每次使用新报告目录。精度执行不需要性能采集,`--no-perf` 不等于关闭真实性检查。显式传设备避免默认占用全部卡;相同 Python 环境的候选安装不得并发互相覆盖。
55+ 
56+开发期可加 `--case-id <整数>` 定位或穿刺,正式全量验收去掉该筛选。先核对实际发现数,再与报告执行数逐项对齐;零用例、漏算子、跳过或部分通过都不能称为全量通过。补充 pytest 也必须记录其数量、结果和日志。
57+ 
58+## 不同任务的交付边界
59+ 
60+- 测试工程准备:核对 proto/cases 可发现、golden 可调用、数据生成与断言可用,提供入口和用例映射;尚无 kernel 时不能伪报设备精度通过。
61+- 算子开发:执行完整黑盒,记录当前源码构建与设备结果。
62+- 白盒接入:在已有 cases 中加入源码分支用例,运行黑盒和白盒;归属明确的算子失败交修复,测试自身错误须修好。
63+- 修复交付:黑盒、白盒及必要补充测试全量通过;已有有效证据的复用遵从当前 task,不使用旧代码日志证明新代码。
64+ 
65+官方 JSON/Markdown/HTML 报告保存原样,阶段记录给出带节点 ID 的结果路径、任务/源码/wheel/加载库版本和哈希、用例计数及失败归属。验收者只读证据,不重新构建或执行。示例 `test.sh` 仅运行示例 pytest,不代表目标算子已通过 cann-bench。
66+ 
67+## 核对依据
68+ 
69+已核对 cann-bench `08d519c503843bce5fd4672ffa2259abeb22fb00`;实际运行记录所用版本。
70+ 
71+- [examples/tasks/level2/add/proto.yaml](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/examples/tasks/level2/add/proto.yaml)
72+- [examples/tasks/level2/add/cases.yaml](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/examples/tasks/level2/add/cases.yaml)
73+- [docs/spec/cases_yaml_spec.md](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/docs/spec/cases_yaml_spec.md)
74+- [src/kernel_eval/cli.py](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/src/kernel_eval/cli.py)
75+- [src/kernel_eval/report/report_generator.py](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/src/kernel_eval/report/report_generator.py)
@@ -0,0 +1,19 @@
1+# 白盒用例接入
2+ 
3+从当前 kernel、Tiling 和 dispatch 源码出发,记录有效分支的文件、函数、条件与版本;覆盖尾核/尾块、对齐、dtype、多核划分及适用的 tilingkey。知识搜集草稿不约束实际分支。
4+ 
5+1. 对每个分支反推需求范围内的输入,采用阈值两侧、整除/非整除等代表参数;已有黑盒命中时复用 ID,不为凑数量重复造例。
6+2. 把新增正常用例写入同一授权任务目录的 `cases.yaml`,使用未占用的整数 ID,在 `note` 和阶段覆盖记录中注明源码条件。沿用原 proto、golden 与 checker,不另建数据生成/比对框架。
7+3. 需求定义的异常或无法由 YAML 表达的输入按 [测试工程](test-framework.md) 接入补充测试;必须进入统一回归清单,不只提交设计文档。
8+4. 运行当前任务要求的黑盒与白盒,记录实际执行数、结果和证据。区分源码推导可覆盖、执行中实际命中和因缺陷受阻,不能把推导当实测覆盖。
9+ 
10+测试或接入错误由测试工作修复;正确用例暴露 kernel 缺陷时记录失败 ID、复现命令和证据,保留用例及失败结果,供代码修复使用。源码修改后复核受影响分支与用例映射,最终交付必须通过全量回归。
11+ 
12+测试文件是目标仓交付件;分支映射和运行报告按本节点 ID 写入 `$WORK_DIR`。不修改被测算子、原始评测任务、golden 或阈值掩盖失败。
13+ 
14+## 核对依据
15+ 
16+已核对 cann-bench `08d519c503843bce5fd4672ffa2259abeb22fb00`;实际运行记录所用版本。
17+ 
18+- [docs/spec/cases_yaml_spec.md](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/docs/spec/cases_yaml_spec.md)
19+- [src/kernel_eval/benches/cann_loader.py](https://gitcode.com/cann/cann-bench/blob/08d519c503843bce5fd4672ffa2259abeb22fb00/src/kernel_eval/benches/cann_loader.py)
@@ -0,0 +1,72 @@
1+#!/usr/bin/env python3
2+# ----------------------------------------------------------------------------
3+# Copyright (c) 2026 Huawei Technologies Co., Ltd.
4+# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
5+# CANN Open Software License Agreement Version 2.0 (the "License").
6+# Please refer to the License for details. You may not use this file except in compliance with the License.
7+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
8+# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
9+# See LICENSE in the root of the software repository for the full text of the License.
10+# ----------------------------------------------------------------------------
11+ 
12+"""Guard the registry inventory, node IDs, dependencies and task references."""
13+import sys
14+import unittest
15+from pathlib import Path
16+ 
17+sys.dont_write_bytecode = True
18+sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
19+from support import WORKFLOWS, assert_graph, load_yaml, registered_workflows, run_tests
20+ 
21+ 
22+class RegistryTests(unittest.TestCase):
23+ def test_registry_covers_all_workflow_templates(self):
24+ entries = registered_workflows()
25+ for field in ['file']:
26+ values = [entry[field] for entry in entries]
27+ self.assertTrue(all(isinstance(value, str) and value.strip() for value in values))
28+ self.assertEqual(len(values), len(set(values)), f'duplicate workflow {field}')
29+ files = {str(path.relative_to(WORKFLOWS)) for path in WORKFLOWS.rglob('*')
30+ if path.suffix in {'.yaml', '.yml'}}
31+ self.assertEqual({entry['file'] for entry in entries}, files, 'missing or obsolete registry entry')
32+ 
33+ def test_basic_keeps_research_implementation_whitebox_and_repair_order(self):
34+ entries = registered_workflows()
35+ self.assertEqual({entry['file'] for entry in entries}, {'basic.yaml', 'feasibility.yaml'})
36+ graph = load_yaml(WORKFLOWS / 'basic.yaml')['nodes']
37+ actual = [(node['id'], load_yaml(WORKFLOWS / node['yaml'])['title'], node['depends_on'])
38+ for node in graph]
39+ self.assertEqual(actual, [
40+ ('0.0', '知识搜集', []), ('0.1', '黑盒测试设计', []),
41+ ('1', '测试工程开发', ['0.0', '0.1']), ('2', '算子开发', ['1']),
42+ ('3', '白盒测试设计', ['2']), ('4', '代码修复', ['3']), ('5', '文档准备', ['4'])])
43+ self.assertTrue(all(node['max_retries'] == 3 for node in graph))
44+ for node in graph[:2]:
45+ self.assertEqual(load_yaml(WORKFLOWS / node['yaml'])['executor'], 'ops-direct-invoke-architect')
46+ 
47+ def test_every_registered_graph_and_task_reference(self):
48+ for entry in registered_workflows():
49+ with self.subTest(workflow=entry['file']):
50+ self.assertEqual(set(entry), {'file', 'use_when'})
51+ self.assertTrue(entry['use_when'].strip())
52+ path = (WORKFLOWS / entry['file']).resolve()
53+ self.assertTrue(path.is_relative_to(WORKFLOWS.resolve()), 'workflow escapes template directory')
54+ self.assertTrue(path.is_file(), path)
55+ self.assertNotIn('nodes', entry, 'graph belongs only in the referenced template')
56+ template = load_yaml(path)
57+ self.assertEqual(set(template), {'workflow', 'max_parallel', 'nodes'})
58+ assert_graph(self, template['nodes'])
59+ for node in template['nodes']:
60+ self.assertEqual(set(node), {'id', 'yaml', 'depends_on', 'max_retries', 'variables'})
61+ self.assertIsInstance(node['yaml'], str)
62+ task = load_yaml((WORKFLOWS / node['yaml']).resolve())
63+ self.assertIsInstance(task, dict)
64+ self.assertNotIn('max_retries', task)
65+ self.assertIs(type(node['max_retries']), int)
66+ self.assertEqual(node['max_retries'], 3, 'registered templates default to three retries')
67+ self.assertNotIn('id', task, 'identity belongs in the registry, not the task')
68+ self.assertNotIn('depends_on', task, 'dependencies belong in the registry, not the task')
69+ 
70+ 
71+if __name__ == '__main__':
72+ run_tests()
@@ -0,0 +1,43 @@
1+#!/usr/bin/env python3
2+# ----------------------------------------------------------------------------
3+# Copyright (c) 2026 Huawei Technologies Co., Ltd.
4+# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
5+# CANN Open Software License Agreement Version 2.0 (the "License").
6+# Please refer to the License for details. You may not use this file except in compliance with the License.
7+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
8+# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
9+# See LICENSE in the root of the software repository for the full text of the License.
10+# ----------------------------------------------------------------------------
11+ 
12+"""Deterministic Codex CLI stand-in; no model, network or harness internals."""
13+import json
14+import logging
15+import os
16+import sys
17+from pathlib import Path
18+ 
19+logging.basicConfig(level=logging.INFO, format='%(message)s', stream=sys.stdout)
20+work = Path(os.environ['WORKFLOW_PROBE_DIR'])
21+prompt = sys.argv[-1]
22+verification = 'Procedure:' in prompt
23+capture = work / 'provider-calls.jsonl'
24+calls = [json.loads(line) for line in capture.read_text().splitlines()] if capture.exists() else []
25+report = work / '0-验收报告.md'
26+seen_report = report.read_text() if report.exists() else ''
27+with capture.open('a') as stream:
28+ stream.write(json.dumps({'prompt': prompt, 'verification': verification,
29+ 'report': seen_report}, ensure_ascii=False) + '\n')
30+if verification:
31+ prior_verifications = [call for call in calls if call['verification']]
32+ if not prior_verifications:
33+ report.write_text('RETRY_FEEDBACK_SENTINEL: missing boundary case')
34+ logging.info(json.dumps({'type': 'item.completed', 'item': {
35+ 'type': 'agent_message', 'text': report.read_text()}}))
36+ reply = 'fail'
37+ else:
38+ reply = 'pass' if any('RETRY_FEEDBACK_SENTINEL' in call['report']
39+ for call in calls if not call['verification']) else 'fail'
40+ report.write_text('pass: prior feedback addressed' if reply == 'pass' else 'fail')
41+else:
42+ reply = 'executed'
43+logging.info(json.dumps({'type': 'item.completed', 'item': {'type': 'agent_message', 'text': reply}}))
@@ -0,0 +1,63 @@
1+#!/usr/bin/env python3
2+# ----------------------------------------------------------------------------
3+# Copyright (c) 2026 Huawei Technologies Co., Ltd.
4+# This program is free software, you can redistribute it and/or modify it under the terms and conditions of
5+# CANN Open Software License Agreement Version 2.0 (the "License").
6+# Please refer to the License for details. You may not use this file except in compliance with the License.
7+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
8+# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
9+# See LICENSE in the root of the software repository for the full text of the License.
10+# ----------------------------------------------------------------------------
11+ 
12+"""Probe retry feedback through the real public CLI with a deterministic provider."""
13+import json
14+import os
15+import shutil
16+import subprocess
17+import sys
18+import tempfile
19+import unittest
20+from pathlib import Path
21+ 
22+sys.dont_write_bytecode = True
23+sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
24+import support
25+from support import SCRIPTS, SKILL_ROOT, run_tests
26+ 
27+ 
28+class RetryFeedbackTests(unittest.TestCase):
29+ def test_retry_preserves_report_but_does_not_inject_verifier_feedback(self):
30+ with tempfile.TemporaryDirectory(prefix='workflow-feedback-') as temp:
31+ work = Path(temp)
32+ binaries = work / 'bin'
33+ binaries.mkdir()
34+ cli = binaries / 'codex'
35+ shutil.copyfile(Path(__file__).parent / 'fixtures/codex.py', cli)
36+ cli.chmod(0o755)
37+ definition = work / 'workflow.yaml'
38+ assembled = subprocess.run([
39+ sys.executable, str(SCRIPTS / 'assemble_workflow.py'),
40+ str(SKILL_ROOT / 'tasks/知识搜集.yaml'), '--max-retries', '1',
41+ '--output', str(definition)], capture_output=True, text=True, timeout=30)
42+ self.assertEqual(assembled.returncode, 0, assembled.stderr)
43+ env = {**os.environ, 'PATH': str(binaries) + os.pathsep + os.environ['PATH'],
44+ 'WORKFLOW_PROBE_DIR': str(work)}
45+ result = subprocess.run([
46+ sys.executable, str(support.HARNESS_SKILL / 'scripts/orchestrator.py'),
47+ '--yaml', str(definition), '--work-dir', str(work), '--provider', 'codex',
48+ '--prompt', 'CLI contract probe only; no real operator development'],
49+ env=env, capture_output=True, text=True, timeout=30)
50+ self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
51+ calls = [json.loads(line) for line in (work / 'provider-calls.jsonl').read_text().splitlines()]
52+ self.assertEqual([call['verification'] for call in calls], [False, True, False, True])
53+ initial, retry = calls[0], calls[2]
54+ self.assertEqual(initial['prompt'], retry['prompt'])
55+ self.assertNotIn('RETRY_FEEDBACK_SENTINEL', retry['prompt'])
56+ self.assertIn('0-验收报告.md', retry['prompt'])
57+ self.assertIn('RETRY_FEEDBACK_SENTINEL', retry['report'])
58+ status = json.loads((work / '.workflow/status.json').read_text())['tasks']['0']
59+ self.assertEqual((status['status'], status['retries']), ('pass', 1))
60+ 
61+ 
62+if __name__ == '__main__':
63+ run_tests()