a3bb78e06b
Security Quality Gate / npm audit, Bandit, pip-audit, detect-secrets (pull_request) Failing after 16m35s
656 lines
28 KiB
Markdown
656 lines
28 KiB
Markdown
# AI 合同平台 V2 Phase 3 next_action / action_hint 语义设计
|
||
|
||
## 背景
|
||
|
||
本设计继续对齐《AI 合同平台 V2 下一阶段开发优化方案》的 Phase 3 schema 硬化方向。
|
||
|
||
截至本设计前:
|
||
|
||
- `contract_versions` 已完成。
|
||
- 正式审批模型 `approval_instances / approval_steps / approval_actions` 已完成。
|
||
- 治理字段和软删除已完成。
|
||
- `status_label / status_tone` 已进入停写第一片,生产 SQLAlchemy 写路径会按 `status` 派生兼容缓存。
|
||
- 远端 smoke PostgreSQL / Docker 已验证 `display_cache_cleanup_prestate.status=ok`,旧展示缓存一致性为 0 mismatch。
|
||
|
||
当前不应删除 `contracts.next_action / contracts.next_actions`。这两个字段已经不是纯 UI 缓存,仍混合了承载系统动作、结构化上下文动作和人工跟进提示。
|
||
|
||
## 当前代码实况
|
||
|
||
### API 和前端读取
|
||
|
||
- `ContractListItem.next_action` 仍是合同列表、workspace 任务、统一搜索摘要的重要展示字段。
|
||
- `ContractDetail.next_actions` 仍是合同详情动作列表。
|
||
- 前端合同列表和详情页仍读取 `next_action / next_actions`。
|
||
- OpenAPI / BFF / 前端类型仍依赖这两个字段,短期不能改名或移除。
|
||
|
||
### 人工编辑入口
|
||
|
||
前端合同编辑面板仍允许编辑 `next_action`:
|
||
|
||
- `apps/contract-web/src/app/contracts/[id]/contract-edit-panel.tsx`
|
||
- 表单字段名:`next_action`
|
||
- 当前 UI 文案:`下一步操作`
|
||
|
||
后端仍允许 PATCH 更新:
|
||
|
||
- `ContractUpdateRequest.next_action`
|
||
- `ContractUpdateRequest.next_actions`
|
||
- `ContractCoreRepository.update_contract(...)` 会把 `next_action / next_actions` 写入 `contracts` 表。
|
||
|
||
这说明人工编辑入口仍存在,并且当前语义容易和系统派生动作混淆。
|
||
|
||
### 系统派生动作来源
|
||
|
||
`ContractActionContext` 已经从以下结构化事实派生动作:
|
||
|
||
- 最新审查任务状态:queued / running / succeeded / failed。
|
||
- 审查风险和未应用条款修复。
|
||
- 已应用条款修复。
|
||
- 待审批实例和待审批步骤。
|
||
- 未完成履约任务。
|
||
|
||
同时仍有部分写路径会直接写旧列 `next_action / next_actions`,例如文件上传、审查任务、条款修复、审批流和归档流程。这些后续应逐步改为写结构化事实,或只通过兼容 helper 写入派生缓存。
|
||
|
||
## 产品语义决策
|
||
|
||
结论:保留人工编辑入口,但不再把它称为“下一步操作”。
|
||
|
||
建议将人工可编辑内容定义为:
|
||
|
||
- 字段语义:人工跟进提示。
|
||
- 推荐字段名:`action_hint`。
|
||
- 推荐前端标签:`人工跟进提示`。
|
||
- 推荐说明:用于补充系统无法从流程事实推导出的提醒,例如“法务确认付款和验收条款”“补充租赁期限后提交”。
|
||
|
||
`next_action / next_actions` 继续作为 API 兼容展示字段保留,但其来源应逐步变为:
|
||
|
||
1. 结构化流程上下文。
|
||
2. 人工 `action_hint`。
|
||
3. 状态默认动作。
|
||
|
||
这样既保留用户需要的人工备注能力,又避免人工字段覆盖审批、审查、条款修复这类系统关键动作。
|
||
|
||
## 方案评估
|
||
|
||
### 方案 A:新增 `contracts.action_hint`
|
||
|
||
做法:
|
||
|
||
- 在 `contracts` 表新增 nullable 文本字段 `action_hint`。
|
||
- 前端编辑面板把原来的 `next_action` 输入改为 `action_hint`。
|
||
- API PATCH 暂时同时接受 `action_hint` 和旧 `next_action`,旧字段作为兼容入口。
|
||
- 响应继续返回 `next_action / next_actions`。
|
||
- `derive_contract_display(...)` 按优先级将 `action_hint` 纳入派生。
|
||
|
||
优点:
|
||
|
||
- 迁移小,语义清楚。
|
||
- 保留人工提示能力。
|
||
- 与当前 `ContractActionContext` 最容易衔接。
|
||
- 回滚简单,旧列仍保留。
|
||
|
||
缺点:
|
||
|
||
- 只能表达一条人工提示,不能精细覆盖多个动作按钮。
|
||
- 后续如果需要角色级、场景级动作覆盖,仍需要扩展。
|
||
|
||
结论:推荐作为第一片实现。
|
||
|
||
### 方案 B:新增 `contract_action_overrides`
|
||
|
||
做法:
|
||
|
||
- 新建子表或 JSON 结构,保存 action overrides。
|
||
- 字段可能包含 `source_type`、`priority`、`label`、`target_url`、`role_scope`、`expires_at`、`created_by`。
|
||
|
||
优点:
|
||
|
||
- 能支持多动作、角色级动作、过期时间、来源追踪。
|
||
- 适合未来做运营型动作配置。
|
||
|
||
缺点:
|
||
|
||
- 当前需求过重。
|
||
- 会把 Phase 3 cleanup 从 schema 硬化带到新业务模型设计。
|
||
- 迁移和前端交互都更复杂。
|
||
|
||
结论:暂不作为第一片。可作为后续增强,不阻塞 `action_hint`。
|
||
|
||
### 方案 C:移除人工编辑入口
|
||
|
||
做法:
|
||
|
||
- 前端删除 `next_action` 输入。
|
||
- 后端拒绝或忽略 PATCH 中的 `next_action / next_actions`。
|
||
- 所有动作完全由系统上下文派生。
|
||
|
||
优点:
|
||
|
||
- 数据模型最干净。
|
||
- 能最快停写旧 UI 缓存。
|
||
|
||
缺点:
|
||
|
||
- 会损失当前业务人员补充跟进提示的能力。
|
||
- V1/V2 早期样本里存在“法务确认付款和验收条款”“补充租赁期限后提交”这类人工上下文,它们不是纯状态默认动作。
|
||
|
||
结论:不建议当前采用。
|
||
|
||
## 推荐最终语义
|
||
|
||
### 字段分工
|
||
|
||
`status`
|
||
|
||
- 合同状态事实。
|
||
- 唯一来源:业务状态流。
|
||
|
||
`status_label / status_tone`
|
||
|
||
- 旧兼容缓存。
|
||
- 由 `status` 派生。
|
||
- 后续可停写或删列,但 API 响应字段继续保留。
|
||
|
||
`action_hint`
|
||
|
||
- 人工跟进提示事实。
|
||
- 可为空。
|
||
- 用户可编辑。
|
||
- 不应覆盖高优先级系统动作。
|
||
|
||
`next_action / next_actions`
|
||
|
||
- API 兼容展示字段。
|
||
- 不再视为长期事实字段。
|
||
- 由 `ContractActionContext + action_hint + status` 派生。
|
||
- 旧数据库列保留为兼容缓存,后续停写或删列。
|
||
|
||
## 派生优先级
|
||
|
||
建议优先级如下:
|
||
|
||
1. 已应用条款修复:`复核已应用的条款修订`。
|
||
2. 审查任务 queued / running:`等待法律审查结果`。
|
||
3. 审查任务 failed:`重新发起法律审查`。
|
||
4. 审查任务 succeeded 且有未应用修复:`处理审查风险并应用推荐条款`。
|
||
5. 审查任务 succeeded 且有风险:`根据审查结果修改或提交审批`。
|
||
6. 待审批步骤:`等待{role}审批`。
|
||
7. 已审批、已签署、已归档阶段的未完成履约任务:`跟踪履约节点:{title}`。
|
||
8. 人工 `action_hint`:例如 `法务确认付款和验收条款`。
|
||
9. 状态默认动作:例如 `补充后提交审批`、`准备签署与归档`。
|
||
|
||
原则:
|
||
|
||
- 结构化流程动作高于人工提示。
|
||
- 人工提示高于普通状态默认动作。
|
||
- `next_actions` 的按钮列表优先来自结构化上下文;当只有 `action_hint` 时,按钮列表仍使用当前状态默认动作,避免把人工提示误当作可点击动作。
|
||
|
||
## 兼容策略
|
||
|
||
### API 输入兼容
|
||
|
||
第一片建议:
|
||
|
||
- `ContractUpdateRequest` 新增 `action_hint: str | None = None`。
|
||
- 暂时保留 `next_action / next_actions`。
|
||
- 如果请求包含 `action_hint`,写入 `contracts.action_hint`。
|
||
- 如果请求只包含旧 `next_action`,按兼容策略写入 `action_hint`,但不再直接视为系统动作事实。
|
||
- 如果请求包含旧 `next_actions`,短期仍接受但标记 deprecated;后续只允许系统派生。
|
||
|
||
### API 输出兼容
|
||
|
||
短期不改:
|
||
|
||
- 合同列表继续返回 `next_action`。
|
||
- 合同详情继续返回 `next_action / next_actions`。
|
||
|
||
可选增强:
|
||
|
||
- 合同详情新增只读字段 `action_hint`,用于前端编辑面板回填。
|
||
- 合同列表是否返回 `action_hint` 可暂缓,避免扩大接口面。
|
||
|
||
### 前端兼容
|
||
|
||
第一片建议:
|
||
|
||
- 编辑面板标签从 `下一步操作` 改为 `人工跟进提示`。
|
||
- 表单提交字段改为 `action_hint`。
|
||
- 当后端未返回 `action_hint` 时,前端可先用当前 `contract.next_action` 回填,但只作为过渡。
|
||
- 详情页主展示仍显示 `next_action`,即系统派生后的下一步动作。
|
||
|
||
## 迁移切片
|
||
|
||
### Slice 3.5.3-a:设计锁定
|
||
|
||
本设计即为该片产物。
|
||
|
||
验收:
|
||
|
||
- 明确人工入口保留。
|
||
- 明确 `action_hint` 是人工提示事实字段。
|
||
- 明确 `next_action / next_actions` 是兼容展示字段。
|
||
- 不写 migration。
|
||
|
||
### Slice 3.5.3-b:新增字段和兼容写入
|
||
|
||
实现:
|
||
|
||
- Alembic 新增 `contracts.action_hint` nullable text/string 字段。
|
||
- SQLAlchemy `ContractModel` 新增 `action_hint`。
|
||
- `ContractUpdateRequest` 新增 `action_hint`。
|
||
- PATCH 兼容旧 `next_action`,写入 `action_hint`。
|
||
- 创建合同和模板起草可选择写入 `action_hint`,默认空。
|
||
|
||
验收:
|
||
|
||
- 旧 PATCH `next_action` 不报错。
|
||
- 新 PATCH `action_hint` 可保存。
|
||
- `schema-check` 确认 `action_hint` 字段存在。
|
||
- Docker smoke 可创建、编辑、提交审批、退回、重提、发起审查。
|
||
|
||
### Slice 3.5.3-c:派生层接入 `action_hint`
|
||
|
||
实现:
|
||
|
||
- `ContractActionContext` 增加 `action_hint`。
|
||
- SQLAlchemy action context loader 从 `contracts.action_hint` 读取。
|
||
- `derive_contract_display(...)` 按优先级接入 `action_hint`。
|
||
- 读路径返回派生后的 `next_action / next_actions`。
|
||
- 搜索文档使用派生后的 `next_action`。
|
||
|
||
验收:
|
||
|
||
- 没有审查、审批、履约、条款修复上下文时,`action_hint` 成为 `next_action`。
|
||
- 有高优先级结构化动作时,`next_action` 使用结构化动作,`action_hint` 不覆盖。
|
||
- `next_actions` 仍保持可执行动作列表,而不是人工提示列表。
|
||
|
||
### Slice 3.5.3-d:前端改名
|
||
|
||
实现:
|
||
|
||
- 编辑面板字段从 `next_action` 改为 `action_hint`。
|
||
- 文案从 `下一步操作` 改为 `人工跟进提示`。
|
||
- 详情页主动作展示继续用 `next_action`。
|
||
|
||
验收:
|
||
|
||
- 用户仍能保存人工提示。
|
||
- 保存后,在无更高优先级系统动作时,详情页下一步显示人工提示。
|
||
- 一旦进入审批或审查,详情页下一步显示系统动作。
|
||
|
||
### Slice 3.5.3-e:停写旧 `next_action / next_actions`
|
||
|
||
实现:
|
||
|
||
- 文件上传、审查任务、条款修复、审批流、归档流程不再手写旧列。
|
||
- 如仍需兼容缓存,由统一 helper 按派生结果刷新。
|
||
- 旧列只作为兼容缓存,不再作为事实来源。
|
||
|
||
验收:
|
||
|
||
- `display_cache_cleanup_prestate` 仍为 ok。
|
||
- 合同列表、详情、workspace、统一搜索展示不退化。
|
||
- 旧列与派生值一致性检查为 0 mismatch。
|
||
|
||
### Slice 3.5.4:cleanup migration 设计评审
|
||
|
||
只有满足以下条件后才考虑:
|
||
|
||
- `status_label / status_tone / next_action / next_actions` 已全部由派生层稳定输出。
|
||
- 前端不再提交旧 `next_action / next_actions` 作为事实字段。
|
||
- OpenAPI 兼容策略已明确。
|
||
- smoke PostgreSQL 和 Docker smoke 已连续通过。
|
||
|
||
此时再决定是否删列。当前不建议进入删列 migration。
|
||
|
||
## 回滚策略
|
||
|
||
- 新增 `action_hint` 为 nullable 字段,不影响旧读取。
|
||
- 旧 `next_action / next_actions` 列保留。
|
||
- 如果派生层有问题,可临时恢复使用旧列。
|
||
- 如果前端改名有问题,可继续兼容旧 `next_action` PATCH。
|
||
- 不做不可逆数据删除。
|
||
|
||
## 测试清单
|
||
|
||
后端单测:
|
||
|
||
- `action_hint` 可通过 PATCH 保存。
|
||
- 旧 `next_action` PATCH 可兼容写入 `action_hint`。
|
||
- 无结构化上下文时,`next_action` 派生为 `action_hint`。
|
||
- 有待审批步骤时,`next_action` 派生为审批动作,不被 `action_hint` 覆盖。
|
||
- 有审查风险和未应用修复时,`next_action` 派生为条款修复动作,不被 `action_hint` 覆盖。
|
||
- 有未完成履约任务时,已审批/已签署/已归档合同显示履约动作。
|
||
- `next_actions` 不把人工提示当按钮列表。
|
||
|
||
前端抽样:
|
||
|
||
- 合同详情编辑面板展示 `人工跟进提示`。
|
||
- 保存人工提示后页面刷新正常。
|
||
- 合同进入审批后,主下一步显示审批动作。
|
||
- 合同退回后,主下一步显示退回后的系统动作或人工提示,按优先级生效。
|
||
|
||
远端 smoke:
|
||
|
||
- 跑 `/api/v1/runtime/schema-check`。
|
||
- 创建合同。
|
||
- 编辑 `action_hint`。
|
||
- 提交审批。
|
||
- 退回。
|
||
- 重提。
|
||
- 发起审查。
|
||
- 抽样合同列表、详情、workspace、统一搜索。
|
||
|
||
## 当前建议
|
||
|
||
下一步不要直接删除 `next_action / next_actions`,也不要马上设计复杂 `contract_action_overrides` 子表。
|
||
|
||
最稳的下一片是:
|
||
|
||
1. 新增 nullable `contracts.action_hint`。
|
||
2. 保留旧列和旧 API 字段。
|
||
3. 让 PATCH 新旧字段都能进入 `action_hint`。
|
||
4. 让派生层在无更高优先级结构化动作时使用 `action_hint`。
|
||
5. 先在本地 PostgreSQL/测试中验证,再部署到 192.168.3.90 smoke。
|
||
|
||
## Slice 3.5.3-b 实施记录
|
||
|
||
本片已完成 `action_hint` 的第一阶段落库能力,仍未进入删列或派生层重排。
|
||
|
||
新增内容:
|
||
|
||
- Alembic migration:`20260630_0022_add_contract_action_hint.py`
|
||
- `contracts.action_hint` nullable 字段。
|
||
- SQLAlchemy `ContractModel.action_hint`。
|
||
- `ContractUpdateRequest.action_hint`。
|
||
- Contract API runtime schema-check:新增 `action_hint_columns` 检查。
|
||
|
||
兼容写入策略:
|
||
|
||
- 新客户端提交 `action_hint` 时,写入 `contracts.action_hint`,并同步刷新旧 `contracts.next_action` 兼容缓存。
|
||
- 旧客户端只提交 `next_action` 时,同步写入 `contracts.action_hint`。
|
||
- `next_actions` 仍保持旧行为,本片不把人工提示转成按钮列表。
|
||
|
||
本片刻意没有做:
|
||
|
||
- 没有删除 `next_action / next_actions` 旧列。
|
||
- 没有改变合同列表、详情、workspace、搜索的响应字段名。
|
||
- 没有把 `action_hint` 加入 API 输出模型。
|
||
- 没有改前端编辑面板文案和字段名。
|
||
- 没有改变 `ContractActionContext` 派生优先级。
|
||
|
||
验证:
|
||
|
||
```powershell
|
||
python -m compileall -q yuqei-contract-platform\services\contract-api\src\yuqei_contract_api
|
||
python -m pytest yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_contract_update_accepts_action_hint_and_legacy_next_action yuqei-contract-platform\services\contract-api\tests\test_health.py::test_runtime_schema_check_warns_for_local_sqlite_auto_created_schema yuqei-contract-platform\services\contract-api\tests\test_health.py::test_runtime_schema_check_errors_for_missing_core_tables yuqei-contract-platform\services\contract-api\tests\test_health.py::test_runtime_schema_check_errors_when_action_hint_column_is_missing -q
|
||
python -m pytest yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py yuqei-contract-platform\services\contract-api\tests\test_health.py -q
|
||
python -m pytest yuqei-contract-platform\services\contract-api\tests\test_display_cache_governance.py -q
|
||
python -m alembic -c alembic.ini heads
|
||
$env:CONTRACT_API_DATABASE_URL='sqlite+pysqlite:///D:/yuqei-project/ai-contract-platform/.tmp-contract-action-hint-alembic.sqlite3'; python -m alembic -c alembic.ini upgrade head
|
||
```
|
||
|
||
结果:
|
||
|
||
- Python compile 通过。
|
||
- Contract API 工作流、health/schema-check、display cache governance 测试通过。
|
||
- Alembic head 为 `20260630_0022`。
|
||
- Alembic base -> head 临时 SQLite 迁移通过。
|
||
|
||
下一片建议:
|
||
|
||
- Slice 3.5.3-c:将 `action_hint` 接入 `ContractActionContext` 和 `derive_contract_display(...)`。
|
||
- 派生优先级仍按设计保持:结构化流程上下文 > `action_hint` > 状态默认动作。
|
||
|
||
## Slice 3.5.3-c 实施记录
|
||
|
||
本片已将 `action_hint` 接入只读派生链路,继续保持旧 API 响应字段兼容。
|
||
|
||
新增内容:
|
||
|
||
- `ContractActionContext.action_hint`。
|
||
- SQLAlchemy action context loader 从 `ContractModel.action_hint` 读取人工跟进提示。
|
||
- `derive_contract_display(...)` 在没有高优先级结构化动作时使用 `action_hint` 作为 `next_action`。
|
||
|
||
派生优先级:
|
||
|
||
1. 条款修复、审查任务、待审批步骤、履约任务等结构化上下文。
|
||
2. `action_hint` 人工跟进提示。
|
||
3. 状态默认动作。
|
||
|
||
关键语义:
|
||
|
||
- `action_hint` 只影响 `next_action` 的展示文案。
|
||
- `next_actions` 仍保持当前状态默认按钮列表,不把人工提示当成动作按钮。
|
||
- 审批、审查、条款修复、履约等系统动作会覆盖 `action_hint`。
|
||
|
||
本片刻意没有做:
|
||
|
||
- 没有把 `action_hint` 加入 API 输出模型。
|
||
- 没有改前端编辑面板字段名或文案。
|
||
- 没有删除或停写旧 `next_action / next_actions` 兼容列。
|
||
- 没有执行远端 smoke 部署。
|
||
|
||
验证:
|
||
|
||
```powershell
|
||
python -m compileall -q yuqei-contract-platform\services\contract-api\src\yuqei_contract_api
|
||
python -m pytest yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_contract_update_accepts_action_hint_and_legacy_next_action yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_contract_action_hint_derives_next_action_without_overriding_buttons yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_structured_action_context_overrides_action_hint -q
|
||
python -m pytest yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py yuqei-contract-platform\services\contract-api\tests\test_health.py -q
|
||
python -m pytest yuqei-contract-platform\services\contract-api\tests\test_display_cache_governance.py -q
|
||
python -m alembic -c alembic.ini heads
|
||
```
|
||
|
||
结果:
|
||
|
||
- Python compile 通过。
|
||
- 新增 `action_hint` 派生优先级回归通过。
|
||
- Contract API 工作流、health/schema-check、display cache governance 测试通过。
|
||
- Alembic head 仍为 `20260630_0022`。
|
||
|
||
下一片建议:
|
||
|
||
- Slice 3.5.3-d:前端编辑面板改名,将 `下一步操作` 输入改为 `人工跟进提示`,提交字段从 `next_action` 改为 `action_hint`。
|
||
- 后端仍继续兼容旧 `next_action` PATCH,方便灰度和回滚。
|
||
|
||
## Slice 3.5.3-d 实施记录
|
||
|
||
本片已完成前端人工编辑入口的语义切换。
|
||
|
||
新增内容:
|
||
|
||
- `ContractDetail.action_hint` 可选响应字段。
|
||
- 合同详情 mapper 返回 `row.action_hint`。
|
||
- 前端 `ContractDetail` TypeScript 类型新增 `action_hint?: string | null`。
|
||
- 合同编辑面板标签从 `下一步操作` 改为 `人工跟进提示`。
|
||
- 合同编辑面板提交字段从 `next_action` 改为 `action_hint`。
|
||
- 表单默认值优先使用 `contract.action_hint`,旧后端或旧数据场景下兜底使用 `contract.next_action`。
|
||
|
||
兼容策略:
|
||
|
||
- 合同详情主展示仍继续使用 `next_action`。
|
||
- 合同列表、workspace、搜索等响应字段不变。
|
||
- 后端仍继续兼容旧客户端提交 `next_action`。
|
||
|
||
本片刻意没有做:
|
||
|
||
- 没有删除 `next_action / next_actions`。
|
||
- 没有停止后端旧写路径的兼容缓存。
|
||
- 没有改合同详情主动作卡片文案。
|
||
- 没有执行远端 smoke 部署。
|
||
|
||
验证:
|
||
|
||
```powershell
|
||
python -m compileall -q yuqei-contract-platform\services\contract-api\src\yuqei_contract_api
|
||
python -m pytest yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_contract_update_accepts_action_hint_and_legacy_next_action yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_contract_action_hint_derives_next_action_without_overriding_buttons yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_structured_action_context_overrides_action_hint -q
|
||
npm run typecheck
|
||
python -m pytest yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py yuqei-contract-platform\services\contract-api\tests\test_health.py -q
|
||
python -m pytest yuqei-contract-platform\services\contract-api\tests\test_display_cache_governance.py -q
|
||
python -m alembic -c alembic.ini heads
|
||
```
|
||
|
||
结果:
|
||
|
||
- Python compile 通过。
|
||
- `action_hint` 兼容写入和派生优先级回归通过。
|
||
- Contract Web typecheck 通过。
|
||
- Contract API 工作流、health/schema-check、display cache governance 测试通过。
|
||
- Alembic head 仍为 `20260630_0022`。
|
||
|
||
下一片建议:
|
||
|
||
- Slice 3.5.3-e:逐步停写旧 `contracts.next_action / next_actions` 兼容列,优先处理文件上传、审查任务、条款修复、审批流、归档流程这些仍手写旧列的路径。
|
||
- 停写时继续保留 API 响应字段,由派生层输出。
|
||
|
||
## Slice 3.5.3-e 实施记录
|
||
|
||
本片已将生产 SQLAlchemy 写路径中的旧 `contracts.next_action / next_actions` 手写逻辑收敛到统一派生兼容缓存 helper。
|
||
|
||
新增内容:
|
||
|
||
- `sync_contract_action_display_cache(session, row)`。
|
||
- helper 基于 `derive_contract_display(...)` 和 `ContractActionContext` 派生:
|
||
- `status_label`
|
||
- `status_tone`
|
||
- `next_action`
|
||
- `next_actions`
|
||
|
||
已替换的生产 SQLAlchemy 写路径:
|
||
|
||
- 审批状态流:提交审批、退回、重提、审批通过、归档等统一状态流。
|
||
- 发起审查。
|
||
- 审查任务重新排队。
|
||
- 审查任务完成。
|
||
- 审查任务失败。
|
||
- 上传合同文件。
|
||
- 应用审查推荐条款。
|
||
|
||
关键语义:
|
||
|
||
- 旧兼容列仍保留,但不再由这些 orchestration 分散手写文案。
|
||
- 文件上传产生的“可发起法律审查”被迁入 `action_hint`,再由派生层同步到旧兼容列。
|
||
- 条款修复先更新 review task 的风险项状态,再同步旧兼容列,确保能派生出“复核已应用的条款修订”。
|
||
- 状态流先写审批实例/步骤/动作,再同步旧兼容列,确保能派生出“等待审批人审批”。
|
||
|
||
本片刻意没有做:
|
||
|
||
- 没有删除 `contracts.next_action / next_actions`。
|
||
- 没有移除方法签名中仍用于旧兼容调用面的 `next_action / next_actions` 参数。
|
||
- 没有改 in-memory demo 仓储。
|
||
- 没有升级 `display_cache_governance` 为完整结构化上下文检查。
|
||
- 没有执行远端 smoke 部署。
|
||
|
||
验证:
|
||
|
||
```powershell
|
||
python -m compileall -q yuqei-contract-platform\services\contract-api\src\yuqei_contract_api
|
||
python -m pytest yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_contract_status_display_cache_is_derived_on_write_paths yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_contract_action_display_cache_is_derived_for_review_write_paths yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_upload_file_and_start_review_closes_review_entry_flow yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_structured_action_context_overrides_action_hint -q
|
||
python -m pytest yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py yuqei-contract-platform\services\contract-api\tests\test_health.py -q
|
||
python -m pytest yuqei-contract-platform\services\contract-api\tests\test_display_cache_governance.py -q
|
||
npm run typecheck
|
||
python -m alembic -c alembic.ini heads
|
||
```
|
||
|
||
结果:
|
||
|
||
- Python compile 通过。
|
||
- 新增/扩展 action display cache 回归通过。
|
||
- Contract API 工作流、health/schema-check、display cache governance 测试通过。
|
||
- Contract Web typecheck 通过。
|
||
- Alembic head 仍为 `20260630_0022`。
|
||
|
||
下一片建议:
|
||
|
||
- 继续做 Slice 3.5.3-f:清理旧方法签名和兼容参数,将 `_transition_contract(...)`、`ContractAuditRepository.transition_contract(...)` 中的 `next_action / next_actions` 参数下沉移除或标记 deprecated。
|
||
- 或者先做远端 `192.168.3.90` smoke 部署验证:跑 migration 到 `20260630_0022`,复跑 `/api/v1/runtime/schema-check`,抽样合同创建、编辑人工跟进提示、提交审批、退回、重提、发起审查、文件上传、条款修复。
|
||
|
||
## Slice 3.5.3-f 实施记录
|
||
|
||
本片已完成生产 SQLAlchemy 状态流内部签名收口:状态迁移不再接收旧 `next_action / next_actions` 展示参数。
|
||
|
||
调整范围:
|
||
|
||
- `ContractAuditRepository.transition_contract(...)`
|
||
- `ContractAuditRepository.transition_contract_in_session(...)`
|
||
- `SqlAlchemyTransitionOrchestration.transition_contract(...)`
|
||
- `SqlAlchemyContractRepository._transition_contract(...)`
|
||
- 审批状态流调用:提交审批、退回、重提、审批通过。
|
||
- 归档状态流调用。
|
||
|
||
关键语义:
|
||
|
||
- 状态迁移只接收状态事实、允许状态集合、timeline action 和操作者请求。
|
||
- 旧 `contracts.next_action / contracts.next_actions` 列仍保留。
|
||
- 旧兼容列仍由 `sync_contract_action_display_cache(session, row)` 基于 `derive_contract_display(...)` 统一同步。
|
||
- API 响应继续返回派生后的 `next_action / next_actions`。
|
||
- 前端和旧客户端 PATCH 兼容策略不变。
|
||
|
||
本片刻意没有做:
|
||
|
||
- 没有删除旧数据库列。
|
||
- 没有移除 API DTO 中的 `next_action / next_actions` 兼容字段。
|
||
- 没有改 `InMemoryContractRepository` 的 demo/test 内部 transition 参数,避免把生产 SQLAlchemy 收口扩大成 demo 仓储重写。
|
||
- 没有进入后续 cleanup migration。
|
||
|
||
验证:
|
||
|
||
```powershell
|
||
python -m compileall -q yuqei-contract-platform\services\contract-api\src\yuqei_contract_api
|
||
python -m pytest yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_submit_reject_resubmit_and_approve_workflow yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_contract_support_operations_persist_with_sqlalchemy_repository yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_structured_action_context_overrides_action_hint -q
|
||
```
|
||
|
||
结果:
|
||
|
||
- Python compile 通过。
|
||
- 审批退回/重提/通过、归档支撑链路、结构化动作覆盖 `action_hint` 回归通过。
|
||
|
||
下一片建议:
|
||
|
||
- 继续把生产写路径里剩余的旧展示字段入口收窄到 `ContractUpdateRequest` 兼容层和 seed/demo 初始化层,优先审计 `persistence/contract_core.py` 的更新路径与 `seed_data.py` 的历史默认值;仍不要删列。
|
||
|
||
## Slice 3.5.3-g 实施记录
|
||
|
||
本片已完成 `persistence/contract_core.py` 更新兼容层和 `seed_data.py` 历史默认展示字段审计。
|
||
|
||
调整范围:
|
||
|
||
- `ContractCoreRepository.update_contract(...)`
|
||
- `normalize_contract_update_fields(...)`
|
||
- `ContractCoreRepository.add_contract_in_session(...)`
|
||
- `contract_create_data_from_detail(...)`
|
||
- `seed_data.py` 三份 demo 合同的人工跟进提示字段
|
||
|
||
关键语义:
|
||
|
||
- `ContractUpdateRequest.action_hint` 继续作为人工跟进提示事实字段。
|
||
- 旧 `ContractUpdateRequest.next_action` 继续兼容接收,但会被规范化为 `action_hint`,不再直接写入 `contracts.next_action`。
|
||
- 旧 `ContractUpdateRequest.next_actions` 继续兼容接收但不再写入 `contracts.next_actions`,按钮列表仍由派生层输出。
|
||
- 合同创建和 seed 初始化后统一调用 `sync_contract_action_display_cache(session, row)`,旧兼容列只保存派生结果。
|
||
- V1/V2 demo 合同里的人工提示迁入 `action_hint`,`next_action / next_actions` 仅作为派生兼容缓存。
|
||
|
||
本片刻意没有做:
|
||
|
||
- 没有删除旧数据库列。
|
||
- 没有移除 API DTO 中的 `next_action / next_actions` 兼容字段。
|
||
- 没有更改 `InMemoryContractRepository` 的 demo/test 内部写法。
|
||
- 没有升级 `display_cache_governance` 为完整结构化上下文检查。
|
||
|
||
验证:
|
||
|
||
```powershell
|
||
python -m compileall -q yuqei-contract-platform\services\contract-api\src\yuqei_contract_api
|
||
python -m pytest yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_create_and_update_contract_draft_persists_to_repository yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_contract_update_accepts_action_hint_and_legacy_next_action yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_contract_action_hint_derives_next_action_without_overriding_buttons yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_sqlalchemy_repository_persists_contracts_and_approval_timeline -q
|
||
```
|
||
|
||
结果:
|
||
|
||
- Python compile 通过。
|
||
- 旧 `next_action` PATCH 兼容到 `action_hint` 通过。
|
||
- 旧 `next_actions` PATCH 不再覆盖派生按钮列表,回归通过。
|
||
- seed demo 合同 `action_hint` 持久化与派生展示回归通过。
|
||
|
||
下一片建议:
|
||
|
||
- 继续审计 `display_cache_governance` 与 search 文档生成是否要接入完整 `ContractActionContext`。当前仍先保持只读轻量检查,不急于删列。
|