我的职责
我指导 orchestrator 创建新功能(不修改现有功能),并事先进行复用性、配置和兼容性分析。与重构不同,这里没有需要保留的现有代码:设计从用户需求开始。
何时使用此技能(而非 refactor-protocol):
- 用户请求一个不存在的端点、服务、job、handler、事件或配置
- 任务是纯粹的创建,不修改现有行为
- 结果会向仓库添加文件,不会改变现有文件的签名
何时不使用此技能(应使用 refactor-protocol):
- 修改现有服务的签名
- 更改已存在的端点的行为
- 重命名、提取或移动代码
阶段 0 — 结构验证(始终优先)
- 加载
project-structure技能并执行完整验证 - 检测宿主类型:
FUNCTIONS|WEBAPP|NUGET_LIBRARY - 根据结果执行操作:
| 状态 | 操作 |
|---|---|
HARD_BLOCK | 停止。通知用户。 |
NUGET_LIBRARY | 创建 HTTP 端点不常见。询问:“您是想在库中添加一个公共操作,还是真的有一个我未检测到的宿主?” |
PREGUNTA | 继续前先回答问题 |
OK / WARNING | 继续到阶段 1 |
阶段 1 — 需求收集
orchestrator 应从用户描述($ARGUMENTS)中推断尽可能多的信息,只问不清楚的问题。不要问描述中已有答案的问题。
1.1 名称、目的和功能类型
- HTTP 端点 (Function/Controller):
[VERB] /路径 — 描述 - 领域服务:服务名称和职责
- Job/事件处理器:触发器 + 操作
- 配置选项:选项名称及其用途
1.2 只读 vs 修改分类
确定功能是修改状态还是只读。这会影响:
- Response DTO 的位置
- 是否需要事务/幂等性
- 需要哪些测试
| 类型 | 特点 | 影响 |
|---|---|---|
| READ-ONLY | GET,返回现有数据,不写入 | 临时 DTO,最少测试 |
| MUTATION | POST/PUT/DELETE,写入或更改状态 | 需要成功+错误测试 |
1.3 收集期望的输入/输出
- 请求:body 或 query params 的结构
- 响应:响应 body 的结构,状态码
- 错误:哪些错误应映射到哪些状态码
阶段 1.5 — 复用分析(关键,不可跳过)
目标:在创建任何内容之前,检测功能是否已部分或完全存在。
步骤
- 使用
@explore在*.Impl/中搜索与功能领域相关的现有服务 - 搜索能覆盖 80%+ 所需行为的候选方法:
- 是否有方法已返回所需数据,只需简单过滤?
- 是否有方法可以通过重载来添加此情况?
- 在
*.API/中搜索具有相同请求/响应形状的类似端点
决策树
是否存在 100% 覆盖当前情况的方法?
└── 是 → 不创建新方法。仅创建:
· *.API/ 中的端点 (Function/Controller)
· *.API/ 中专用的 Request/Response DTO
· 响应形状的测试
是否存在几乎完美的方法(过滤、分页、排序)?
├── 是 → 考虑:
│ ├── 为现有方法添加可选参数(带默认值)
│ ├── 创建具有更具体签名的重载
│ └── 创建包装现有方法的扩展方法
└── 否 → 继续创建新方法
是否存在相关但不同的服务(例如,类似职责)?
├── 是 → 询问用户:“我扩展 [CSXxxService] 还是创建一个新的 [CSYyyService]?”
└── 否 → 创建新服务
此阶段的预期输出
以下三个决定之一,在继续前展示给用户:
- 纯复用:功能作为现有方法的包装器实现
- 扩展:向现有服务添加重载/方法
- 新建:新服务和方法(说明为何不能复用)
阶段 1.6 — 配置分析(新增)
目标:检测功能是否需要可配置参数,如果需要,在哪里定义它们。
关键问题
- 功能是否有合理的默认值而无需外部配置?
- 是否有阈值、分页、超时或标志应可按环境配置?
- 是否连接到外部系统,需要 URL/密钥/机密?
- 是否需要功能标志以实现逐步推出?
决策树
功能是否需要配置?
├── 否 → 不创建 IXxxOptions,不修改 AddCustomConfiguration
└── 是 → 继续
什么类型的配置?
├── 连接字符串或机密
│ └── 使用 IConfiguration,名称在 appsettings.json 中(由 AddCustomConfiguration 管理)
├── 简单值(阈值、超时、标志)
│ └── 在 *.Impl/ 中创建 IXxxOptions(接口)+ 添加到 AddCustomConfiguration<T>("key")
└── 值列表(允许的来源、映射)
└── 创建具有 IEnumerable<T> 类型属性的 IXxxOptions
项目约定
项目使用 AddCustomConfiguration<IXxxOptions>("config-section") 在 IoCExtensions.cs 中(当前项目的第 43-45 行)。接口位于 *.Impl/ 中,并从 *.Impl/Services/ 引用。
预期输出
如果功能需要配置,向用户展示:
- 接口名称(例如,
IPendingPaymentOptions) - 属性及其类型和默认值
appsettings.json中的节(例如,"RAMBLA.PendingPayment")- 对
IoCExtensions.AddCSLevelBooking()的修改
如果不需要,在计划中明确指出。
阶段 1.7 — 公共 API 影响分析
目标:避免破坏现有消费者。
如果功能复用一个现有方法
- 方法保持相同签名?→ 无影响
- 添加可选参数?→ 验证没有调用点被破坏
- 添加重载?→ 验证编译器能无歧义地解析
- 重命名?→ 用
grep搜索所有调用点并迁移
如果功能添加新服务
- 服务是否注册到 DI?→ 确保在
IoCExtensions中注册 - 任何现有服务是否有潜在的循环依赖?→ 验证
如果功能添加新端点
- 路由是否与现有路由冲突?→ 验证
- HTTP 方法是否与 REST 一致?(GET 用于读取,POST 用于修改)
阶段 1.8 — 回归测试预检(必需)
目标:在生成新代码或修改现有代码之前,验证即将动用的组件(即使是间接的)是否有测试覆盖。如果没有,则在开始实现之前创建并运行它们。
步骤
-
识别间接影响面:根据阶段 1.5(复用、扩展或新建),列出:
- 其方法将被扩展或重载的现有服务
- 将被修改的现有接口
- 可能受路由/DI 影响的现有端点
- 任何将被编辑(而非创建)的现有文件
-
对于每个将被打扰的现有组件:
- 在
src/*.Test*/**中搜索执行它的测试 - 如果有覆盖 → OK,继续
- 如果没有覆盖 → HARD BLOCK:
- 调用
@refactor-worker-tests创建当前行为的特性测试 - 调用
@refactor-verifier确认测试通过 - 单独提交:
test(characterization): add characterization tests for <类>
- 调用
- 在
-
如果功能是 100% 全新创建(不触及现有文件):
- 没有回归影响面 → 跳过预检
- 但新功能的测试在阶段 4 创建,并必须在阶段 5 通过
阶段 5 的完成标准
要认为功能正确完成,@refactor-verifier 必须确认以下测试通过:
- 新测试(服务 + 端点)
- 现有测试(间接影响组件——回归)
如果任何测试失败,功能不能关闭。
阶段 2 — 决策树:创建什么以及放在哪里
应用阶段 1.5(复用/扩展/新建)和阶段 1.6(配置)的决定。
对于带复用的只读端点
*.API/
+ {Name}Function.cs — 新的 Function/Controller
+ {Name}Request.cs — 表示层专用
+ {Name}Response.cs — 表示层专用
*.Test*/
+ {Name}FunctionTests.cs — 响应形状测试(非逻辑)
对于带新服务的修改端点
*.Contracts/
+ ICS{Name}Service.cs — 服务接口
+ {Name}Request.cs — 如果共享 Request
+ {Name}Response.cs — 如果共享 Response
*.Impl/
+ CS{Name}Service.cs — 实现
+ I{Name}Options.cs — 仅在阶段 1.6 检测到配置时
*.API/
+ {Name}Function.cs — Function/Controller
+ {Name}Request.cs — 专用(如果未放在 Contracts 中)
+ {Name}Response.cs — 专用(如果未放在 Contracts 中)
*.Test*/
+ CS{Name}ServiceTests.cs — happy path + 至少一个错误
对于扩展现有服务
*.Contracts/
~ ICS{Name}Service.cs — 添加方法签名(或创建重载)
*.Impl/
~ CS{Name}Service.cs — 实现新方法/重载
*.API/
+ {Name}Function.cs — 新的 Function/Controller
+ {Name}Request.cs — 如果专用
+ {Name}Response.cs — 如果专用
*.Test*/
+ (或 ~) 服务测试 — 为新方法添加用例
阶段 3 — 创建计划
在调用 workers 之前,orchestrator 向用户展示此计划并等待明确确认:
[创建计划] 功能:<名称> — <简要描述>
宿主:<FUNCTIONS | WEBAPP>
分类:<READ-ONLY | MUTATION>
策略:<REUSE | EXTENSION | NEW>
复用分析(阶段 1.5):
· 候选服务:<ICSXxxService> 或 "无"
· 候选方法:<XxxService.YyyMethod> 或 "无"
· 决定:<REUSE | EXTENSION | NEW>
配置分析(阶段 1.6):
· 需要配置:<YES | NO>
· 如果是:<IXxxOptions + appsettings 节>
公共 API 影响(阶段 1.7):
· 受影响的调用点:<列表> 或 "无"
· 破坏性变更:<YES | NO>
要创建的工作产物:
*.Contracts/([N] 文件):
+ ICS{Name}Service.cs — 新接口(或:向 IXxx 添加方法)
+ {Name}Request.cs — 如果共享类型
+ {Name}Response.cs — 如果共享类型
*.Impl/([N] 文件):
+ CS{Name}Service.cs — 服务实现
+ I{Name}Options.cs — 仅当需要配置时(阶段 1.6)
*.API/([N] 文件):
+ {Name}Function.cs — Azure Function(或:{Name}Controller.cs)
+ {Name}Request.cs — 如果专用类型
+ {Name}Response.cs — 如果专用类型
*.Test*/([N] 文件):
+ CS{Name}ServiceTests.cs — 服务测试(happy path + 错误)
+ {Name}FunctionTests.cs — 端点测试(如果适用)
对现有文件的修改:
~ src/.../IoCExtensions.cs — 注册服务和选项(如果适用)
执行顺序:Contracts → Impl → Presentation → Tests
是否继续?
没有用户的明确批准,不调用 workers。
阶段 4 — 执行
Workers 的调用顺序
@refactor-worker-contracts— 仅当*.Contracts/中有新类型或签名时@refactor-worker-impl— 只要*.Impl/中有代码@refactor-worker-presentation— 只要有端点@refactor-worker-tests— 始终在最后
注意:除非功能暴露了新的 Service Gateway,否则不调用
@refactor-worker-crosscutting。这在创建时很少见;通常在重构中发生。
给每个 worker 的指令
在提示中包含:
- 完整计划(阶段 3)
- 项目模式:在创建之前读取一个类似的文件
- 文件的精确列表及其预期内容
- 如果阶段 1.6 检测到配置:
IXxxOptions的路径和配置节
阶段 5 — 验证和提交
- 调用
@refactor-verifier - 如果通过 → 建议提交,格式如下:
feat(<scope>): add <短名称> feature - Added ICS{Name}Service interface and CS{Name}Service implementation - Added {VERB} /{路径} Function/Controller - Added {Name}Request/{Name}Response contracts - Added I{Name}Options for new configuration (if applicable) - Added unit tests for CS{Name}Service - 如果失败 → 识别失败层,重新调用 worker,重新验证
各宿主模式
FUNCTIONS — Azure Functions 独立工作进程
在创建 Function 之前,读取一个现有的 HTTP Function 并复制其样式。典型示例:
public class {Name}Function
{
private readonly I{Name}Service _field;
public {Name}Function(I{Name}Service {field}) => _field = {field};
[Function("{Name}Function")]
public async Task<HttpResponseData> RunAsync(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = "{route}")] HttpRequestData req)
{
var request = await req.ReadFromJsonAsync<{Name}Request>();
var result = await _field.ExecuteAsync(request);
var response = req.CreateResponse(HttpStatusCode.OK);
await response.WriteAsJsonAsync(result);
return response;
}
}
创建前验证:
- 是
AuthorizationLevel.Function还是 `A
…
[为翻译而截断]