# Task Templates — cryptoHermes 任何非平凡修改(>1 个文件、改边界、引入新依赖、改 migration、新增 collector),先写一份微型任务契约。短即可——长度像 commit message,但目的是让你自己(和后续 agent)能在 30 秒内对齐范围。 --- ## 通用契约模板 ``` objective: 一句话说要做的事 scope: 会改的文件 / 目录(具体路径,不要"相关文件") out-of-scope: 显式不改的范围(防止 scope creep) constraints: 引用 ai/risk-guardrails.md 的哪几条(G1-G10) validation: 要跑哪些命令证明通过(必须可机械执行) acceptance: 完成判据(行为可观测的描述) ``` **示例**: ``` objective: 给 /v1/market/context 加一个 ?intervals=1h,4h 参数,允许 Hermes 只拉部分周期,减少响应体积 scope: - internal/controller/restapi/v1/market_routes.go - internal/usecase/market_context.go - README.md(API 段补 query 参数说明) out-of-scope: - 不改 entity(响应结构不变,只是 klines map 的 key 集合可能少几个) - 不改 collector(采集策略不变) constraints: - G6:不能在 controller 里直接调 repo,必须通过 usecase 接收 intervals 参数 validation: - go build ./... && go vet ./... - curl 'localhost:8080/v1/market/context?symbol=BTCUSDT&intervals=1h,4h' | jq '.klines | keys' - 期望:只返回 ["1h","4h"] acceptance: - 不传 intervals 时行为完全不变(默认全部 5 个周期) - 传未知 interval 返回 400 - 至少一个 happy-path 单测覆盖 ``` --- ## 任务类型 → 模板 ### T1. 新增 API 路由 ``` objective: <做什么> scope: - internal/controller/restapi/v1/.go(新 handler) - internal/usecase/.go(新业务方法或扩展现有) - internal/usecase/ports.go(如果需要新 repo 方法) out-of-scope: - 不改 entity 结构 - 不改 collector constraints: G6 validation: - go build ./... && go vet ./... - curl 测 happy-path + 错误参数 acceptance: - 路由响应符合 JSON schema - 参数校验完整(缺失/非法都返回 400) - README 更新 API 段 ``` ### T2. 新增数据表 / migration ``` objective: <为什么要存这个> scope: - migrations/0000N_.up.sql - migrations/0000N_.down.sql - internal/entity/.go - internal/repo/persistent/postgres/_repo.go - internal/usecase/ports.go(新 Repository 接口) out-of-scope: - 不改已发布 migration(编号≤当前 max) constraints: - G2(金额必须 string / NUMERIC(36,18)) - G4(UpsertMany 必须幂等) - G7(down/up 互逆) validation: - make migrate-up - make migrate-down - make migrate-up # 再次成功 - go build ./... acceptance: - 表是 hypertable:psql 跑 SELECT * FROM timescaledb_information.hypertables 看到 - upsert 跑两次行数不变 - 至少 1 个 repo 单测(连本地 Timescale) ``` ### T3. 新增数据源(CoinGlass / ETF / ...) **必须先写 `ai/specs/.md`**(见 AGENTS.md §8)。 ``` objective: 接入 提供 <什么数据> spec: ai/specs/.md scope: - internal/repo/webapi//{client,dto,mapper,...}.go - internal/usecase/ports.go(新 Provider 接口) - internal/app/app.go(DI 装配) - config/config.go + config.yml(新数据源的 base_url / rps / timeout) out-of-scope: - 不改 Binance client constraints: - G1(绝不接私钥) - G2(金额 string) - G5(必须走 pkg/httpclient 限流) validation: - go build ./... && go vet ./... - 临时挂一个 debug 路由验证能拉到真数据 acceptance: - 新 Provider 实现接口;usecase 不直接 import 包 - 速率预算文档化(在 spec 里) ``` ### T4. 改 collector / scheduler ``` objective: <调整哪个采集,为什么> scope: - internal/worker/collector.go - internal/app/scheduler.go out-of-scope: - 不改 binance client(如果要新方法,先开 T3 / T1) - 不改表结构(如果要,开 T2) constraints: - G3(未收线丢弃) - G4(upsert 幂等) - G5(rate limit 不绕开) validation: - go build ./... && go vet ./... - 本地起服务跑 1 个 cron 周期,psql 看新行写入 acceptance: - 新 cron 表达式合理(不要 0 0 * * * 这种容易和别人撞的高峰) - 重启服务后 scheduler 能正常注册 - weight 预算在 PR 描述里说明(Binance 2400/min IP 上限) ``` ### T5. Bug fix ``` objective: 修 (issue 链接或复现命令) scope: <最小改动范围> constraints: <相关 G 条> validation: - 写一个能复现 bug 的最小测试(先红后绿) - go build ./... && go vet ./... acceptance: - 测试通过 - 不引入新的 lint warning ``` ### T6. 重构 / Clean Architecture 修正 ``` objective: <消除哪个边界违反 / 抽取哪段重复> scope: <文件列表> out-of-scope: - 不改行为(API 响应字节级一致 / DB schema 不变) constraints: G6 validation: - go build ./... && go vet ./... - 全部 grep 边界检查(AGENTS.md §6) - make test acceptance: - diff 中不含行为变化(只是搬代码 / 重命名 / 抽接口) ``` --- ## 何时升级到 spec micro contract 写不下、或者需要跨多个 agent / 多次会话才能完成 → 升级到 `ai/specs/.md`: - 多 milestone 跨越 - 引入新数据源 - 改变响应 schema(影响上游 Hermes) - 引入新部署组件(消息队列、新 service) spec 内容:objective / non-goals / config 形状 / API 形状 / 错误模式 / 兼容性 / 验收 / 验证计划。 --- ## 何时升级到 ADR contract 涉及"以后类似场景应该都这么做" → 写 ADR(`ai/adr/000N-.md`): - 换核心库 - 改架构层数 / 改 Clean Arch 边界 - 引入新通信协议 - 改部署拓扑 ADR 结构参考 `ai/adr/0001-architecture-foundations.md`。 --- ## 反模式 - ❌ "顺便把这里也改一下"——顺便的部分单独开一个 contract,不要混 - ❌ "测试很难写,先合了"——测试难写说明设计有问题,先调设计 - ❌ "之前 review 过类似的,应该没问题"——每个 PR 独立 validate - ❌ commit message 写"WIP"——本仓库不允许 WIP commit 进 main