a3bb78e06b
Security Quality Gate / npm audit, Bandit, pip-audit, detect-secrets (pull_request) Failing after 16m35s
147 lines
5.6 KiB
Markdown
147 lines
5.6 KiB
Markdown
# AI 合同平台 V2 Phase 3 action_hint 前端与接口语义收敛
|
||
|
||
## 背景
|
||
|
||
上一片已停写旧 `contracts.next_action / contracts.next_actions` 生产写路径,并确认 API 响应继续由完整 `ContractActionContext` 派生。
|
||
|
||
本片继续收敛产品语义:
|
||
|
||
- `action_hint` 是人工填写的跟进提示事实字段。
|
||
- `next_action / next_actions` 是系统派生的展示字段和兼容响应字段。
|
||
- 旧 `next_action` 写入入口在观察窗口通过后已进入 rejected 阶段,不再规范化到 `action_hint`。
|
||
|
||
## 本次调整
|
||
|
||
### 前端编辑入口
|
||
|
||
合同详情编辑面板中的“人工跟进提示”输入框现在只使用:
|
||
|
||
- `contract.action_hint`
|
||
|
||
不再 fallback 到:
|
||
|
||
- `contract.next_action`
|
||
|
||
原因:
|
||
|
||
- `next_action` 现在是系统派生动作,例如“等待审批人审批”“处理审查风险并应用推荐条款”。
|
||
- 如果编辑表单默认带入派生动作,用户保存时会把系统动作误存成人工提示。
|
||
|
||
同时,编辑面板 Props 已移除 `next_action` 依赖,后续 TypeScript 会阻止该组件重新把派生动作当作人工提示默认值。
|
||
|
||
前端占位文案也同步收敛为“人工补充的跟进提示,不会覆盖系统下一步操作”,避免把 `action_hint` 理解成可手工改写系统派生动作。
|
||
|
||
### API / OpenAPI 语义
|
||
|
||
后端 DTO 和 OpenAPI 已补充字段说明:
|
||
|
||
- `ContractUpdateRequest.action_hint`
|
||
- 支持写入。
|
||
- 表示人工跟进提示。
|
||
- `ContractUpdateRequest.next_action`
|
||
- deprecated。
|
||
- 不再接受写入。
|
||
- 客户端应改用 `action_hint`。
|
||
- `ContractUpdateRequest.next_actions`
|
||
- deprecated。
|
||
- 不再接受写入。
|
||
- 响应按钮列表由 `ContractActionContext` 派生。
|
||
- `ContractListItem.next_action`
|
||
- 响应字段保留。
|
||
- 来源是派生展示动作,不是持久化人工输入。
|
||
- `ContractDetail.next_actions`
|
||
- 响应字段保留。
|
||
- 来源是派生动作按钮。
|
||
|
||
## 没有做
|
||
|
||
- 未删除旧数据库列。
|
||
- 未移除响应字段 `next_action / next_actions`。
|
||
- 未移除旧 `next_action / next_actions` 请求字段定义,但写路径已拒绝旧字段。
|
||
- 未进入 cleanup migration。
|
||
|
||
## 验证
|
||
|
||
```powershell
|
||
python -m py_compile yuqei-contract-platform\services\contract-api\src\yuqei_contract_api\domain.py
|
||
|
||
python -m pytest `
|
||
yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_contract_update_accepts_action_hint_and_rejects_legacy_next_action `
|
||
yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_contract_action_hint_derives_next_action_without_overriding_buttons `
|
||
-q
|
||
|
||
npm --workspace @yuqei/contract-web run typecheck
|
||
```
|
||
|
||
结果:
|
||
|
||
- `py_compile`:通过。
|
||
- 后端 action_hint 回归:2 passed。
|
||
- contract-web typecheck:通过。
|
||
|
||
## 远端 smoke 验证
|
||
|
||
环境:
|
||
|
||
- 宿主机:`192.168.3.90`
|
||
- compose project:`yuqei-contract-v2-smoke`
|
||
- Contract API:`http://127.0.0.1:18100`
|
||
- Contract Web:`http://127.0.0.1:13000`
|
||
- PostgreSQL database:`yuqei_contract`
|
||
|
||
验证结果:
|
||
|
||
- `contract-api` / `contract-web` 容器均为 healthy。
|
||
- `/api/v1/runtime/schema-check` 返回 `status=ok`。
|
||
- `display_cache_consistency`:
|
||
- `checked_rows=12020`
|
||
- `mismatch_count=0`
|
||
- `checked_fields=status_label,status_tone`
|
||
- `retained_compat_fields=next_action,next_actions`
|
||
- `display_cache_cleanup_prestate`:
|
||
- `status=ok`
|
||
- `legacy_columns_retained=true`
|
||
- `display_cache_consistent=true`
|
||
- `next_step=stop_legacy_display_cache_writes_before_drop_columns`
|
||
- 旧 `next_action` PATCH 抽样:
|
||
- smoke 合同:`contract-19740a3a80f2`
|
||
- 请求字段:`next_action=legacy-next-action-alias-to-action-hint`
|
||
- 响应字段:`action_hint=legacy-next-action-alias-to-action-hint`
|
||
- 响应字段:`next_action=legacy-next-action-alias-to-action-hint`
|
||
- 数据库字段:`action_hint=legacy-next-action-alias-to-action-hint`
|
||
- 数据库旧缓存字段:`next_action=''`
|
||
- 数据库旧缓存字段:`next_actions=[]`
|
||
- 合同详情页面:`/contracts/contract-19740a3a80f2` 返回 HTTP 200。
|
||
- 最近 10 分钟 `Contract display cache mismatch` 日志计数为 0。
|
||
- 前端文案收敛后已重新构建并部署 `contract-web`:
|
||
- Next build:通过。
|
||
- 生产构建内置 TypeScript:通过。
|
||
- `contract-web` 容器:healthy。
|
||
- 合同详情页面:`/contracts/contract-19740a3a80f2` 返回 HTTP 200。
|
||
|
||
## cleanup migration 评审结论
|
||
|
||
本轮不进入删列或移除响应字段的 cleanup migration。
|
||
|
||
理由:
|
||
|
||
- `next_action / next_actions` 仍是对外响应兼容字段,前端和旧调用方可能仍读取。
|
||
- 旧 `next_action` 写入口已经明确降级为 `action_hint` alias,保留它不会再污染旧缓存列。
|
||
- schema-check 已把检查口径收敛到 `status_label/status_tone`,并明确标注旧动作列只作为兼容保留。
|
||
- 后续真正删列前,需要先观测是否仍有外部客户端提交旧字段,并决定是否增加 alias 使用审计。
|
||
- 旧 alias 使用观测已进入独立收口文档:`V2-phase3-deprecated-next-action-alias-observability-2026-07-01.md`。
|
||
|
||
## 当前结论
|
||
|
||
前端和接口语义已收敛为:
|
||
|
||
- 人工输入只走 `action_hint`。
|
||
- 系统展示只读 `next_action / next_actions` 派生响应。
|
||
- 旧写入字段已经拒绝,不再作为兼容入口。
|
||
|
||
下一步仍建议先保持兼容观测,不直接删列。若继续推进 cleanup,应先检查:
|
||
|
||
- 是否还有外部客户端提交 `next_action / next_actions`。
|
||
- 是否需要在日志或审计中记录旧 alias 的使用次数。
|
||
- 是否需要在后续版本中把 OpenAPI deprecated 字段推进到移除计划。
|