Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions skills/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# TransformerEngine-FL Upgrade Skills

这组 skills 用于维护 TransformerEngine-FL 与任意上游 TransformerEngine release 之间的升级流程。它们不绑定具体版本;每次运行通过 `base`、`fork`、`target` 三个 ref 参数确定范围。

## 用途

这套流程覆盖:

- FL fork 设计基线和差异分类;
- plugin manager、registry、policy、discovery 和各硬件 backend;
- `transformer_engine_torch` 动态 alias、enum、callable public contract;
- PyTorch attention/device 等侵入式 runtime patch;
- C++/CUDA 构建、wheel、CMake 和 third-party submodule;
- GitHub Actions、硬件 CI、QA 和测试矩阵;
- 升级后的证据汇总、回滚和交付。

## 目录

| Skill | 作用 |
|---|---|
| `te-upgrade-orchestrator` | 按 gate 串联完整升级流程 |
| `te-classify-fork-delta` | 生成 fork 差异清单和设计基线 |
| `te-integrate-upstream-conflicts` | 分类和解决 upstream/fork 冲突 |
| `te-audit-plugin-api` | 审计 plugin/native/Python API 和动态 alias |
| `te-preserve-runtime-patches` | 保护 runtime 侵入式修改及跨模块调用链 |
| `te-integrate-build-submodules` | 审计构建、打包、CUDA 和 submodule |
| `te-audit-cicd` | 审计 CI/CD、硬件矩阵和 QA 入口 |
| `te-run-upgrade-test-matrix` | 执行 import、GPU、backend 和回归测试 |
| `te-finalize-upstream-upgrade` | 汇总证据并生成交付决策 |

## 推荐用法

在仓库根目录开始,先创建工作分支,不要直接在 `main` 上操作:

```bash
git switch -c chore/te-upgrade-<date>
```

然后按以下顺序使用:

```text
1. te-classify-fork-delta
2. te-integrate-upstream-conflicts
3. te-audit-plugin-api
4. te-preserve-runtime-patches
5. te-integrate-build-submodules
6. te-audit-cicd
7. te-run-upgrade-test-matrix
8. te-finalize-upstream-upgrade
```

也可以直接使用 `te-upgrade-orchestrator`,它会检查每个阶段的 artifact、ref 一致性、P0 决策和用户审批。

## 参数和 artifact

典型参数:

```text
base = 上游共同基线 ref
fork = 当前 FL 分支/ref
target = 要升级到的上游 ref
```

所有中间结果放在:

```text
/share/project/zhaoyingli/flagos/temp/<run-name>/
```

不要把审计结果或生成文件放到 `/tmp`。每个阶段都应记录:输入 refs、输出 artifact、owner、验收命令和 `preserve/adapt/drop` 决策。

## 关键验收原则

- fork-owned plugin、runtime、build 和 CI 文件不能因 whole-file/tree replacement 被删除;
- 动态 `transformer_engine_torch` 必须与目标 release 的 Python/native public contract 对齐;
- enum、sentinel、import-time callable 和签名必须逐项检查;
- runtime 修改按“定义—导入—alias—调用”链验证;
- 每个 backend、CI surface、submodule 和测试入口都有 owner 或明确排除理由;
- GPU、reference、plugin manager 和 staged import 测试结果必须分开记录;
- 未经用户批准,不执行 merge-to-main、push、PR、tag 或 release。

## 本仓库当前实例

本仓库外部 artifact 中保存了本次 FL 设计基线和升级证据;仓库内的 skills 保持版本无关,只提供可复用流程和验收标准。
35 changes: 35 additions & 0 deletions skills/te-audit-cicd/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
name: te-audit-cicd
description: Audit TransformerEngine-FL GitHub Actions, CI configs, QA entrypoints, reusable workflows, local actions, runner labels, and vendor test coverage after an upstream upgrade. Use when .github, qa, workflow matrices, hardware backends, or CI scripts may be stale or silently incomplete.
---

# Audit TransformerEngine-FL CI/CD

Perform a static audit before relying on remote CI. Do not edit workflows or trigger jobs in this skill.

## Workflow

1. Read the fork-delta inventory and identify changed workflow, config, script, and QA paths.
2. Parse every YAML workflow/config; report syntax and duplicate-key failures.
3. Resolve local action, reusable-workflow, script, Dockerfile, config, and test-entrypoint references. Compare fork-only workflows against the target tree and require an explicit preserve/remove decision; never assume upstream absence means deletion.
4. Extract vendor/backend and test-group matrices dynamically. Compare supported plugin backends with CI coverage and mark intentional exclusions.
5. Check runner labels, images, permissions, secrets, event triggers, path filters, and failure masking.
6. Run shell syntax checks for referenced scripts and static QA entrypoint checks.
7. Write a coverage matrix and require owner/reason for every missing or blocked path.

## Outputs

Write cicd-audit.json, workflow-matrix.tsv, missing-references.tsv, cicd-audit.md, and raw parser logs under /share/project/zhaoyingli/flagos/temp/<run>.

## Acceptance Criteria

- Every workflow/config parses or has an owned blocker.
- Every local reference resolves. Fork-only workflows and CI configs remain in the merged tree unless an explicit removal decision has evidence.
- Every discovered plugin backend has CI coverage or an explicit exclusion.
- Vendor matrices and test groups have no unexplained gaps.
- Permissions, triggers, runner labels, and secrets are recorded.
- Referenced shell scripts pass syntax checks or have an owned blocker.
- No workflow silently suppresses test failures. Do not use tree replacement or whole-file theirs resolution on fork-owned workflows.
- Audit is deterministic, main unchanged, and all artifacts are under /share/project/zhaoyingli/flagos/temp, never /tmp.

Do not infer CI success from YAML syntax alone.
4 changes: 4 additions & 0 deletions skills/te-audit-cicd/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "TE CI/CD Auditor"
short_description: "Audit workflows and vendor CI coverage"
default_prompt: "Use $te-audit-cicd to validate TransformerEngine-FL workflows, QA entrypoints, and vendor test coverage."
7 changes: 7 additions & 0 deletions skills/te-audit-cicd/references/rules.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# CI/CD Audit Rules

Check uses: ./path, workflow_call workflows, shell commands, and config paths. A path existing locally but not in the target commit is stale.

Record vendor coverage by backend identity, not workflow filename. Separate unsupported hardware from omitted tests. Inspect continue-on-error, || true, if: always(), and upload-only jobs for failure masking.

Record permissions and secrets because pull_request and pull_request_target have different trust boundaries.
28 changes: 28 additions & 0 deletions skills/te-audit-cicd/scripts/audit_cicd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env python3
import argparse,json,re,subprocess
from pathlib import Path
def main():
ap=argparse.ArgumentParser(); ap.add_argument('--repo',type=Path,required=True); ap.add_argument('--ref',required=True); ap.add_argument('--output',type=Path,required=True)
a=ap.parse_args(); repo=a.repo.resolve(); a.output.mkdir(parents=True,exist_ok=True)
def run(*x): return subprocess.run(['git','-C',str(repo),*x],text=True,errors='replace',capture_output=True)
ref=run('rev-parse','--verify',a.ref+'^{commit}').stdout.strip()
files=run('ls-tree','-r','--name-only',ref).stdout.splitlines()
wf=[p for p in files if p.startswith('.github/workflows/') and p.endswith(('.yml','.yaml'))]
cfg=[p for p in files if p.startswith('.github/configs/') and p.endswith(('.yml','.yaml'))]
rows=[]; missing=[]; masks=[]
for path in wf+cfg:
text=run('show',ref+':'+path).stdout; rows.append({'path':path,'nonempty':bool(text.strip()),'syntax':'unverified'})
for local in re.findall(r'uses:\s*\./([^\s#]+)',text):
local=local.rstrip('/')
if local not in files and not any(x.startswith(local+'/') for x in files): missing.append({'source':path,'reference':local})
masks += re.findall(r'\|\|\s*true|continue-on-error:\s*true',text,re.I)
vendors=sorted({p.split('/')[5] for p in files if p.startswith('transformer_engine/plugin/core/backends/vendor/') and len(p.split('/'))>5 and p.split('/')[5]!='__init__.py'})
alltext='\n'.join(run('show',ref+':'+p).stdout for p in wf)
coverage=[{'backend':v,'covered':v.lower() in alltext.lower(),'reason':''} for v in vendors]
data={'ref':ref,'workflows':rows,'configs':cfg,'missing_references':missing,'backend_coverage':coverage,'failure_masks':sorted(set(masks))}
(a.output/'cicd-audit.json').write_text(json.dumps(data,indent=2)+chr(10))
(a.output/'workflow-matrix.tsv').write_text('backend\tcovered\treason\n'+''.join(x['backend']+'\t'+str(x['covered']).lower()+'\t\n' for x in coverage))
(a.output/'missing-references.tsv').write_text('source\treference\n'+''.join(x['source']+'\t'+x['reference']+'\n' for x in missing))
(a.output/'cicd-audit.md').write_text('# CI/CD Audit\n\n'+'- Workflows/configs: '+str(len(rows))+'\n- Missing local references: '+str(len(missing))+'\n- Failure masks: '+str(len(set(masks)))+'\n')
print(json.dumps({'output':str(a.output),'workflows':len(rows),'missing':len(missing),'failure_masks':len(set(masks))}))
if __name__=='__main__': main()
49 changes: 49 additions & 0 deletions skills/te-audit-plugin-api/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
name: te-audit-plugin-api
description: Audit TransformerEngine-FL plugin API compatibility against an upstream release. Use when upstream pybind bindings, Python call sites, enums, dataclasses, or attention signatures change; when adding/removing plugin ops; or when verifying every implementation and registration across dynamically discovered backends.
---

# Audit TransformerEngine-FL Plugin API

Use an isolated tree and exact base, fork, and target refs. This skill audits before edits; it does not invent fallbacks or silently suppress missing APIs.

## Workflow

1. Read the fork-delta and conflict inventories. Require their refs to match.
2. Extract target pybind exports, Python-side tex call sites, plugin base methods, registered op names, and backend methods.
3. Compare base and target signatures, including multiline definitions, constructors, enum types, dataclasses, and AttentionParams fields.
4. Build a matrix: symbol, upstream status, plugin base, CUDA/reference/FlagOS/vendor implementations, registration, signature risk, disposition, owner, test.
5. Dynamically discover backends from transformer_engine/plugin/core/backends. Never use a hard-coded vendor list.
6. Classify each gap as required, intentionally unsupported, fallback, or obsolete. Every non-required disposition needs a written reason.
7. Update code only after the matrix is approved. Re-run the audit after each API change.

## Outputs

Write under /share/project/zhaoyingli/flagos/temp/<run>:

- api-inventory.json
- api-matrix.tsv
- api-audit.md
- raw upstream/plugin symbol lists
- decisions.tsv

## Acceptance Criteria

- Base/fork/target SHAs match the upstream and conflict inventories.
- Binding extraction includes all binding files and macro-generated exports considered.
- Every target export and Python call site has a matrix row.
- Every matrix row records base/target signature status and enum/dataclass risk.
- Every required symbol has a base stub, implementation, registration, and focused test.
- Every backend is dynamically discovered and has native/fallback/unsupported status per required symbol.
- No unexplained missing, stale, duplicate, or signature-mismatch symbols remain.
- Allowlisted unsupported symbols have owner, reason, and test or blocked evidence.
- Re-running the audit is deterministic and produces identical symbol sets.
- All artifacts are under /share/project/zhaoyingli/flagos/temp; never /tmp.

Stop on macro-generated exports not accounted for, mismatched refs, ambiguous capability, or unapproved API decisions.

## Dynamic public-module contract

When the fork registers `transformer_engine_torch` dynamically, audit that alias as a first-class public surface. Compare Python import-time consumers against both the native binding and the plugin-provided module, including enum member sets, sentinel values, signatures, and required callables. Run the audit in staged imports so the first exception does not hide later incompatibilities.

Acceptance additionally requires: `transformer_engine.pytorch.constants`, `pytorch.cpp_extensions`, and full `transformer_engine.pytorch` imports pass; all public enum sets used at import time match; every deliberate plugin-only difference has an owner, rationale, and test.
4 changes: 4 additions & 0 deletions skills/te-audit-plugin-api/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "TE Plugin API Auditor"
short_description: "Audit plugin API and backend coverage"
default_prompt: "Use $te-audit-plugin-api to compare upstream bindings with TransformerEngine-FL plugin coverage."
14 changes: 14 additions & 0 deletions skills/te-audit-plugin-api/references/decision-rules.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# API Audit Decision Rules

A symbol is required when upstream Python code calls it, the fork's plugin contract exposes it, or a supported backend needs it. A pybind export alone may be intentionally unsupported only with an explicit reason.

Check more than function names:

- parameter order, defaults, and keyword names;
- enum domains and conversion at the tex boundary;
- dataclass/NamedTuple fields such as AttentionParams;
- return tuple shape and optional values;
- registration priority and availability predicate;
- backend capability and fallback semantics.

Never use *args/**kwargs to conceal a signature mismatch unless the target CUDA implementation itself uses it and the exception is recorded.
38 changes: 38 additions & 0 deletions skills/te-audit-plugin-api/scripts/audit_plugin_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env python3
import argparse,json,re,subprocess
from pathlib import Path
def git(repo,*args):
p=subprocess.run(["git","-C",str(repo),*args],text=True,errors="replace",capture_output=True)
if p.returncode: raise SystemExit(p.stderr.strip() or "git failed")
return p.stdout
def names(text,pattern):
return sorted(set(re.findall(pattern,text,re.M)))
def main():
ap=argparse.ArgumentParser()
for n in ("base","fork","target"): ap.add_argument("--"+n,required=True)
ap.add_argument("--repo",type=Path,required=True); ap.add_argument("--output",type=Path,required=True)
a=ap.parse_args(); repo=a.repo.resolve(); a.output.mkdir(parents=True,exist_ok=True)
refs={n:git(repo,"rev-parse","--verify",getattr(a,n)+"^{commit}").strip() for n in ("base","fork","target")}
def tree(ref,glob):
return git(repo,"grep","-h","-E",glob,ref,"--","transformer_engine/pytorch/csrc",check=False) if False else ""
# Use git grep per ref and retain output even if no match.
def grep(ref,pat,paths):
p=subprocess.run(["git","-C",str(repo),"grep","-h","-E",pat,ref,"--",*paths],text=True,errors="replace",capture_output=True)
return p.stdout
bind=names(grep(refs["target"], r"\.def\(\s*\"[A-Za-z0-9_]+", ["transformer_engine/pytorch/csrc/"]), r"\.def\(\s*\"([A-Za-z0-9_]+)")
pyops=names(grep(refs["fork"],r"^\s*def\s+\w+",["transformer_engine/plugin/core/ops.py"]),r"^\s*def\s+(\w+)")
reg=names(grep(refs["fork"],r'op_name[[:space:]]*=[[:space:]]*"[^"]+',["transformer_engine/plugin/core/backends"]),r'op_name\s*=\s*"([^"]+)"')
files=git(repo,"ls-tree","-r","--name-only",refs["fork"]).splitlines()
pref="transformer_engine/plugin/core/backends/"
backend=sorted({("vendor/"+q[1]) if q[0]=="vendor" and len(q)>1 else q[0] for p in files if p.startswith(pref) for q in [p[len(pref):].split("/")] if q[0] in {"vendor","flagos","reference"} and (q[0]!="vendor" or (len(q)>1 and q[1]!="__init__.py"))})
rows=[]
for n in sorted(set(bind)|set(pyops)|set(reg)):
rows.append({"symbol":n,"binding":n in bind,"plugin_base":n in pyops,"registered":n in reg,"backends":backend,"disposition":"proposed"})
data={"resolved_refs":refs,"counts":{"bindings":len(bind),"plugin_base":len(pyops),"registered":len(reg),"matrix":len(rows)},"backends":backend,"symbols":rows}
(a.output/"api-inventory.json").write_text(json.dumps(data,indent=2)+chr(10))
(a.output/"api-matrix.tsv").write_text("symbol"+chr(9)+"binding"+chr(9)+"plugin_base"+chr(9)+"registered"+chr(9)+"disposition"+chr(9)+"owner"+chr(9)+"test"+chr(10)+"".join(f"{r['symbol']}"+chr(9)+str(r['binding']).lower()+chr(9)+str(r['plugin_base']).lower()+chr(9)+str(r['registered']).lower()+chr(9)+"proposed"+chr(9)+chr(9)+chr(10) for r in rows))
for fn,items in [("upstream-bindings.txt",bind),("plugin-base-methods.txt",pyops),("plugin-registered-ops.txt",reg)]: (a.output/fn).write_text(chr(10).join(items)+chr(10))
(a.output/"decisions.tsv").write_text("symbol"+chr(9)+"disposition"+chr(9)+"reason"+chr(9)+"owner"+chr(9)+"test"+chr(9)+"status"+chr(9)+"evidence"+chr(10))
(a.output/"api-audit.md").write_text("# Plugin API Audit"+chr(10)+chr(10)+f"- Matrix symbols: {len(rows)}"+chr(10)+f"- Backends: {', '.join(backend)}"+chr(10)+f"- Decisions required: {len(rows)}"+chr(10))
print(json.dumps({"output":str(a.output),"matrix":len(rows),"bindings":len(bind),"backends":backend}))
if __name__=="__main__": main()
Loading
Loading