a3bb78e06b
Security Quality Gate / npm audit, Bandit, pip-audit, detect-secrets (pull_request) Failing after 16m35s
5.6 KiB
5.6 KiB
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。
验证
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=12020mismatch_count=0checked_fields=status_label,status_toneretained_compat_fields=next_action,next_actions
display_cache_cleanup_prestate:status=oklegacy_columns_retained=truedisplay_cache_consistent=truenext_step=stop_legacy_display_cache_writes_before_drop_columns
- 旧
next_actionPATCH 抽样:- 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=[]
- smoke 合同:
- 合同详情页面:
/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_hintalias,保留它不会再污染旧缓存列。 - 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 字段推进到移除计划。