Files
ai-contract-platform/project-docs/V2-phase3-stop-legacy-action-column-read-path-2026-07-02.md
T
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

176 lines
5.1 KiB
Markdown
Raw 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 列读路径
## 背景
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、合同详情、统一搜索、审批、审查、条款修复。