跳转至

SOP — 技能条款第四轮实战验证 + 工程阻断项修复

主题目录 skill-verify-r4/。本次变更对象有两类:① 全局技能 deployment-tool-engineering(条款补一处盲点);② 本工程 lustre_ins 的两处阻断级缺陷(门禁遗漏、dry-run 副作用)及其文档口径。

前三轮技能改造见 skill-portability/SOP.md、skill-design-refine/SOP.md、skill-clause-fix/SOP.md。本轮触发方式与第三轮相同(以本工程为对象实跑验证),差别是:本轮验的是第三轮修订后的条款,因而同时得到「条款是否站得住」与「工程还差什么」两份结论。

1. 背景

第三轮改造新增了三处条款(--force 两类语义、存量工程渐进期不与交付分级冲突、分批按数据面可分性分级),并留下两项工程待办。本轮按修订后的条款把本工程重新对照一遍。

结论:

  • 三处新条款在本工程全部经受住检验(实测落点见附录 B.2);
  • 逐条对照又抓到 8 项此前未记录的差距,其中 3 项为阻断级(附录 B.1),触发本次工程侧修复;
  • 条款自身暴露 1 处盲点:上轮已看到「三态被 bool 包装函数折平」的形态,但当时只记为工程问题,未升格为条款,导致同类形态(含共享库通用幂等工具)本轮仍只能靠人读代码发现。本次补齐。

本次变更属 C 类(改全局技能 + 改工程代码),只动工具层,不触碰任何 Lustre 主机、不重跑任何不可逆动作。

2. 目标

变更完成后应达到以下可验证状态:

  • 技能正文含「禁止把三态折回两值」的约束,反例表含「bool 折平三态」「关键词子串判定」两条
  • repo 子命令纳入变更门禁(MUTATING_SUBCOMMANDS)
  • add-mdt 的 lctl set_param mds.*.enable_dne=1 经统一变更入口执行,--dry-run 下零副作用
  • 技能 frontmatter 可解析、name 与目录名一致、行数 < 500、引用的 references/ 齐全
  • deployer.py 语法自检通过;SOP / RUNBOOK 与实现体口径一致

3. 前置条件

项 要求 检查命令
受改文件 技能 ~/.trae-cn/skills/deployment-tool-engineering/SKILL.md、工程 deployer.py、docs/SOP.md 均可写 test -w <file> && echo writable
依赖 python3 与工程 .venv/bin/python 可用 python3 --version
备份台账 前几轮备份仍在(skill-clause-fix/backup/ 等),本轮与之并列、不混用 ls skill-clause-fix/backup skill-verify-r4/backup
作业占用 无需检查:本次不接触 Lustre 主机,不涉及 Slurm / LSF 节点 —

4. 影响范围

维度 说明
主机 本机(操作机)一处,不涉及 192.168.31.21 / .22 等任何远端主机
组件 全局技能 deployment-tool-engineering 正文;工程编排层 deployer.py;工程手册 docs/SOP.md
受影响资产 技能 +3 行(312 → 315 行);deployer.py 门禁清单 1 行、DNE 步骤 16 行;docs/SOP.md 两处说明
是否停服 否。不触碰 edafs 文件系统,无客户端 IO 影响
窗口期 无限制
在跑业务 无
行为变化 repo 子命令新增前置门禁(只读预检查):节点不可达或环境不达标时会 BLOCK 而不再直接改仓库文件,属预期收紧
缓存影响 改技能使上游前缀缓存失效,收尾后开新会话

5. 分步操作

本次由 Agent 直接编辑文件完成,无实现体脚本;以下为与实现等价的操作序列,供复核与手工复现。以实现体(SKILL.md / deployer.py 本身)为准。

# 1. 备份受改文件(高危前置:备份先于一切修改)
TS=$(date +%Y%m%d-%H%M%S)                                     # 备份时间戳
D=/home/rain/Documents/lustre_ins/skill-verify-r4/backup
mkdir -p "$D/global-skills/deployment-tool-engineering" "$D/docs"
cp -p /home/rain/.trae-cn/skills/deployment-tool-engineering/SKILL.md \
      "$D/global-skills/deployment-tool-engineering/SKILL.md.bak.$TS"   # 技能
cp -p /home/rain/Documents/lustre_ins/deployer.py "$D/deployer.py.bak.$TS"   # 工程编排层
cp -p /home/rain/Documents/lustre_ins/docs/SOP.md  "$D/docs/SOP.md.bak.$TS"  # 工程手册

# 2. 技能:补三态约束 + 两条反例(定点替换,不重写整文件)
#    2a 「幂等与计划先行」节三态表后新增:禁止把三态折回两值
#    2b 「常见反例」表新增两行:bool 包装函数折平三态 / 通用幂等工具关键词子串判定

# 3. 工程 deployer.py:修两处阻断级缺陷(定点替换)
#    3a MUTATING_SUBCOMMANDS 增补 "repo"(实现文件 deployer.py:cmd_repo 与
#       modules/repo_setup.py 会写各节点 /etc/yum.repos.d/*.repo)
#    3b cmd_add_mdt 末步「启用 DNE」由裸调 _ssh.run 改为走 apply_change,
#       并去掉 `2>/dev/null || true`(改为校验返回码,失败计入本次失败)

# 4. 工程 docs/SOP.md:与实现体口径对齐
#    4a 5.1 节「变更类子命令」枚举补 repo,并新增「单独执行 repo」小节
#    4b 5.5 节补注:末步 DNE 经统一变更入口,dry-run 下不下发

失败判断依据:任一步返回码非 0,或第 6 章校验任一项不通过,即视为失败,按第 7 章回滚。

6. 验证

# 1. 技能结构校验:frontmatter、name、description、行数、references、修订点命中
python3 - <<'PY'
import re, pathlib
root = pathlib.Path('/home/rain/.trae-cn/skills/deployment-tool-engineering')
t = (root/'SKILL.md').read_text(encoding='utf-8')
fm = re.match(r'^---\n(.*?)\n---\n', t, re.S).group(1)
name = re.search(r'^name:\s*(.+)$', fm, re.M).group(1).strip()
desc = re.search(r'^description:\s*(.+)$', fm, re.M).group(1).strip()
print('frontmatter 可解析: True')
print('name 一致/合法:', name == root.name, bool(re.fullmatch(r'[a-z0-9]+(-[a-z0-9]+)*', name)))
print('desc 合规:', ': ' not in desc and '<' not in desc and '>' not in desc and 'Use when' in desc)
print('行数:', len(t.splitlines()), '(<500:', len(t.splitlines()) < 500, ')')
print('缺失 references:', [r for r in set(re.findall(r'references/([\w.\-]+\.md)', t))
                          if not (root/'references'/r).exists()] or '无')
for k in ['禁止把三态折回两值', '用 bool 包装函数把三态折平', '通用幂等工具用关键词子串判定']:
    print(f'修订点命中 [{k}]:', t.count(k))
PY

# 2. 工程语法与门禁清单校验
cd /home/rain/Documents/lustre_ins
.venv/bin/python -m py_compile main.py deployer.py            # 预期:无输出(成功)
.venv/bin/python -c "
import deployer
m = deployer.LustreDeployer.MUTATING_SUBCOMMANDS
print('变更子命令清单:', m)
print('repo 已入门禁:', 'repo' in m)
"

# 3. dry-run 零副作用验证(不联网:直接验统一变更入口的行为)
.venv/bin/python -c "
from deployer import LustreDeployer
d = LustreDeployer(config_path='config/deploy.yaml', dry_run=True)
called = []
r = d.apply_change('测试变更', action=lambda: called.append(1), dry_run_desc='将做某事')
print('dry-run 下 apply_change 返回:', r)      # 预期 None
print('action 是否被调用:', bool(called))       # 预期 False
"

实测结果(2026-09-24 01:15):

校验项 结果
技能 frontmatter 可解析 / name 一致且合法 / desc 合规 True / True True / True
技能行数 315(变更前 312,< 500)
引用的 references 齐全 True(skeleton.md / python-stack.md / shared-lib-contract.md)
三个修订点命中 各 1 次
py_compile main.py deployer.py 通过
变更子命令清单 ('bootstrap','add-oss','add-ost','add-mdt','add-client','enable-ha','tune','repo')
dry-run 下 apply_change 返回 None、action 未被调用
RUNBOOK 口径 无需改动(其 repo 引用为恢复动作,未描述门禁)

未做项及理由:未做真机 --dry-run 端到端复跑(需 SSH 到 192.168.31.21/.22)。本次改动是编排层的分支归属变更,行为已由第 3 条用例在本地覆盖;端到端复跑留待下一次真实部署窗口执行。

7. 回滚

备份位置:skill-verify-r4/backup/,逐条登记见 skill-verify-r4/backup/README.md。

# 高危:覆盖,执行前先确认目标路径与本轮时间戳
B=/home/rain/Documents/lustre_ins/skill-verify-r4/backup
TS=20260924-011524

# 回滚技能正文
cp -p "$B/global-skills/deployment-tool-engineering/SKILL.md.bak.$TS" \
      /home/rain/.trae-cn/skills/deployment-tool-engineering/SKILL.md
# 回滚工程编排层
cp -p "$B/deployer.py.bak.$TS" /home/rain/Documents/lustre_ins/deployer.py
# 回滚工程手册
cp -p "$B/docs/SOP.md.bak.$TS" /home/rain/Documents/lustre_ins/docs/SOP.md

回滚后验证:

grep -c "禁止把三态折回两值" /home/rain/.trae-cn/skills/deployment-tool-engineering/SKILL.md   # 应为 0
cd /home/rain/Documents/lustre_ins && .venv/bin/python -c "
import deployer
print('repo 已入门禁(回滚后应为 False):', 'repo' in deployer.LustreDeployer.MUTATING_SUBCOMMANDS)"

注意:三处回滚相互独立,可只回滚其一。回滚技能正文后需开新会话使其生效。

8. 风险说明

风险 等级 缓解措施
技能定点替换误匹配到别处 中 匹配段含足够上下文;替换后逐处 diff 复核,并用第 6 章命中计数确认
新增反例改变既有工程判据 低 两条反例属「把已有原则落到反例表」,未新增安全要求;三项无开关的红线原文未动
repo 入门禁后被既有流程当作"新增校验"而误判 中 第 4 章已声明属预期收紧;--dry-run 下 BLOCK 降级为告警,预演不受影响
DNE 步骤去掉 \|\| true 后,非 DNE 环境上命令失败导致 add-mdt 记失败 中 仅在确实执行 mds.*.enable_dne=1 时判定;失败会记 enable_dne:<host> 并置本次失败,属显式暴露而非静默吞掉;如需容忍应在配置中显式处理
技能改动使缓存前缀失效带来成本 低 变更集中在一次会话内完成,收尾后开新会话

附录 A — 交付物清单

文件 说明
skill-verify-r4/SOP.md 本文件
skill-verify-r4/backup/README.md 备份台账(3 条)
skill-verify-r4/backup/global-skills/deployment-tool-engineering/SKILL.md.bak.20260924-011524 技能正文修订前版本
skill-verify-r4/backup/deployer.py.bak.20260924-011524 工程编排层修订前版本
skill-verify-r4/backup/docs/SOP.md.bak.20260924-011524 工程手册修订前版本
skill-verify-r4/backup/docs/HANDOFF.md.bak.20260924-011653 交接快照整体重写前版本

改造后资产位置:/home/rain/.trae-cn/skills/deployment-tool-engineering/(SKILL.md 315 行 + references/ 三份)。

附录 B — 第四轮验证发现(对象:本工程 lustre_ins)

B.1 本轮抓到的 8 项差距

# 发现 证据 级别 本次处置
N1 repo 是变更子命令却不入门禁 deployer.py 的 MUTATING_SUBCOMMANDS 原无 repo;modules/repo_setup.py 写 /etc/yum.repos.d/*.repo(且在 ROLLBACK_REMOTE_PATHS 中);docs/SOP.md 第 83 行称"各变更子命令"但枚举里无它,第 5 章亦无小节 阻断 已修
N2 add-mdt 在 dry-run 下仍有真实副作用 deployer.py:cmd_add_mdt 裸调 _ssh.run("lctl set_param mds.*.enable_dne=1 2>/dev/null \|\| true"),未经 apply_change、未判 dry_run、未校验返回码 阻断 已修
N3 多主机数据面不可逆变更(mkfs)未分批、无失败阈值 全工程无批次/失败阈值配置;_run_steps 失败即终止但明写"前序模块已变更的不会自动回滚" 阻断 未修,见 B.3
N4 无 plan.yaml 预演产物 dry-run 仅打日志,无结构化计划文件 建议 未修,见 B.3
N5 模块普遍不覆盖 sync_status(),幂等判定内嵌 execute() modules/ 下无 def sync_status;backup() 因而无法"仅对变更项"执行 建议 未修,见 B.3
N6 共享库通用幂等工具用 bool + 关键词子串判定,异常当"需变更" base_module.check_idempotent / skip_if_done(expected_output in stdout;异常 return False);当前工程未调用,属潜伏 阻断 未修,见 B.3(已由本轮技能反例覆盖)
N7 ssh_user 配置项无实效引用,连接身份硬编码 root deployer.py:_do_initialize 传 {"username": "root"};ssh_user 仅被 lustre_state.py 塞进 target dict,未用于建立连接 建议 未修,见 B.3
N8 lctl dl 按固定字段位置解析 utils/lustre_state.py:get_online_targets 用 parts[4] 取 host、parts[-1] 取 state 建议 未修,见 B.3

复核说明:N1、N2 是据以动手的证据,已单独做过定向交叉复核(对比实现体、docs/SOP.md、docs/RUNBOOK.md 三处口径),确认非误报;N1 复核时额外发现 SOP 第 83 行"各变更子命令"的表述本身也与实现体不符。

B.2 第三轮三处修订条款的实测落点

修订 本工程实测 判定
--force 两类语义 modules/target_format.py 的设备校验在 --force 判定之前完成;--force 只用于 mkfs / rollback 的显式确认,无一处拿它跳过校验 条款正确,原措辞确实过窄
渐进期不与交付分级冲突 本工程仍未做 bundle 与环境契约,按新条款应登记差距清单而非判交付未完成 条款消解了自相冲突
分批按数据面可分性分级 tune / repo / firewall 等仅服务配置面且可重入 → 建议;mkfs 数据面不可逆 → 阻断(即 N3) 分级在本工程给出了不同且正确的判据

B.3 本次未处置项(转为工程待办)

项 为何不在本次范围 建议下一步
N3 分批与失败阈值 需新增配置项与编排改造,属独立变更单元,非"顺手可修" 优先级高于 N4/N5:先补批次规模与失败阈值配置,再改编排
N4 plan.yaml 属新增能力,需设计产物结构 与 N5 一并做:sync_status() 生成变更清单即天然产出计划
N5 sync_status() 未覆盖 触及全部业务模块,改动面大 与 N4 合并规划
N6 共享库幂等工具 未被调用,属潜伏;改动共享库影响所有挂载工程 单独评估:要么改三态,要么删除
N7 ssh_user 幽灵配置 涉及执行身份模型(当前为 root-only) 需先确认是否支持非 root 部署
N8 lctl dl 解析 lctl dl 无结构化输出,影响面限于巡检展示 低优先,随巡检改造一并处理

来源:/home/rain/Documents/lustre_ins/skill-verify-r4/SOP.md | 最后更新:2026-09-24 01:17(由 build/sync.py 同步,请勿在站点侧修改)