a3bb78e06b
Security Quality Gate / npm audit, Bandit, pip-audit, detect-secrets (pull_request) Failing after 16m35s
176 lines
5.1 KiB
Markdown
176 lines
5.1 KiB
Markdown
# AI 合同平台 V2 Phase 3 停止旧 next_action 列读路径
|
||
|
||
## 背景
|
||
|
||
Slice A 已经完成:
|
||
|
||
- `action_hint` 是唯一支持的人工写入字段。
|
||
- 旧 `next_action / next_actions` PATCH 输入返回 `422`。
|
||
- 旧输入仍记录 metrics,状态为 `compatibility_status=rejected`。
|
||
- 数据库旧列仍保留,未删列。
|
||
|
||
本片进入 Slice B:停止 response/search/display 读路径读取旧列。
|
||
|
||
## 本次调整
|
||
|
||
### 合同响应
|
||
|
||
合同列表和详情 mapper 不再把以下旧列传入 `derive_contract_display(...)`:
|
||
|
||
- `contracts.next_action`
|
||
- `contracts.next_actions`
|
||
|
||
响应字段仍保留:
|
||
|
||
- `ContractListItem.next_action`
|
||
- `ContractDetail.next_actions`
|
||
|
||
但来源只包括:
|
||
|
||
- 合同状态默认动作。
|
||
- 审批实例/步骤。
|
||
- 审查任务和结构化风险。
|
||
- 履约任务。
|
||
- 条款修复状态。
|
||
- `action_hint`。
|
||
|
||
### 统一搜索
|
||
|
||
合同搜索文档生成不再读取旧动作列。
|
||
|
||
搜索摘要和搜索文本继续使用派生动作:
|
||
|
||
- `summary=display.next_action`
|
||
- `fields` 中的下一步动作来自派生层。
|
||
|
||
### display cache governance
|
||
|
||
`display_cache_governance` 继续检查旧列是否存在,但不再读取旧列值:
|
||
|
||
- 不再 select `contracts.next_action`。
|
||
- 不再 select `contracts.next_actions`。
|
||
- 不再把旧动作列传给 `derive_contract_display(...)`。
|
||
|
||
一致性检查仍只覆盖:
|
||
|
||
- `status_label`
|
||
- `status_tone`
|
||
|
||
### schema-check 语义
|
||
|
||
schema-check 文案已从 “read-derived” 更新为:
|
||
|
||
- 旧动作列仍保留。
|
||
- 旧动作列不再被读路径使用。
|
||
- 下一步是准备 legacy action column cleanup migration。
|
||
|
||
## 不做
|
||
|
||
本片仍不做:
|
||
|
||
- 不删除 `contracts.next_action`。
|
||
- 不删除 `contracts.next_actions`。
|
||
- 不删除响应字段 `next_action / next_actions`。
|
||
- 不改 `derive_contract_display(...)` 函数签名。
|
||
|
||
保留函数签名是为了降低拆分风险;生产 mapper/search/governance 已不再传旧列。
|
||
|
||
## 验证
|
||
|
||
新增回归:
|
||
|
||
```powershell
|
||
python -m pytest `
|
||
yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_contract_display_and_search_ignore_legacy_action_columns `
|
||
yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_search_document_generation_uses_contract_action_context `
|
||
yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_contract_action_hint_derives_next_action_without_overriding_buttons `
|
||
-q
|
||
```
|
||
|
||
结果:
|
||
|
||
- 3 passed。
|
||
|
||
治理和 schema-check 回归:
|
||
|
||
```powershell
|
||
python -m pytest `
|
||
yuqei-contract-platform\services\contract-api\tests\test_display_cache_governance.py `
|
||
yuqei-contract-platform\services\contract-api\tests\test_health.py `
|
||
-q
|
||
```
|
||
|
||
结果:
|
||
|
||
- 15 passed。
|
||
|
||
编译:
|
||
|
||
```powershell
|
||
python -m py_compile `
|
||
yuqei-contract-platform\services\contract-api\src\yuqei_contract_api\workflow_helpers.py `
|
||
yuqei-contract-platform\services\contract-api\src\yuqei_contract_api\persistence\search.py `
|
||
yuqei-contract-platform\services\contract-api\src\yuqei_contract_api\display_cache_governance.py `
|
||
yuqei-contract-platform\services\contract-api\src\yuqei_contract_api\schema_check.py
|
||
```
|
||
|
||
结果:
|
||
|
||
- 通过。
|
||
|
||
## 当前结论
|
||
|
||
旧动作列已经不再影响合同响应、统一搜索和 display cache governance。
|
||
|
||
## 远端 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_consistency.unused_compat_fields=next_action,next_actions`。
|
||
- `display_cache_cleanup_prestate.next_step=prepare_legacy_action_column_cleanup_migration`。
|
||
|
||
旧列脏值抽样:
|
||
|
||
- smoke 合同:`contract-f5f9df91a450`
|
||
- 人工写入旧列:
|
||
- `contracts.next_action=LEGACY-STORED-ACTION-MARKER-SMOKE`
|
||
- `contracts.next_actions=["LEGACY-STORED-ACTION-MARKER-SMOKE"]`
|
||
- 触发普通 PATCH 重建搜索文档。
|
||
- 合同详情:
|
||
- `contains_marker=false`
|
||
- `next_action=补充后提交审批`
|
||
- `next_actions=["编辑合同","提交审批"]`
|
||
- 搜索文档:
|
||
- `summary=补充后提交审批`
|
||
- `search_text` 不包含 `LEGACY-STORED-ACTION-MARKER-SMOKE`
|
||
- 3 秒观察窗口:
|
||
- `baseline_total=0`
|
||
- `final_total=0`
|
||
- `observed_delta=0`
|
||
- `relevant_new_count=0`
|
||
- 最近 10 分钟 `Deprecated contract update action alias used` 日志计数为 0。
|
||
- 最近 10 分钟 `Contract display cache mismatch` 日志计数为 0。
|
||
|
||
远端 smoke 结论:
|
||
|
||
- 旧动作列脏值不再影响详情响应。
|
||
- 旧动作列脏值不再影响统一搜索索引。
|
||
- schema-check 已进入删列准备语义。
|
||
|
||
下一步可以进入 Slice C 的删列前设计,建议先准备:
|
||
|
||
- Alembic 删列迁移。
|
||
- 回滚迁移:重新 add column,默认空值/空数组,不恢复旧缓存语义。
|
||
- schema-check 从 retained/unused 过渡到 removed/removable。
|
||
- Docker smoke:schema-check、合同详情、统一搜索、审批、审查、条款修复。
|