Files
ai-contract-platform/project-docs/V2-phase3-next-action-action-hint-design-2026-06-30.md
T
yuqei a3bb78e06b
Security Quality Gate / npm audit, Bandit, pip-audit, detect-secrets (pull_request) Failing after 16m35s
release: freeze V2 release candidate
2026-07-12 15:32:24 +08:00

656 lines
28 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`。当前仍先保持只读轻量检查,不急于删列。