# 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、合同详情、统一搜索、审批、审查、条款修复。