a3bb78e06b
Security Quality Gate / npm audit, Bandit, pip-audit, detect-secrets (pull_request) Failing after 16m35s
4.1 KiB
4.1 KiB
AI 合同平台 V2 Phase 3 拒绝旧 next_action 输入
背景
30 分钟 smoke 观察窗口显示旧 next_action / next_actions alias 没有新增调用:
baseline_total=1final_total=1observed_delta=0relevant_new_count=0
因此进入 cleanup 的 Slice A:先收紧接口输入,不动数据库结构。
本次调整
PATCH 输入收紧
合同更新接口:
PATCH /api/v1/contracts/{contract_id}
现在行为:
action_hint:继续支持,作为人工跟进提示唯一写入字段。next_action:拒绝,返回422。next_actions:拒绝,返回422。
错误响应示例:
{
"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_actionfields=["next_action","next_actions"]target_field=action_hintcompatibility_status=rejected
观测记录仍不保存旧字段文本值。
不动数据库结构
本片没有执行 Alembic migration。
继续保留:
contracts.next_actioncontracts.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_hintinstead。
验证
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_hintPATCH 返回 200。next_action / next_actionsPATCH 返回 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_hintPATCH:返回 200。- 旧
next_action / next_actionsPATCH:返回 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_actioncompatibility_status=rejectedfields=["next_action","next_actions"]trace_id=trace-reject-legacy-alias-smoketenant_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 和读路径都不再依赖旧列。