Files
ai-contract-platform/project-docs/V2-phase3-reject-legacy-next-action-input-2026-07-02.md
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

143 lines
4.1 KiB
Markdown
Raw Permalink 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 输入
## 背景
30 分钟 smoke 观察窗口显示旧 `next_action / next_actions` alias 没有新增调用:
- `baseline_total=1`
- `final_total=1`
- `observed_delta=0`
- `relevant_new_count=0`
因此进入 cleanup 的 Slice A:先收紧接口输入,不动数据库结构。
## 本次调整
### PATCH 输入收紧
合同更新接口:
```text
PATCH /api/v1/contracts/{contract_id}
```
现在行为:
- `action_hint`:继续支持,作为人工跟进提示唯一写入字段。
- `next_action`:拒绝,返回 `422`。
- `next_actions`:拒绝,返回 `422`。
错误响应示例:
```json
{
"detail": {
"code": "deprecated_contract_update_action_alias",
"message": "Deprecated contract action fields are no longer accepted. Use action_hint for manual follow-up text.",
"fields": ["next_action", "next_actions"],
"replacement_field": "action_hint"
}
}
```
### 观测保留
旧字段被拒绝时仍会写入观测窗口:
- `alias_group=contract_update_action`
- `fields=["next_action","next_actions"]`
- `target_field=action_hint`
- `compatibility_status=rejected`
观测记录仍不保存旧字段文本值。
### 不动数据库结构
本片没有执行 Alembic migration。
继续保留:
- `contracts.next_action`
- `contracts.next_actions`
原因:
- 响应字段 `next_action / next_actions` 仍由派生层对外保留。
- 部分 read/search/schema-check 路径仍把旧列作为 retained compatibility columns。
- 真正删列应放到后续 Slice C。
## OpenAPI
`ContractUpdateRequest.next_action / next_actions` 描述已更新为:
- deprecated。
- no longer accepted by write paths。
- use `action_hint` instead。
## 验证
```powershell
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_update_legacy_action_alias_usage_is_observable `
-q
```
预期:
- `action_hint` PATCH 返回 200。
- `next_action / next_actions` PATCH 返回 422。
- 旧字段文本值不会进入错误响应或 metrics。
- metrics 中 `compatibility_status=rejected`。
本地结果:
- 聚焦回归:2 passed。
- `py_compile`:通过。
- `test_health.py` + `test_monitoring.py`:17 passed。
- OpenAPI YAML 解析:`3.1.0 / 51 paths`。
## 远端 smoke 验证
环境:
- 宿主机:`192.168.3.90`
- Contract API:`http://127.0.0.1:18100`
- compose project:`yuqei-contract-v2-smoke`
部署结果:
- `contract-api` 已重建并启动。
- `contract-api` 容器状态:healthy。
- `/api/v1/runtime/schema-check` 返回 `status=ok`。
- `display_cache_consistency.mismatch_count=0`。
- `display_cache_cleanup_prestate.status=ok`。
- 旧列仍保留:`retained_compat_fields=next_action,next_actions`。
接口抽样:
- smoke 合同:`contract-e51a2edfa899`
- `action_hint` PATCH:返回 200。
- 旧 `next_action / next_actions` PATCH:返回 422。
- 错误 code:`deprecated_contract_update_action_alias`。
- 合同详情仍保持:`action_hint=supported-action-hint-smoke`。
- 响应派生字段仍返回:`next_action=supported-action-hint-smoke`、`next_actions=["编辑合同","提交审批"]`。
- metrics 记录:
- `alias_group=contract_update_action`
- `compatibility_status=rejected`
- `fields=["next_action","next_actions"]`
- `trace_id=trace-reject-legacy-alias-smoke`
- `tenant_id=tenant-reject-legacy-alias-smoke`
- 旧字段文本值未进入错误响应或 metrics。
- 最近 10 分钟 `Deprecated contract update action alias used` 日志计数为 1。
- 最近 10 分钟 `Contract display cache mismatch` 日志计数为 0。
- 3 秒观察窗口通过:`baseline_total=1`、`final_total=1`、`observed_delta=0`、`relevant_new_count=0`。
## 下一步
后续建议:
- 再跑一个 30 分钟观察窗口,确认没有真实旧客户端继续调用。
- 如果窗口仍为 0,进入 Slice B:停止旧列读取。
- 继续暂缓 Slice C 数据库删列,直到 schema-check 和读路径都不再依赖旧列。