# 拒绝跨领域通用条件写入 Module

状态：已采纳（2026-08-11）

## 背景

Campaign 与 Intelligent Evaluation 的 Repository 都使用条件更新，并都区分 `applied`、`not_found`、`conflict`。因此曾考虑抽取跨领域的 compare-and-set module，以复用 SQL 模板和结果分类。

## 删除测试

假想 interface 至少需要调用方提供：数据库表与主键列、状态列、一个或多个期望状态、目标字段映射、时间戳策略、JSON 序列化、更新后模型映射，以及可选的同事务副作用。

两个领域真正需要隐藏的知识并不相同：

| 维度 | Campaign | Intelligent Evaluation |
|---|---|---|
| 状态条件 | 可接受多个来源状态 | 单一期望状态与完整转换表 |
| 时间语义 | 调用方传入时间；按目标状态写开始或完成时间 | Repository 取当前时间；始终更新 `updated_at`，首次执行用 `coalesce` |
| 业务字段 | 主要写状态 | 同时写计划、反馈或报告，并负责 JSON 序列化 |
| 事务副作用 | 完成/取消时同步结算 Exploration Session | 无跨聚合结算 |
| 冲突结果 | 返回当前 Campaign 快照 | 返回冲突分类，由 lifecycle 重新表达领域错误 |

删除该假想 module 后，只会在两个 Repository 中恢复少量 SQL 更新与结果分类；状态规则、字段映射和事务副作用仍必须留在各自领域。它不能减少调用方需要掌握的知识，反而会把稳定的领域差异暴露为通用参数和回调，形成浅 interface。

## 决策

不创建跨 Campaign 与 Intelligent Evaluation 的通用条件写入 module。两侧保留领域命名的结果类型和 Repository 私有 helper；生命周期 module 继续作为生产调用方的写入 interface。

只有出现第三个真实 adapter，且至少三个调用面共享相同的状态条件、时间策略、字段语义、事务副作用和冲突映射时，才重新评估该 seam。单纯重复 SQL 形状不足以建立新 module。

## 影响

- 保持领域事务知识的 locality，Campaign 结算变化不会影响 Intelligent Evaluation。
- 接受少量 SQL 模板重复，避免通用字典、回调和类型擦除。
- 测试继续穿过各自 lifecycle interface，断言持久状态和领域副作用，而不是测试通用 SQL helper。
