9.8 KiB
AI 合同平台 V2 Phase 3 Slice 3.4 UI 展示字段派生设计评审
背景
本次继续对齐《AI 合同平台 V2 下一阶段开发优化方案》和 Phase 3 schema 硬化设计评审。
Slice 3.1 已完成 contract_versions。
Slice 3.2 已完成正式审批模型。
Slice 3.3 已完成治理字段和软删除,并已在权威 V2 smoke PostgreSQL/Docker 环境验证到 Alembic head 20260630_0021。
Slice 3.4 的目标不是新增业务页面,也不是立即删除数据库字段,而是把 status_label、status_tone、next_action、next_actions 这类 UI 展示字段逐步从事实表中迁出,转为 domain/serializer 派生。
当前问题
contracts 表仍保存以下 UI 展示字段:
status_labelstatus_tonenext_actionnext_actions
这些字段目前还被以下路径使用:
- 合同列表和合同详情响应。
- 工作台待办卡片。
- dashboard 状态统计标签。
- 统一搜索文档的
status_label、summary和search_text。 - 审批、审查、文件上传、条款修复等状态流副作用。
- 前端 TypeScript service 和 OpenAPI schema 兼容字段。
直接删除字段风险较高,因为前端和搜索仍需要这些响应字段。
设计原则
- 不在 Slice 3.4 第一片删除数据库列。
- 不改变现有 API 响应字段名。
- 不改变前端读取字段方式。
- 先把派生规则集中到 domain/serializer 层。
- 旧字段暂时保留为兼容缓存,用于灰度和回滚。
- 当数据库缓存值与派生值不一致时,响应层优先使用派生值,并记录 warning。
status_label和status_tone可以直接从status强派生。next_action和next_actions需要分阶段迁出,因为当前它们既包含状态默认动作,也包含少量合同上下文提示。
第一片实现边界
新增 contract_display.py,集中维护:
ContractDisplayFieldsCONTRACT_DISPLAY_BY_STATUSderive_contract_displaystatus_label_for_statusstatus_tone_for_status
第一片 read-switch:
- 合同列表响应:
status_label、status_tone优先派生。 - 合同详情响应:
status_label、status_tone优先派生。 - 合同详情响应:
next_action、next_actions对已知旧状态默认文案做派生修正。 - 统一搜索文档:合同类文档的
status_label、summary、search_text使用派生结果。 - in-memory dashboard:状态标签从
status派生。
第一片暂不做:
- 不删除
contracts.status_label等旧列。 - 不移除写路径中的旧字段写入。
- 不修改 OpenAPI 字段。
- 不修改前端字段名。
- 不把所有合同特定
next_action强制覆盖成状态默认值。
next_action 分阶段策略
next_action 当前有两类含义:
- 状态默认动作,例如“审批人处理”“修改后重新提交”“准备签署与归档”。
- 业务上下文提示,例如“法务确认付款和验收条款”“补充租赁期限后提交”“跟踪履约节点”。
第一片只覆盖明显属于旧状态默认文案、且与当前 status 不一致的缓存值。
后续要把 next_action 完全派生,需要先从结构化事实中提取上下文:
- 审批实例和待办步骤。
- 最新审查任务状态。
- 未完成义务任务。
- 条款修复动作。
- 合同版本/草稿编辑状态。
验收标准
第一片验收:
- 当数据库中
status_label/status_tone与status不一致时,合同列表和详情响应返回派生值。 - 当数据库中
next_action/next_actions是已知旧状态默认文案且与当前status不一致时,合同详情响应返回派生默认动作。 - 合同搜索文档重建后使用派生的
status_label。 - 现有合同工作流测试继续通过。
后续完整验收:
- 合同列表、详情、搜索、工作台展示不依赖手工维护 UI 文案。
- 数据库字段表达业务事实,UI 文案集中在代码映射层。
- PostgreSQL smoke 环境中搜索重建、合同列表、详情、workspace 抽样均通过。
回滚策略
第一片只新增集中派生层并切换响应读取,不删除旧列。
如出现前端展示异常,可以回滚 mapper/search 对 derive_contract_display 的调用,数据库旧字段仍可继续支撑响应。
后续拆分建议
- 权威 V2 smoke PostgreSQL 环境复跑合同列表、详情、搜索、workspace、runtime schema-check 抽样。
- 稳定后再评审是否进入 cleanup migration,删除或降级旧 UI 缓存列。
第二片实施记录
本次已实现 ContractActionContext,将 next_action 和 next_actions 从“状态默认 + 旧缓存兼容”推进到“状态 + 结构化上下文”派生。
新增上下文来源:
- 最新审查任务状态:
queued、running、succeeded、failed。 - 审查风险项是否存在未处理风险。
- 审查风险项是否已有
repair_status=applied的条款修复记录。 - 正式审批模型中的 pending approval instance/step。
- 未完成履约任务的首个待处理节点。
派生优先级:
- 已应用条款修复:提示“复核已应用的条款修订”。
- 审查任务排队或运行中:提示“等待法律审查结果”。
- 审查失败:提示“重新发起法律审查”。
- 审查完成且存在未处理风险:提示“处理审查风险并应用推荐条款”。
- 审查完成且存在风险但无需条款修复:提示“根据审查结果修改或提交审批”。
- 正式审批待办:提示“等待审批人审批”。
- 已审批、已签署、已归档阶段存在未完成履约任务:提示具体履约节点。
- 否则回落到
status默认动作。
接入范围:
- SQLAlchemy 合同列表响应。
- SQLAlchemy 合同详情响应。
- 工作台待办响应。
- 统一搜索文档同步/重建。
- transition 写路径的即时响应。
仍未做:
- 未删除
contracts.status_label/status_tone/next_action/next_actions旧列。 - 未移除旧写路径对 UI 缓存字段的写入。
- 未修改 OpenAPI 和前端字段名。
- 未把合同版本/草稿编辑状态纳入
ContractActionContext。
验证:
python -m compileall -q yuqei-contract-platform\services\contract-api\src\yuqei_contract_api
python -m pytest yuqei-contract-platform\services\contract-api\tests -q
结果:完整 Contract API 测试通过。
远端 PostgreSQL / Docker smoke 验证记录
验证环境:
- 服务器:
192.168.3.90 - Compose project:
yuqei-contract-v2-smoke - Contract API:
http://192.168.3.90:18100 - PostgreSQL 数据库:
yuqei_contract - 部署 artifact:
project-docs/qa-artifacts/v2-smoke-docker-deploy/2026-06-30T16-40-34
执行命令:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File yuqei-infra\scripts\deploy-v2-smoke-docker.ps1 -UseSshpass -AllowDirtyWorktree -KeepRemoteBackup
结果:
- Docker smoke:通过。
- Web、Contract API、AI Platform API health endpoints:通过。
- AI golden sample asset gate:通过,90 samples、6 suites、16 checks。
- Remote database baseline:
yuqei_contract、yuqei_ai、yuqei_ops均存在。 - Contract review worker smoke:通过。
/api/v1/runtime/schema-check 抽样结果:
- 顶层状态:
warning。 database_backend:ok,PostgreSQL。database_name:ok,当前数据库为yuqei_contract。alembic_version:ok,actual/head 均为20260630_0021。core_tables:ok,检查 20 张核心表。governance_columns:ok,检查 11 张表、36 个治理字段。postgres_extensions:ok,已安装pg_trgm。display_cache_consistency:warning,检查 12010 条未软删除合同记录,发现 8000 条旧 UI 缓存字段与派生值不一致。
样例:
perf-contract-000001:status_tone
perf-contract-000004:status_label
perf-contract-000005:status_tone
perf-contract-000006:status_label,status_tone
perf-contract-000007:status_tone
处理说明:
- 本片只做只读检查,不自动修复旧缓存。
- 本片不删除
contracts.status_label/status_tone/next_action/next_actions旧列。 - 为避免报告型
warning误伤容器健康状态,Contract API Docker healthcheck 已调整为只在 schema-check 顶层状态为error时失败;warning继续保留在 runtime schema-check 报告中供后续治理。
第三片实施记录
本次已将 display cache consistency 纳入 Contract API runtime schema-check。
新增检查项:
display_cache_consistency
检查范围:
- 只读扫描
contracts表中未软删除记录。 - 对比旧缓存字段与
derive_contract_display派生值:status_labelstatus_tonenext_actionnext_actions
返回策略:
- 全部一致:
status=ok。 - 存在不一致:
status=warning,不自动修复。 contracts表缺失:status=warning并标记 skipped,由core_tables继续负责报error。
返回 details:
checked_rowsmismatch_countsample_limitsamples:最多 5 条,格式为contract_id:field1,field2。
本片仍不做:
- 不写库。
- 不修复旧缓存。
- 不删除旧列。
- 不改变 OpenAPI 和前端字段。
验证:
python -m compileall -q yuqei-contract-platform\services\contract-api\src\yuqei_contract_api
python -m pytest yuqei-contract-platform\services\contract-api\tests\test_health.py::test_runtime_schema_check_warns_for_local_sqlite_auto_created_schema yuqei-contract-platform\services\contract-api\tests\test_health.py::test_runtime_schema_check_errors_for_missing_core_tables yuqei-contract-platform\services\contract-api\tests\test_health.py::test_runtime_schema_check_warns_for_stale_contract_display_cache -q
python -m pytest yuqei-contract-platform\services\contract-api\tests -q
结果:完整 Contract API 测试通过。