为什么:原 controller handler 在 HTTP 层同时承担了 4 项 usecase 职责 (多源拼装、错误降级策略、limit 硬编码、响应结构组装),违反了 "controller 只做参数解析 + 调用 + 序列化" 的边界。等后续给衍生品加 缓存 / taker volume / 数据质量字段时,HTTP 层会持续变厚。 改动: - 新增 internal/usecase/market_query.go: MarketQueryUsecase.GetDerivatives() 并发拉 current funding/OI + 串行查历史 + 错误聚合为 warnings 返回 - /derivatives handler 退化到 4 行;MarketDeps / restapi.Deps 同步收窄 - /klines 保持直查 KlineRepo(thin query,G11 例外) - 新增 G11 守卫:grep "FundingRepo|OIRepo|LSRepo|TakerRepo" internal/controller 破坏性 API 变更(/derivatives 响应): - 删除 funding.error / openInterest.error - 新增顶层 warnings: []string 顶层 symbol / funding / openInterest / longShortRatio / takerBuySellVolume 保持。 harness 同步: - AGENTS.md §6 加 G11 grep - ai/project-map.md 加 market_query.go + /derivatives 数据流分支 - ai/task-templates.md T6 加"破坏性变体"分支(本次重构暴露了原假设过严) - ai/harness-health.md W1 记一次轻量验证 + 守卫数 10→11 验收: go build / go vet / G6 grep / G11 grep 全绿。
210 lines
6.7 KiB
Markdown
210 lines
6.7 KiB
Markdown
# 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/<file>.go(新 handler)
|
||
- internal/usecase/<file>.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_<name>.up.sql
|
||
- migrations/0000N_<name>.down.sql
|
||
- internal/entity/<name>.go
|
||
- internal/repo/persistent/postgres/<name>_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/<source>.md`**(见 AGENTS.md §8)。
|
||
|
||
```
|
||
objective: 接入 <source> 提供 <什么数据>
|
||
spec: ai/specs/<source>.md
|
||
scope:
|
||
- internal/repo/webapi/<source>/{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 <source> 包
|
||
- 速率预算文档化(在 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: 修 <bug 简述>(issue 链接或复现命令)
|
||
scope: <最小改动范围>
|
||
constraints: <相关 G 条>
|
||
validation:
|
||
- 写一个能复现 bug 的最小测试(先红后绿)
|
||
- go build ./... && go vet ./...
|
||
acceptance:
|
||
- 测试通过
|
||
- 不引入新的 lint warning
|
||
```
|
||
|
||
### T6. 重构 / Clean Architecture 修正
|
||
|
||
```
|
||
objective: <消除哪个边界违反 / 抽取哪段重复>
|
||
scope: <文件列表>
|
||
out-of-scope:
|
||
- 行为变化(默认:API 响应字节级一致 / DB schema 不变)
|
||
- 例外:如果重构本身是为了把不该在 controller 的"错误降级 / 响应组装"搬进 usecase,
|
||
可以一并修响应契约(如 sub-object 的 error 字段聚合为顶层 warnings)。
|
||
必须在 acceptance 显式标 "破坏性",并在 PR 描述列出旧 → 新字段映射。
|
||
constraints: G6 + G11(如果动 controller)
|
||
validation:
|
||
- go build ./... && go vet ./...
|
||
- 全部 grep 边界检查(AGENTS.md §6)
|
||
- make test
|
||
acceptance:
|
||
- 默认:diff 中不含行为变化(只是搬代码 / 重命名 / 抽接口)
|
||
- 破坏性变体:列出响应字段变化,确认上游(Hermes)消费方已知或不受影响
|
||
```
|
||
|
||
---
|
||
|
||
## 何时升级到 spec
|
||
|
||
micro contract 写不下、或者需要跨多个 agent / 多次会话才能完成 → 升级到 `ai/specs/<task>.md`:
|
||
|
||
- 多 milestone 跨越
|
||
- 引入新数据源
|
||
- 改变响应 schema(影响上游 Hermes)
|
||
- 引入新部署组件(消息队列、新 service)
|
||
|
||
spec 内容:objective / non-goals / config 形状 / API 形状 / 错误模式 / 兼容性 / 验收 / 验证计划。
|
||
|
||
---
|
||
|
||
## 何时升级到 ADR
|
||
|
||
contract 涉及"以后类似场景应该都这么做" → 写 ADR(`ai/adr/000N-<decision>.md`):
|
||
|
||
- 换核心库
|
||
- 改架构层数 / 改 Clean Arch 边界
|
||
- 引入新通信协议
|
||
- 改部署拓扑
|
||
|
||
ADR 结构参考 `ai/adr/0001-architecture-foundations.md`。
|
||
|
||
---
|
||
|
||
## 反模式
|
||
|
||
- ❌ "顺便把这里也改一下"——顺便的部分单独开一个 contract,不要混
|
||
- ❌ "测试很难写,先合了"——测试难写说明设计有问题,先调设计
|
||
- ❌ "之前 review 过类似的,应该没问题"——每个 PR 独立 validate
|
||
- ❌ commit message 写"WIP"——本仓库不允许 WIP commit 进 main
|