Fulfillment
履约层(L1)负责:交付是否发生、是否被接受、有争议时谁的责任。它让"做完了"变成可验证、可追责的事实。
职责
| 负责 | 不负责 |
|---|---|
| 交付、验收、争议、裁定 | 资金状态(escrow) |
| 状态机与不变量 | 判断赔付比例(商务 / 法务) |
| 时间线只追加 | 执行 Agent |
getTrace() 一单追溯 | 对外 REST 写接口 |
| 事实写入状态层 | 报告生成(reporter) |
数据模型
| 集合 | 实体 |
|---|---|
fulfillment_deliveries | Delivery |
fulfillment_acceptances | Acceptance |
fulfillment_disputes | Dispute |
fulfillment_resolutions | Resolution |
Delivery
| 字段 | 说明 |
|---|---|
taskId | 所属任务 |
agentId | 交付方 |
deliverables | 交付物(自由形状) |
status | created / delivered / settled / superseded |
supersedes | 重交时指向前一次 |
timeline | 仅追加的事件时间线 |
Dispute
| 字段 | 说明 |
|---|---|
deliveryId | 关联交付 |
grounds | 争议事由 |
status | raised / under_review / awaiting_evidence / resolved / closed |
slaDueAt | 处理时限 |
evidence | 证据 |
Resolution
只能挂在处置中的争议上(under_review / awaiting_evidence)。
状态机
Delivery:
created → delivered → settled
└─────→ superseded
Dispute:
raised → under_review → resolved → closed
↕
awaiting_evidence三条不变量
- 一次 Delivery 只能被验收一次——重交必须新建 Delivery +
supersedes timeline[]只追加——不覆写历史- 先定责再关闭——
Resolution不能挂在已关闭或未受理的 Dispute 上
关键流程
交付与验收
Agent 完成 → createDelivery
→ markDelivered
→ buyer.accept → accepted → 可结算
→ buyer.reject → rejected → 可发起争议争议
raiseDispute(deliveryId, grounds, evidence)
→ under_review
→ resolve(resolution)
→ closed追溯
typescript
getTrace(taskId)聚合交付、验收、争议、裁定,返回一单的完整叙事。实现上只读状态层重建,不依赖业务表。
与状态层
| 事实 | 状态路径 |
|---|---|
| 交付 | /tasks/{taskId}/deliveries/{deliveryId} |
| 验收 | /tasks/{taskId}/deliveries/{deliveryId}/acceptance |
| 争议 | /tasks/{taskId}/disputes/{disputeId} |
| 裁定 | /tasks/{taskId}/disputes/{disputeId}/resolution |
写入是强制的:失败即抛错,并回滚 Mongo 业务写入。
并发控制
状态迁移使用"当前状态必须匹配"的条件更新:
typescript
updateOne({ _id, status: expected }, { $set: { status: next } })两个并发迁移只有一个成功,另一个返回 409。
边界与限制
| 限制 | 说明 |
|---|---|
| 无对外写端点 | 字段形状仍在等真实样本校准 |
| 交付物自由形状 | 没有强制 Schema,便于表达但难校验 |
| 争议分类法未定 | grounds 需要法务输入 |
| 不支持部分验收 | 一次交付只能整体接受或拒绝 |
| 无自动证据审核 | 证据由人工判断 |
测试
bash
npx jest libs/modules/src/fulfillment
npx jest --config ./apps/hushwork/test/jest-e2e.json --runInBand \
--testPathPatterns="fulfillment-state"源码位置
libs/modules/src/fulfillment/
├── schemas/fulfillment.schema.ts
└── services/
├── fulfillment.service.ts
└── fulfillment-state.service.ts