Files
ai-contract-platform/project-docs/V2-phase3-ui-cache-cleanup-design-2026-06-30.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

9.4 KiB
Raw Blame History

AI 合同平台 V2 Phase 3 UI 缓存字段 cleanup 设计评审

当前基线

本设计继续对齐《AI 合同平台 V2 下一阶段开发优化方案》的 Phase 3 schema 硬化方向,目标是把 contracts 表中的旧 UI 缓存字段从“历史兼容缓存”逐步治理到“可安全停写、可选删列”的状态。

截至本记录:

  • 远端 smoke PostgreSQL:192.168.3.90
  • Contract API:http://192.168.3.90:18100
  • Alembic actual/head:20260630_0021
  • display_cache_consistency.status:ok
  • checked_rows:12010
  • mismatch_count:0
  • 回滚 snapshot:/opt/apps/ai-contract-platform-v2-smoke/backups/display-cache/display-cache-backfill-candidate-2026-06-30T17-37-24.json
  • 本地备份:project-docs/qa-artifacts/display-cache-governance/2026-06-30T17-37-24/display-cache-backfill-candidate-2026-06-30T17-37-24.json

这说明当前 smoke 环境已经处于 cleanup migration 前的稳定状态:旧列仍保留,但值已与派生规则一致。

字段分层判断

目标字段:

  • contracts.status_label
  • contracts.status_tone
  • contracts.next_action
  • contracts.next_actions

分层结论:

  1. status_label/status_tone 是纯展示字段,可以完全由 contracts.status 派生。
  2. next_action/next_actions 不是纯展示字段,当前混合了三类含义:
    • 状态默认动作,例如待提交、待审批、已审批。
    • 结构化上下文动作,例如审查任务、审批实例、条款修复、履约任务。
    • 少量人工/业务上下文提示,例如合同编辑页仍允许编辑 next_action。

因此不建议直接创建一次性 migration 删除四列。更稳的路径是先把 status_label/status_tone 和 next_action/next_actions 拆开治理。

当前仍在写旧列的位置

合同主写路径

  • persistence/contract_core.py
    • 创建合同时仍从 ContractCreateData 写入 status_label/status_tone/next_action/next_actions。
    • 更新合同时仍允许更新 next_action/next_actions。

状态流/审计/时间线

  • persistence/audit.py
    • transition_contract 与 transition_contract_in_session 仍将状态流参数写回四个旧列。
  • sqlalchemy_transition_orchestration.py
    • 状态流仍传递四个展示字段。
  • sqlalchemy_approval_orchestration.py
    • 审批提交、重提、通过、退回仍提供展示字段。

审查/文件/条款修复

  • sqlalchemy_review_orchestration.py
    • 审查开始、完成、失败后仍写 status_label/status_tone/next_action/next_actions。
  • sqlalchemy_file_orchestration.py
    • 文件上传后仍写 next_action/next_actions。
  • sqlalchemy_clause_repair_orchestration.py
    • 条款修复后仍写 next_action/next_actions。

支撑路径

  • sqlalchemy_support_orchestration.py
    • 归档动作仍写展示字段。
  • seed_data.py
    • demo/seed 数据仍包含旧字段。
  • in_memory_repository.py
    • 测试/demo 内存仓储仍维护旧字段。

不属于本轮删除目标的字段

  • review_tasks.status_label:这是审查任务自己的状态标签,不是 contracts 表 UI 缓存列。
  • contract_search_documents.status_label:这是搜索索引/搜索展示冗余字段,后续可以单独治理,但不应与 contracts 表删列混在同一刀。
  • OpenAPI 和前端 TypeScript 响应字段:仍应保留兼容,因为前端合同列表、详情、搜索、dashboard 仍依赖这些响应字段。

当前读路径状态

读路径已经基本完成派生化:

  • 合同列表 mapper 使用 derive_contract_display。
  • 合同详情 mapper 使用 derive_contract_display。
  • 搜索文档同步/重建使用 derive_contract_display。
  • ContractActionContext 已纳入审查、审批、条款修复、履约任务等上下文。
  • runtime/schema-check 已复用同一套 display cache governance 逻辑做只读一致性检查。

这意味着 API 响应可以继续返回 status_label/status_tone/next_action/next_actions,但来源应逐步变为 serializer/domain 派生,而不是依赖数据库旧列。

推荐 cleanup 顺序

Slice 3.5.1:停写前设计锁定

目标:

  • 保留数据库旧列。
  • 保留 API/OpenAPI/前端字段。
  • 明确 next_action/next_actions 中人工提示的归属。

建议动作:

  1. 审计前端合同编辑页的 next_action 输入是否仍是产品需求。
  2. 如果仍需要人工提示,新增事实字段或结构:
    • 方案 A:contracts.action_hint 文本字段。
    • 方案 B:contract_action_overrides JSON/子表。
    • 方案 C:完全移除人工编辑入口,只保留结构化派生动作。
  3. 不在此片写 migration。

验收:

  • 形成明确决策:next_action 人工提示是保留、迁移还是废弃。
  • schema-check 仍为 ok。

Slice 3.5.2:停止写 status_label/status_tone

目标:

  • contracts.status_label/status_tone 不再由业务编排手写。
  • 仍保留列,用于兼容、回滚和 schema-check。

建议动作:

  1. 创建集中 helper,例如 apply_contract_display_cache(row, action_context=None) 或 sync_contract_display_cache(row)。
  2. 对状态流写路径,改为只写事实字段 status,展示字段由 helper/派生层统一刷新。
  3. 对 create/seed/in-memory 路径,改为由 status 派生默认展示字段。
  4. 增加测试:制造错误旧值后,读路径仍返回派生值;写路径不会再写手写 status label/tone。

验收:

  • schema-check.display_cache_consistency 保持 ok。
  • 合同列表、详情、workspace、搜索抽样通过。
  • OpenAPI/前端响应字段不变。

Slice 3.5.3:拆分 next_action/next_actions 语义

目标:

  • 将 next_action/next_actions 从“旧 UI 缓存列”转成真正的 Action Context 派生。
  • 如果保留人工提示,迁移到新事实字段或覆盖结构。

建议动作:

  1. 将合同编辑页的 next_action 输入改名/改语义,避免继续把它当展示缓存。
  2. 将文件上传、审查任务、条款修复等写路径改成写结构化事实,而不是写 next_action 文案。
  3. 扩展 ContractActionContext,覆盖合同版本/草稿编辑状态。
  4. 搜索文档继续保留派生后的展示文案,但来源来自 domain/serializer。

验收:

  • 写路径不再直接设置 contracts.next_action/next_actions,或仅通过兼容 helper 写入派生结果。
  • 旧列一致性检查仍为 ok。
  • 前端主要动作按钮展示不退化。

Slice 3.5.4:cleanup migration 设计评审

只有满足以下条件后才进入删列 migration:

  • API 响应字段完全由 mapper/serializer 派生。
  • 后端业务写路径不再依赖四个旧列。
  • 前端不再提交旧 UI 缓存字段作为业务输入。
  • 搜索索引重建可以完全从事实字段和派生规则生成展示文案。
  • smoke 环境连续多轮 display_cache_consistency 为 ok。
  • 已保留可回滚 snapshot,且 rollback 演练流程可执行。

删列顺序建议:

  1. 第一片只删除或弃用 status_label/status_tone,因为它们最纯粹。
  2. 第二片再处理 next_action/next_actions,前提是人工提示语义已经迁出。
  3. 每片 migration 后都复跑 Docker smoke、schema-check、合同列表、详情、搜索、workspace 抽样。

不建议的做法

  • 不建议一次性删除四个旧列。
  • 不建议为了“数据库更干净”破坏 OpenAPI/前端兼容字段。
  • 不建议在 next_action 人工提示归属未决时删除 next_action/next_actions。
  • 不建议把 contract_search_documents.status_label 和 contracts.status_label 放在同一个 migration 里治理。

当前建议

2026-07-01 已完成完整上下文口径的 display cache prestate 重新固化:

  • 旧列 status_label/status_tone/next_action/next_actions 仍保留。
  • display_cache_governance 已按完整 ContractActionContext 判断一致性。
  • smoke 环境已执行可回滚 backfill,display_cache_consistency.mismatch_count=0。
  • display_cache_cleanup_prestate.status=ok。
  • 详细记录见 project-docs/V2-phase3-display-cache-context-prestate-2026-07-01.md。

下一步最稳仍不是直接写删列 migration,而是继续停写旧 contracts.next_action/next_actions 的生产写路径:

  1. 让文件上传、审查任务、条款修复、审批流、归档等路径只写结构化事实。
  2. API 响应继续由 derive_contract_display(...) 和完整 ContractActionContext 派生 next_action/next_actions。
  3. 旧列只作为兼容缓存和回滚面保留,继续由 schema-check 保护。
  4. 连续多轮 smoke 保持 display_cache_consistency=ok 后,再进入 Slice 3.5.4 cleanup migration 设计评审。

这个顺序能避免把“UI 文案缓存治理”和“合同下一步动作业务模型”混成一次高风险 schema 大改,同时保留对旧前端/API 调用方的兼容面。

2026-07-01 停写旧动作缓存列进展

已完成第一片停写:

  • 生产 SQLAlchemy 写路径不再刷新 contracts.next_action / contracts.next_actions。
  • 旧动作列仍保留,用于兼容、回滚和后续 cleanup migration 前保护。
  • display_cache_consistency 调整为只检查 status_label/status_tone 与派生状态展示一致。
  • next_action/next_actions 的用户可见值继续由 derive_contract_display(...) 和完整 ContractActionContext 派生。
  • 详细记录见 project-docs/V2-phase3-stop-legacy-next-action-writes-2026-07-01.md。

下一步应先部署 smoke 验证,而不是直接删列。