agentleFS
Ex-imanityEx-imanity/SkillCollections/skills/case-lite/SKILL.md

case-lite

Skill1 starsChanged 17 days agoMITView on GitHub

小需求测试用例生成 skill。用户提供飞书 Docx、Wiki 或云空间原生 Markdown 文件链接 → 浏览并手动选择章节 → 生成场景结构 → 生成完整用例 → 可选 agent 自检补漏 → 写回搬山。不含模块拆分和自动选章,适用于单一功能点的小需求。当用户说"小需求用例"、"简单需求生成用例"、"case-lite",或明确只有 1-2 篇文档且无需模块拆分时触发。

The file

Files
SKILL.md

case-lite:小需求用例生成

定位

面向单一功能点的小需求,核心理念是精准输入:用户自己选择相关章节,避免读入无关信息影响判断和浪费 token。

  • 无模块拆分、无自动选章、无质量门禁
  • 用户主导章节选择,AI 专注生成
  • 可独立分发,不依赖 skills-migration 其他模块

环境要求

进入 Step 1 之前,先做轻量 MCP 可用性检查。 如果工具都可用,直接进入 Step 1,不要展开安装流程;只有依赖缺失、版本过旧或用户明确要求安装时,才进入“首次使用依赖向导”。这是渐进式披露:普通用例生成不应该被完整安装链路打断。

首次使用依赖向导(仅在缺依赖时)

优先使用内置脚本输出诊断报告:

python case-lite/scripts/setup_mcp.py --agent claude-code
python case-lite/scripts/setup_mcp.py --agent codex

根据当前 Agent 选择 claude-code 或 codex。若无法判断 Agent 类型,先询问用户。

诊断报告展示后,必须询问用户是否同意自动写入全局 MCP 配置。用户同意后,再运行:

python case-lite/scripts/setup_mcp.py --agent <claude-code|codex> --fix

setup_mcp.py 会在写入前再次确认,写入前备份原配置,并只写缺失/过期的 MCP server。它只支持 Claude Code / Codex 的全局配置;其他 Agent 继续展示手动配置提示。写入注意:

  • 配置路径不确定时不要盲写:若报告提示同时存在 ~/.claude/.claude.json 与 ~/.claude.json(旧版 cc-switch 可能覆盖生效路径),先和用户确认哪个是生效路径,再用 --config <路径> 指定;--fix --yes 在路径不确定时会拒绝写入。
  • 默认不覆盖已有 feishu-docx-blocks:已配置时脚本默认保留,仅在用户确认升级或显式加 --replace-feishu 时才替换(例如从源码安装切换到 uvx@latest)。
  • Claude Code 写入前请退出 Claude Code,避免运行中并发写回覆盖本次修改。

凭证安全:不要在 skill 中写入默认凭证,也不要在对话或日志中输出 FEISHU_APP_SECRET 明文。FEISHU_APP_ID / FEISHU_APP_SECRET 由用户从内部文档获取,并通过环境变量或脚本交互输入提供。默认凭证文档:https://gaotuedu.feishu.cn/wiki/CNBZwz8rwiew8dkXHt1cRIAAn8g#share-DrNhdQPiToYWMXxyC6nciHlknJh

完整安装说明仅在需要时读取:references/install-mcp.md。

飞书文档工具(必需)

对 Docx/Wiki 尝试调用 get_child_documents、parse_document_id 或 extract_document_structure。当用户提供 /file/TOKEN,或 Wiki 节点解析为 file 时,必须确认 get_markdown_file_sections 可用。缺少本任务所需工具时进入首次使用依赖向导;如果已经配置但不是 feishu-docx-blocks@latest,询问用户是否升级。

{
  "mcpServers": {
    "feishu-docx-blocks": {
      "command": "uvx",
      "args": ["feishu-docx-blocks@latest"],
      "env": {
        "FEISHU_APP_ID": "<用户提供>",
        "FEISHU_APP_SECRET": "<用户提供>"
      }
    }
  }
}

首次调用工具或授权过期时,feishu-docx-blocks 会自动拉起浏览器完成飞书授权。 get_child_documents 依赖 feishu-docx-blocks 最新版及 wiki:node:retrieve 权限。原生 Markdown 文件还需要 get_markdown_file_sections 和 drive:file:download 授权。若所需工具缺失,提示用户重启 MCP / 重新授权 / 确认 uvx feishu-docx-blocks@latest 已生效;无法立即升级时,只能处理当前 MCP 已支持的文档类型。

搬山测试平台工具(推荐)

尝试调用 testCaseDetail。如果工具不存在,进入首次使用依赖向导,或提示用户手动添加:

{
  "mcpServers": {
    "Banshan": {
      "type": "streamable-http",
      "url": "https://tech.baijia.com/mcp-server/banshan/mcp"
    }
  }
}

搬山 MCP 用于获取参考用例(Step 3a)。写回功能由内置脚本直接调用 HTTP 完成,不依赖此配置。 如果用户无法安装,Step 3a 的参考用例获取降级为手动粘贴 markdown,其余流程不受影响。

产物目录

产物根目录由是否提供迭代信息决定。后续所有步骤中的产物路径都相对于「产物根目录」,本文档统一用 {产物根目录} 指代:

场景产物根目录
未提供迭代信息(默认)case-lite-output/{需求slug}/
提供了迭代信息case-lite-output/{迭代slug}/{需求slug}/

{需求slug} 由需求名称生成,如 ai-audit-model;{迭代slug} 由迭代名称生成,如 ai-search-202609。两者规则一致:小写英文 kebab-case,中文按语义译成英文,日期/版本号保留数字(详见 Step 1)。

产物根目录内部结构在两种场景下完全一致:

{产物根目录}/
├── chapters/
│   └── {docKey}-chapters.md    ← 章节树展示(供用户选章)
│   └── child-documents.md      ← 子文档发现结果与用户纳入选择
├── corpus/
│   ├── selected-corpus.md      ← 用户选定章节的拼接语料
│   └── extra-context.md        ← 用户补充信息(含 Review 阶段追加内容)
├── style-ref/
│   └── reference-cases.md      ← 参考用例或默认风格说明
├── structure.md                ← 场景结构(用户审核)
├── full.md                     ← 完整用例(用户审核)
├── review.md                   ← 用例检查结果(用户决定是否采纳)
└── writeback/
    ├── node-tree.json          ← writeback.py 生成的节点树
    └── writeback-log.json      ← 写回日志

提供迭代信息时,迭代目录下额外维护一份跨需求索引:

case-lite-output/{迭代slug}/
├── iteration-index.md          ← 本迭代需求清单与进度(跨需求,追加维护)
├── {需求slug-A}/
└── {需求slug-B}/

向后兼容:不提供迭代信息时,行为与旧版完全一致,已有的扁平产物目录无需迁移。

产物落盘约束

  • 每一步结束前,必须确认该步骤对应的 markdown 产物已经写入磁盘,而不是只在对话中展示
  • 若某一步没有实际内容,也要写入占位说明,避免后续流程判断不清。例如:
    • 无补充信息 → corpus/extra-context.md 写明“当前无补充信息”
    • 跳过参考用例 → style-ref/reference-cases.md 写明“本次未提供参考用例,使用默认风格规则”
    • 跳过自检 → review.md 写明“用户选择跳过用例自检,直接进入回填”
  • 任务完成后不要删除这些产物。chapters/、corpus/、structure.md、full.md、review.md、writeback/ 都应保留,便于复盘和二次编辑
  • 提供了迭代信息时,iteration-index.md 位于迭代目录(需求目录的上一级),维护方式是按需求行追加或更新,绝不整份重写覆盖其他需求的记录
  • 进入下一步前,先检查上一步产物文件存在且内容已更新;若不存在,先补写文件再继续
  • 如果后续步骤修订了前序结论,应更新对应 markdown 文件,而不是只修改终态文件

执行流程

Step 1:收集输入

从用户消息中提取:

  1. 需求名称(必须)→ 用于生成 {需求slug} 和产物目录
  2. 迭代名称(可选)→ 用于生成 {迭代slug},决定产物目录是否多一层。一个迭代可包含多个需求
  3. 文档链接(必须)→ 飞书文档 URL 列表
  4. 文档类型标签(可选)→ 需求 / 前端 / 后端 / 客户端 / 算法

引导话术:

请提供以下信息:
1. 需求名称(如:AI审核模型变更)
2. 迭代名称(可选,一个迭代可包含多个需求,如:AI搜索9月迭代)
3. 相关文档链接(飞书链接,可多个)
4. 文档类型(可选,如:需求文档、后端技术方案等)

示例:
- 需求名称:AI审核模型变更
- 迭代名称:AI搜索9月迭代
- 后端技术方案:https://xxx.feishu.cn/docx/TOKEN1
- 需求文档:https://xxx.feishu.cn/wiki/TOKEN2

迭代名称是可选项。用户未提供时不要额外追问,直接按无迭代处理。

1a. 确定产物根目录

  1. 生成 slug:需求名称和迭代名称都按同一规则转成 slug——小写英文 kebab-case;中文按语义译成英文(如「AI搜索9月迭代」→ ai-search-202609);日期、版本号保留数字;不使用空格、中文或特殊字符。
  2. 拼出产物根目录:
    • 无迭代名称 → case-lite-output/{需求slug}/
    • 有迭代名称 → case-lite-output/{迭代slug}/{需求slug}/
  3. 复用已有迭代目录:若 case-lite-output/{迭代slug}/ 已存在,直接复用,不要新建变体目录名。若存在语义相同但拼写不同的迭代目录(如 ai-search-2026-09 vs ai-search-202609),先列给用户确认用哪一个。
  4. 旧扁平目录冲突检测(仅在提供了迭代名称时执行):如果 case-lite-output/{需求slug}/ 已作为扁平目录存在,不要自动移动,也不要静默新建,先提示用户并等待回复:

    检测到已存在扁平产物目录:case-lite-output/{需求slug}/
    本次指定了迭代「{迭代名称}」,目标目录为 case-lite-output/{迭代slug}/{需求slug}/
    
    请选择:
    - 回复「迁移」→ 将旧目录移动到迭代目录下,在已有产物基础上继续
    - 回复「新建」→ 保留旧目录不动,在迭代目录下新建一份产物

    用户选择「迁移」后再执行移动;用户未明确回复前不要动任何已有产物。

1b. 初始化产物

创建产物根目录,并初始化以下产物(如文件不存在则创建):

  • corpus/extra-context.md
  • style-ref/reference-cases.md
  • review.md
  • chapters/child-documents.md

初始化内容可使用简短占位说明,后续步骤再覆盖或追加。

提供了迭代名称时,还要维护 case-lite-output/{迭代slug}/iteration-index.md:

  • 文件不存在则按下方格式创建
  • 文件已存在则追加或更新本需求所在行,不要重写其他需求的行
  • Step 1b 写入本需求行时,caseId 填 —,状态填 进行中
  • 后续步骤中状态变化时回来更新对应行(Step 4 完成 → 用例已生成;Step 6 写回成功 → 填入 caseId 并置为 已写回)
# 迭代:{迭代名称}({迭代slug})

| 需求 | 产物目录 | 搬山 caseId | 状态 | 更新时间 |
|---|---|---|---|---|
| AI审核模型变更 | ai-audit-model/ | 22841 | 已写回 | 2026-09-03 |
| 新用户欢迎引导 | new-user-welcome-guide/ | — | 用例已生成 | 2026-09-03 |

状态取值:进行中 / 用例已生成 / 已写回。

1c. 递归发现 wiki 子文档 [HITL]

在进入章节浏览前,对 Wiki/Docx 链接尝试发现子文档;直接 /file/TOKEN 的原生 Markdown 文件没有 Docx 子文档树,跳过发现并在 chapters/child-documents.md 记录“不适用”:

  1. 调用子文档工具:对每个原始链接调用:
    get_child_documents(url="{url}", fetch_all=true, include_non_docx=false)
    只保留 obj_type == "docx" 的子文档。普通 docx 不在知识库节点树中时,工具会返回空 children,这是正常情况。
  2. 递归展开:如果返回的子文档 has_child == true,继续对该子文档的 url 调用 get_child_documents(fetch_all=true, include_non_docx=false),直到没有更下级子文档。递归过程中用 node_token(无则用 url)去重,避免重复或循环。
  3. 只收集链接和元数据:本步骤只读取 title、url、obj_token、obj_type、has_child 等元数据,不读取正文内容,不调用 get_document_blocks。
  4. 展示发现结果并等待用户确认纳入:如果发现任意子文档,将其按层级列给用户,并说明“默认作为父文档的同类文档纳入”。用户可以选择全部纳入、按编号纳入、全部跳过,或指定个别子文档改为其他类型。

展示格式示例:

检测到「后端技术方案」下存在子文档:

1. 后端技术方案 / 接口设计
   - 类型:默认同父文档(后端)
   - 链接:https://xxx.feishu.cn/wiki/CHILD1
2. 后端技术方案 / 接口设计 / 错误码说明
   - 类型:默认同父文档(后端)
   - 链接:https://xxx.feishu.cn/wiki/CHILD2

是否将这些子文档作为同类文档一起读取?
- 回复“全部纳入”
- 回复编号,如“1,2”
- 回复“跳过”
- 如需改类型,可回复“1=后端, 2=需求”
  1. 扩展文档列表:用户确认纳入的子文档加入后续 Step 2 的文档列表;默认继承父文档的文档类型标签(需求 / 前端 / 后端 / 客户端 / 算法等),除非用户显式改类型。
  2. 落盘记录:将完整发现树、用户确认纳入的子文档、继承/覆盖后的文档类型写入 chapters/child-documents.md。如果没有发现子文档,也写明“未发现可纳入的 docx 子文档”。

关键约束:发现子文档不等于自动读取内容。必须经过用户确认纳入后,才进入 Step 2 的章节浏览与选章。

Step 2:章节浏览与选择 [HITL]

2a. 逐文档浏览章节并完成选章

对 Step 1 和 Step 1c 确认后的文档列表依次先进行类型分流,同一任务中允许同时包含原生 Markdown 和 Docx:

  1. 原生 Markdown 分流:
    • /file/TOKEN URL:调用 get_markdown_file_sections(url="{url}", max_level=4, preview_chars=0);首轮只返回章节元数据,不能读取正文。
    • /wiki/TOKEN URL:先以 preview_chars=0 调用同一工具。若其成功返回,则该 Wiki 节点底层是原生 Markdown file,继续使用此分流;若返回“不是原生飞书 Markdown 文件”,才进入下方 Docx 分流。
    • 不要对原生 Markdown 调用 parse_document_id、extract_document_structure 或 get_document_blocks。
  2. Docx 分流:调用 parse_document_id(url) 获取 document_id,再调用 extract_document_structure(document_id, max_level=4, output_format="json")。
  3. 处理无章节的文档:若对应工具返回空章节列表(Markdown 指代码围栏外没有 ATX 标题;Docx 指没有 H1-H4),告知用户并让其选择:
    📄 文档 "{文档标题}" 未解析出任何章节标题,可能是纯文本/列表格式。
    请选择处理方式:
    1. 全量导入该文档内容(适合短文档)
    2. 跳过该文档
    3. 我手动指定需要的内容
    • 选 1:Docx 调用 get_document_blocks(document_id, fetch_all=true) 获取全文;Markdown 仅在用户确认短文件可全文导入后调用 get_markdown_file_sections(..., include_full_content=true) 获取原始 Markdown
    • 选 2:跳过该文档,继续处理下一个
    • 选 3:按用户指示获取部分内容(如用 search_document_content 搜索关键词定位)
  4. 格式化展示(正常有章节时):将对应工具返回的章节树转为用户友好的编号列表。Markdown 使用 id、section_path、range.start_line/end_line;Docx 继续使用 position。

展示格式示例:

## 📄 UOS 相关需求 后端反讲(后端文档)

1. 一、变更历史
2. 二、背景
   2.1 需求
   2.2 关联方
3. 三、整体设计
   3.1 Apollo 新增/变更配置
      3.1.1 新增模型连接配置
      3.1.2 变更业务模型路由配置
   3.2 需求六(账号类型字段)
4. 四、详细设计
   4.1 AI审核模型变更
      4.1.1 整体流程图
      4.1.2 核心实现
      4.1.3 关键设计检查
  1. 保存章节树:写入 chapters/{docKey}-chapters.md
  2. 引导用户选章:
请选择需要纳入用例生成的章节(可多选):

选择方式:
- 按编号:3, 4.1, 4.2(支持整章或子章节)
- 按关键词:整体设计, AI审核
- 混合:3, "核心实现"

输入 "全选" 选择该文档所有章节。
多个文档请分别选择。
  1. 记录选择:在 chapters/{docKey}-chapters.md 末尾追加选章结果,格式:
## 用户选章结果
- {章节标题} | pos:{start}-{end}
- {章节标题} | pos:{start}-{end}

Docx 的 position range 从 extract_document_structure 的 JSON 返回值中读取。Markdown 记录 line:{start}-{end} 和 MCP 返回的 section_id。每个文档单独追加到其对应的 chapters 文件。

完成所有文档的章节展示与选章后,再统一进入补充信息确认。

飞书工具详细用法:见 references/feishu-tools-guide.md

2b. 统一收集补充信息 [HITL]

用户的补充内容可选,但询问本身不可省略。

必须在所有文档选章完成后,统一发出询问并等待用户明确回复,方可进入 Step 3。 不得因“文档已全选”、“用户最初没有主动提供补充信息”或“已有部分文档处理完成”而跳过此步骤。

如果用户在 Step 1 输入阶段已经提供了补充信息,也要先落盘到 corpus/extra-context.md,并在此处继续确认:

  • 这些信息是否就是全部补充信息
  • 是否还有新增内容需要纳入
已选定的文档章节会作为用例生成的主要依据。

是否还有补充信息需要纳入?例如:
- TAPD/Jira 上的需求描述或验收标准
- 产品口头沟通的额外规则或约束
- 接口文档、字段说明等技术细节
- 其他背景信息

可以直接粘贴文本,也可以回复”没有了”继续。

如果用户提供了补充信息,保存到 corpus/extra-context.md,在后续 Step 3 生成时与选定语料一同作为输入。 如果用户回复”没有了”,也要在 corpus/extra-context.md 中写明当前无补充信息。

Step 2 完成检查点(进入 Step 3 前必须确认):

  • 所有文档的章节树文件 chapters/{docKey}-chapters.md 已写入 ✓
  • 用户已完成所有文档的选章,且选择结果已记录 ✓
  • 补充信息询问已统一发出,并收到用户明确回复(补充内容或”没有了”均可),corpus/extra-context.md 已写入 ✓

三项均满足后,方可进入 Step 3。

Step 3:生成场景结构 [HITL]

3a. 收集参考用例(可选,不阻塞)

是否有可以参考的优秀用例?(用于学习文本风格和覆盖度)
- 输入搬山用例 ID(如:20612)
- 粘贴 markdown 格式的用例片段
- 回复"跳过"使用默认风格
  • 搬山 caseId → 调用 testCaseDetail(caseId) 获取,保存到 style-ref/reference-cases.md
  • markdown 片段 → 直接保存到 style-ref/reference-cases.md
  • 跳过 → 使用内置 assets/case-learning.md 默认风格规则

如果用户跳过参考用例,也要在 style-ref/reference-cases.md 中写明本次使用默认风格规则,避免该产物缺失。

参考用例学习规则(必须遵守):

  • 只学习文本风格:学习参考用例中场景/测试点/步骤/结果的文本措辞和描述粒度
  • 不学习节点层级:无论参考用例的结构是什么样的(可能有前置条件节点、可能有多层嵌套),生成时始终严格按本 skill 的 full.md 格式规范输出
  • 不学习优先级:即使参考用例有 P0/P1/P2 标记,也不要在 full.md 中生成优先级标记(agent 判断的优先级不准,由用户事后标注)

3b. 拉取选定语料

⛔ 严禁改写 — selected-corpus.md 必须原文写入 get_document_blocks 返回的文本,包括表格、代码块、JSON 示例、curl 命令、字段说明。不得摘要、精简、改写任何内容。 唯一允许的处理是添加章节分隔注释 <!-- SOURCE: ... -->。

对每个选定章节,按文档类型走对应分支,并在每个文档完成后立即追加写入 corpus/selected-corpus.md:

原生 Markdown 文件分支

  1. 对同一文件的用户选章 ID 一次调用:
    get_markdown_file_sections(url="{url}", section_ids=["1", "2.1"])
  2. 工具返回的 selected_sections[].content 是原始 Markdown。按返回顺序逐段落盘,格式:
    <!-- SOURCE: {docKey} | {section_title} | line:{start}-{end} | native-markdown -->
    {原始 Markdown,不改写}
    <!-- END SOURCE -->
  3. 不下载图片:Markdown 内的图片、链接和附件引用作为原始文本保留。不要调用 download_image_blocks 或 download_board_as_image,因为它们只适用于 Docx blocks。

Docx 文档分支

对每个选定章节,按顺序执行以下三步,每章完成后立即追加写入 corpus/selected-corpus.md,不等所有章节拉完再统一写盘:

Step 3b-1:拉取文本和媒体元数据

get_document_blocks(document_id, start_position=X, end_position=Y)

返回章节的文本内容和媒体元数据。注意:图片/画板只返回 block_id 和 token,不包含实际图片。

Step 3b-2:下载图片(如果上一步返回了图片元数据)

download_image_blocks(document_id, image_block_ids=["block_id_1", "block_id_2"])

将实际图片下载到本地,返回可视化的图片内容。

  • 下载成功:在 corpus 对应位置插入 [📷 图片: {上下文描述}]
  • 下载失败:插入 [📷 图片下载失败: block_id={id},跳过],不阻塞后续流程

如果章节包含画板(流程图、架构图等),额外调用:

download_board_as_image(board_tokens=["token_1"], document_id=document_id, board_block_ids=["block_id_1"])

Step 3b-3:立即追加写入

完成上两步后,立即将本章内容追加到 corpus/selected-corpus.md,格式:

<!-- SOURCE: {docKey} | {section_title} | pos:{start}-{end} -->
{章节文本内容,原文逐字写入,不做任何处理}
[📷 图片: {image_description_or_context}]
<!-- END SOURCE -->

所有章节处理完毕后,corpus/selected-corpus.md 应包含每个章节各自的 <!-- SOURCE --> 注释块。

关键:文档中的流程图、接口说明图、交互稿等视觉信息对用例生成至关重要。 如果跳过图片下载,生成的用例可能遗漏图中描述的分支逻辑和交互细节。

Step 3b 完成检查点(进入 3c 前必须确认):

  • corpus/selected-corpus.md 已存在,且包含所有选定章节各自的 <!-- SOURCE --> 注释头 ✓
  • 文件内容包含原始代码块、JSON 示例、表格等,未被摘要替代 ✓

3c. 生成场景结构

基于以下输入生成 structure.md:

  • 选定语料(selected-corpus.md)
  • 补充信息(extra-context.md,如有)
  • 风格参考(参考用例或默认规则)
  • 需求名称

生成 prompt 要点:

  • 按功能/流程拆分场景
  • 先按单层场景草拟,这一步不纠结拆不拆子场景——分层决策统一交给 3d 复核
  • 每个场景列出测试点,标注优先级(P0/P1/P2)
  • 覆盖维度:正常流程、异常处理、边界值、安全/权限
  • 命名格式:操作对象 + 操作 + 结果/场景(不用"验证"/"测试"前缀)
  • 在输出 structure.md 前先做一次测试点去重:如果两个测试点覆盖目标、核心操作和断言对象本质相同,只是表述不同,优先合并,避免重复测试点先进入审核流

草拟完成后先不要展示给用户,进入 3d 复核。

3d. 场景分层复核 [必做]

3c 草拟出场景和测试点后、展示给用户之前,逐个顶层场景评估要不要拆子场景。

这一步的检查是必做的,拆不拆是可选的结果——但无论结论是什么,都要写进下面的复核表。

判据速查:

该场景直接挂的测试点数处理
≤ 5不拆。拆了只是多一层点击
6–8仅当存在正交维度、或子集间前置条件差异大时才拆
> 8必须逐条对照判据,拆与不拆都要给出理由
何时拆子场景(完整判据)

该拆(满足任一条):

  • 单个场景下测试点超过 8 个,且这些测试点天然沿某个维度聚成几堆
  • 存在正交维度,不拆就要在每个测试点标题里重复维度名:端(iOS/Android/H5)× 功能、角色(管理员/普通用户)× 操作、支付渠道 × 结果
  • 子集之间前置条件差异大:一组需要「已开通免密」,另一组需要「未开通」,混在一层会让每个测试点第一步都在重复铺环境
  • 需求文档本身就是两级结构(模块 → 子功能),且这个结构对测试有意义

不该拆(满足任一条就别拆):

  • 场景下测试点 ≤ 5 个 —— 拆了只是多一层点击
  • 拆出来的子场景只有 1 个测试点 —— 等于没拆,反而加深了树
  • 只是为了对齐文档目录结构,测试上没有区分意义
  • 需要拆到第 4 层 —— 说明这个需求本身该拆成多个搬山用例

拆分维度优先级:前置条件差异 > 端/角色等正交维度 > 功能子模块 > 正常流/异常流。 按前置条件拆收益最大,因为它直接减少每个测试点里的环境铺垫重复。

决定拆时,遵守「场景分层规则」:把该场景原有的测试点 全部下沉到子场景,不能留一部分挂在父场景下(禁止混搭),并同步重编号 (测试点4.3 → 测试点4.1.3)。

复核结论连同 structure.md 一起展示给用户:

场景结构已生成,请审核:
[展示 structure.md 内容]

分层复核:

| 场景 | 测试点数 | 结论 |
|---|---|---|
| 场景1 登录鉴权 | 4 | 不拆(≤5)|
| 场景4 提交与路由 | 11 | **已拆** → 4.1 提交与路由 / 4.2 SSE 卡片协议 / 4.3 异常与重试(前置条件差异大)|
| 场景9 详情页渲染 | 7 | 不拆(无正交维度,测试点前置条件一致)|

请确认或提出修改意见,包括对分层的意见。确认后将生成完整用例。

复核表必须覆盖所有顶层场景,包括结论为「不拆」的那些。 省略任何一行都等同于跳过复核——用户无法从结果里区分 「评估过,认为不必拆」和「根本没评估」。

structure.md 里不写这张表,它只出现在给用户的确认消息中。

Step 4:生成完整用例 [HITL]

基于已审核的 structure.md + selected-corpus.md 生成 full.md。

生成 prompt 要点:

  • 严格按照 structure.md 的场景和测试点展开,编号必须与 structure.md 完全一致(编号即层级路径,改编号等于改树结构)
  • 每个测试点只包含:执行步骤、预期结果(不生成"前置条件"section)
  • 如有前置条件,将其精简后融入执行步骤的第一步(如"1. 已登录管理后台,进入XX页面")
  • 执行步骤精确到字段名/按钮名/接口路径
  • 预期结果多层验证(UI/交互/接口/数据层),断言可量化
  • 不扩写 structure.md 中没有的场景
  • structure.md 是结构的唯一真相:不在 full.md 里私自调整分层或重编号。 如果展开过程中发现某个场景确实该拆(例如实际写出来远超 8 个测试点), 停下来,提出 structure.md 的修订方案并请用户确认,改完 structure.md 再重新生成 full.md。 不要边写 full.md 边改结构——两份产物的编号必须始终一致
  • 不生成优先级标记:full.md 的场景和测试点标题中不要包含 P0/P1/P2(优先级由用户事后标注)
  • 即使参考用例中包含"前置条件"节点或优先级标记,也不要模仿
  • 生成时先做一次去重检查:如果不同场景下的测试点本质上是同一组前置条件 + 操作 + 断言,只是表述不同,优先合并或收敛,避免 full.md 出现重复用例

生成后输出 full.md 并请用户审核:

完整用例已生成,请审核:
[展示 full.md 内容或告知文件路径]

确认后,可选择先做 agent 自检,再决定是否进入回填。

用户审核通过后,如果本次提供了迭代信息,将 iteration-index.md 中本需求的状态更新为 用例已生成。

Step 5:用例检查 [HITL]

在 full.md 生成并完成用户初审后,先主动询问:

完整用例已生成。写回搬山前,是否需要我先自检这份用例?

如果你还有补充信息,也可以现在一并发我,例如:
- 边界规则或异常处理要求
- 产品/研发口头补充的约束
- 线上问题、历史缺陷、埋点或权限要求
- 其他刚想到但前面没写进文档的内容

- 回复"否"或"直接回填":跳过自检;如果同时附带补充信息,则仅归档到 markdown 产物,不修改当前用例,随后进入回填搬山
- 回复"是":先做用例检查
- 也可以在回复里附带补充信息

5a. 用户选择否

如果用户在“否/直接回填”时附带了补充信息:

  • 追加保存到 corpus/extra-context.md
  • 在 review.md 记录“用户补充了信息,但本轮未启用自检或改稿,直接回填”
  • 不要修改 structure.md 或 full.md

如果用户没有补充信息,也要在 review.md 写明“用户选择跳过用例自检,直接进入回填”。

直接进入 Step 6 回填搬山。

5b. 用户选择是

  1. 先检查当前会话的可用 skills 列表,判断是否有可辅助 Review 的 skill
    优先检查当前会话的 available skills 中是否存在精确名称 case-design-strategy-skill,其次再看其他覆盖度评审 / 用例设计策略类 skill。
    • 这里检查的是当前会话已加载的 skill 列表,不要靠文件系统路径扫描,也不要依赖记忆中的旧别名
    • 如果当前会话可用 skills 中存在 case-design-strategy-skill,则必须显式读取并使用它,将当前步骤视为 coverage review / 边界异常覆盖评审
    • 如果当前会话中不存在该 skill,即使磁盘上已安装,也应明确告知“当前窗口未加载到该 skill”,随后直接进行 inline Review
    • 若用户希望使用该 skill 但当前窗口未加载到,可建议用户在新窗口 / 新会话重试
  2. 如果用户在此时提供了补充信息
    将其追加保存到 corpus/extra-context.md(如新增一个 ## Review 补充信息 段落),后续如用户允许修改文档,则将这些补充信息一并纳入。
  3. Review 重点
    重点检查:
    • 边界与异常覆盖是否缺失
    • 权限、状态流转、重复提交、幂等、空值/非法值等是否遗漏
    • 文档原文、补充信息与现有用例之间是否存在冲突
    • 是否存在内容重复或高度重合的测试点,尤其是"正常场景"与后补的"边界场景"之间
  4. Review 产出约束
    • 将检查结论保存到 review.md
    • 不要在 Review 完成后直接修改 full.md
    • 先向用户简要汇报结果,再由用户决定是否允许修改 full.md

建议汇报格式:

用例检查已完成,结论如下:
1. 缺失覆盖:...
2. 重复/重合:...
3. 其他风险:...

是否需要我根据这些建议修改 full.md?

5c. 用户允许修改 full.md

修改前先判断补充信息的影响范围:

  1. 仅影响已有测试点的步骤、断言或细节补充
    例如补充异常返回码、埋点校验、权限断言、边界值断言,但不新增独立场景或测试点。
    这种情况:
    • 不改 structure.md
    • 直接对 full.md 做增量补充
    • 只修改受影响的测试点,避免整份 full.md 重生成
  2. 引入新的测试点,但场景结构变化较小
    例如在某个既有场景下补充 1-2 个边界/异常测试点。
    这种情况:
    • 先更新 structure.md
    • 将变更后的 structure.md 给用户确认
    • 用户确认后,默认只对 structure.md 中新增或变更的测试点增量补充 full.md
    • 不重写未受影响的已有测试点
  3. 引入新的场景,或造成结构性变化
    例如场景拆分/合并、测试点大范围重排、编号体系明显变化、覆盖策略整体调整。
    这种情况:
    • 先更新 structure.md
    • 将变更后的 structure.md 给用户重新审核
    • 用户确认后,再全量重生成 full.md

无论是哪一种,修改前都先做去重判断,再补充内容:

  • 如果拟新增的测试点与现有测试点在前置条件、核心操作、断言目标上本质相同,只是换了说法,不要新增重复用例
  • 优先选择:
    • 合并到已有测试点
    • 在已有测试点的执行步骤 / 预期结果中补充缺失断言
    • 仅在确实新增了独立覆盖目标时,再新增测试点

修改完成后:

  • 更新对应产物文件(structure.md / full.md / review.md)
  • 向用户展示变更摘要或变更后的相关片段
  • 待用户确认后进入 Step 6

5d. 用户不允许修改 full.md

保留当前 full.md 不变,直接进入 Step 6。

Step 6:回填搬山 [HITL]

建议:本步骤为纯机械操作,优先使用 writeback.py 脚本完成全部处理(解析 → 写入 → 验证),避免 LLM 读取 full.md 浪费 token。 如果脚本执行失败,允许 agent 读取 full.md 排查原因并修复格式问题后重试。

  1. 收集 caseId:
    请提供搬山用例 ID(caseId),用于写回搬山平台。
    如还未创建用例,请先在搬山创建后提供 ID。
  2. 定位 writeback.py:在本 skill 安装目录的 scripts/writeback.py。用 Glob 查找:
    Glob("**/case-lite/scripts/writeback.py")
  3. dry-run 验证(必须先执行,不可跳过):

    python {writeback.py路径} {产物根目录}/full.md \
      --case-id {caseId} --dry-run

    脚本会执行以下检查:

    • 格式验证:检测未被识别的 ## / ### 标题(格式漂移)
    • 数量校验:对比 markdown 原文与解析出的场景/测试点数
    • 完整性检查:检测无执行步骤的测试点

    如果有 ⚠ 警告,必须先修复 full.md 再写回。 不要带警告强行写入。 展示场景概览和节点数给用户确认。

  4. 用户确认后,执行写回:

    python {writeback.py路径} {产物根目录}/full.md \
      --case-id {caseId} --modifier case-lite

    脚本自动完成:

    • 重复写入检测:若 caseId 已有 AI 节点则提醒并中止,请用户先在搬山平台清空用例后重试
    • 解析 markdown → 构建节点树 → 调用搬山 batchAddNode → testCaseDetail 验证

    agent 只需读取终端输出摘要并告知用户结果。

  5. 产物:
    • writeback/node-tree.json — 节点树 JSON
    • writeback/writeback-log.json — 写回日志
  6. 更新迭代索引(仅在提供了迭代信息时):写回成功后,将 iteration-index.md 中本需求行的 搬山 caseId 填为本次 caseId,状态置为 已写回,更新时间置为当天。写回失败或中止时不要改动索引。

脚本源码:scripts/writeback.py。零外部依赖,纯 Python 标准库。 MCP 端点可通过环境变量 BANSHAN_MCP_ENDPOINT 覆盖。


structure.md 格式规范

编号即层级:场景3.1 是 场景3 的子场景,测试点3.1.2 挂在 场景3.1 下。

### 场景1:场景标题
  - 测试点1.1:测试点标题(P0)
  - 测试点1.2:测试点标题(P1)

### 场景2:场景标题
  - 测试点2.1:测试点标题(P0)
  - 测试点2.2:测试点标题(P2)

### 场景3:场景标题(含子场景,本层不直接挂测试点)
#### 场景3.1:子场景标题
  - 测试点3.1.1:测试点标题(P0)
  - 测试点3.1.2:测试点标题(P1)
#### 场景3.2:子场景标题
  - 测试点3.2.1:测试点标题(P0)
  • 不拆子场景时,结构与旧版完全一致
  • 一个场景要么直接挂测试点,要么只挂子场景,不能两者混排(见下方「场景分层规则」)
  • 分层决策在 Step 3d 复核,复核结论写在给用户的确认消息里,不写进 structure.md

full.md 格式规范

核心约定:编号即路径

writeback.py 用编号段数决定树的层级,不看标题的 # 级别。

写法编号路径在树中的位置
场景1:登录(1)顶层场景
场景3:支付(3)顶层场景
场景3.1:微信支付(3,1)场景3 的子场景
测试点1.1:正常登录(1,1)场景1 下的测试点
测试点3.1.2:余额不足(3,1,2)场景3.1 下的测试点

推论(很重要):

  • 标题级别只影响阅读观感,不影响解析结果。写错级别不会导致节点丢失或错位,写错编号才会。
  • 执行步骤 / 预期结果 的标记与深度解耦:#### 执行步骤、##### 执行步骤、**执行步骤** 都能被识别。推荐统一用 #### ,不必随嵌套深度往下顺延。
  • 建议标题级别 = 场景深度 + 1(场景1 → ##,场景3.1 → ###,场景3.1.1 → ####),纯粹为了好读。

单层场景(最常见,与旧版完全一致)

## 场景1:场景标题

### 测试点1.1:测试点标题

#### 执行步骤
1. 前置:已登录XX系统,进入XX页面(前置条件融入第一步)
2. 操作步骤(精确到字段/按钮/接口级)

#### 预期结果
1. 期望结果(可量化断言)

多级场景

## 场景3:支付

### 场景3.1:微信支付

#### 测试点3.1.1:余额充足时支付成功

#### 执行步骤
1. 已登录且微信账户余额 ≥ 订单金额,进入收银台
2. 选择「微信支付」,点击「确认支付」

#### 预期结果
1. 调起微信收银台,订单状态由「待支付」变为「已支付」
2. POST /order/pay 返回 code=0

#### 测试点3.1.2:余额不足时支付失败

#### 执行步骤
1. 已登录且微信账户余额 < 订单金额,进入收银台
2. 选择「微信支付」,点击「确认支付」

#### 预期结果
1. 提示「余额不足」,订单保持「待支付」

### 场景3.2:支付宝支付

#### 测试点3.2.1:免密支付直接扣款

#### 执行步骤
1. 已开通支付宝免密,进入收银台
2. 选择「支付宝」,点击「确认支付」

#### 预期结果
1. 无需二次确认直接扣款成功

对应写入搬山后的树形:

场景3:支付
├── 场景3.1:微信支付
│   ├── 测试点3.1.1:余额充足时支付成功
│   │   └── 执行步骤 → 预期结果
│   └── 测试点3.1.2:余额不足时支付失败
│       └── 执行步骤 → 预期结果
└── 场景3.2:支付宝支付
    └── 测试点3.2.1:免密支付直接扣款
        └── 执行步骤 → 预期结果

场景分层规则(硬约束,违反会被 writeback.py 拒绝)

  1. 不允许混搭:任一场景的直接子节点,要么全是子场景,要么全是测试点,不能两者共存。
    • ✗ 场景1 下同时有 测试点1.1 和 场景1.1
    • ✓ 想加子场景,就把 测试点1.1 也下沉到某个子场景里
  2. 编号不能断层:出现 场景3.1 之前必须先有 场景3,且父场景要写在子场景前面
  3. 编号不能重复:同一个 场景N / 测试点N.M 编号只能出现一次
  4. 测试点至少两段编号:测试点1.1 ✓,测试点1 ✗(测试点不能挂在根节点下)
  5. 场景嵌套建议不超过 3 层:超过只提示不阻塞,但通常说明该需求应拆成多个搬山用例。 另有 20 层硬上限用于挡住畸形输入,正常写法碰不到

以上是 writeback.py 机械校验的部分。拆不拆是判断题,判据见 Step 3d 场景分层复核。

真实示例(来自参考用例 22328,writeback.py 可正确解析)

## 场景1:速搭端-下发重置密码链接

### 测试点1.1:未输入userId或重置原因时执行,不出现链接

#### 执行步骤
1. 打开「飞途速搭-操作类-账号密码重置」页面
2. 保持userId输入框为空,重置原因输入框为空,点击「执行」按钮
3. 分别验证仅填写userId不填重置原因、仅填写重置原因不填userId两种情况

#### 预期结果
1. 三种情况下页面均不出现重置密码链接
2. 不触发下发链接请求

### 测试点1.2:填写userId和重置原因后点击执行,生成重置密码链接

#### 执行步骤
1. 打开「飞途速搭-操作类-账号密码重置」页面
2. 在userId输入框中输入目标用户的userId(如6819696814)
3. 在重置原因输入框中输入原因(如"无法收到手机验证码")
4. 点击「执行」按钮

#### 预期结果
1. 请求 POST /v1/user/visitor/adminReset/sendLink 接口,入参包含targetUserId、reason、employeeId
2. 接口返回有效的重置密码链接
3. 页面出现蓝色可点击链接
4. 后台记录客服操作日志
  • 执行步骤 / 预期结果:#### 级标题 + 编号列表
  • 不生成 **前置条件** section,前置条件融入执行步骤第一步

full.md 写回解析约束(必须严格遵守)

writeback.py 用正则逐行解析 full.md,以下格式偏差会导致节点丢失:

writeback.py 用正则逐行解析 full.md,并把编号解释为树路径。违反规则的后果分三档:阻塞错误(拒绝写回)、警告(dry-run 拒绝放行)、建议(只提示)。

阻塞错误 —— 结构不合法,dry-run 和写回都会中止(exit 2)

规则正确错误
场景直接子节点不混搭场景1 下全是测试点,或全是子场景场景1 下同时有 测试点1.1 和 场景1.1
编号不断层,父在子前先 场景3,再 场景3.1出现 场景3.1 但没有 场景3
编号不重复(场景和测试点都算)每个编号只出现一次两个 ## 场景1:,或两个 ### 测试点1.1:
测试点至少两段编号测试点1.1:标题测试点1:标题
场景嵌套不超过 20 层(硬上限)正常写法远低于此值畸形输入,如 20 层以上嵌套

警告 —— 内容可能丢失,dry-run 会拒绝放行

规则正确错误(会被跳过)
场景/测试点用阿拉伯数字 + 冒号场景1:标题、场景1:标题场景一:标题、场景1 标题(无冒号)
标题必须是这四类之一场景N / 测试点N.M / 执行步骤 / 预期结果自创的 ### 补充说明 等标题
步骤/结果内容用编号列表;编号步骤下可用 - 子项列举输入数据1. 分别输入以下内容: + - 输入A纯 bullet 作为主步骤,缺少编号父步骤
每个测试点必须有执行步骤先 执行步骤 再 预期结果只有预期结果无执行步骤(结果会被丢弃)
场景不能为空每个场景至少有一个测试点或子场景空场景(写进去是无意义节点)
编号连续不跳号测试点1.1 测试点1.2 测试点1.3测试点1.1 测试点1.3(通常是生成时被截断)
同级编号按升序书写测试点1.1 写在 测试点1.2 前面先写 测试点1.2 再写 测试点1.1(写入搬山后的节点次序由书写顺序决定,与编号不一致会造成误读)
每段编号不超过 6 位场景12:标题场景{一长串数字}:标题(不会被识别为场景)

建议 —— 只打印,不阻塞

提示含义
场景嵌套超过 3 层平台支持,但通常说明该拆成多个搬山用例(20 层是硬上限,见阻塞错误)
某场景只有 1 个子场景拆了等于没拆,可合并回上层
某场景下测试点超过 10 个可考虑按维度拆子场景

不再是问题的(相比旧版放宽)

项说明
标题的 # 级别解析时忽略,写错级别不会导致节点丢失或错位
#### 执行步骤 vs **执行步骤**两种写法都能识别,任意 # 级别也都能识别
--- 分割线已明确跳过,不干扰解析

仍然保留:不生成 **前置条件** section,其内容会被解析器跳过、不写入搬山,前置条件应融入执行步骤第一步。

生成 full.md 后必须跑 writeback.py --dry-run。它会打印完整的场景/测试点树形概览,逐层核对比数数字更可靠。


工具依赖

工具用途阶段必需
feishu-docx-blocks MCP文档解析、章节获取、语料拉取Step 2, 3是
Banshan MCP通过 caseId 获取参考用例Step 3a推荐(可降级)
scripts/writeback.pyfull.md 解析 + 节点树构建 + HTTP 写回搬山Step 6内置,无需安装

风格规则

详见 assets/case-learning.md。

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.