Files
ai-contract-platform/project-docs/V2-phase3-deprecated-next-action-alias-observability-2026-07-01.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

7.7 KiB
Raw Blame History

AI 合同平台 V2 Phase 3 旧 next_action alias 使用观测

背景

contracts.next_action / contracts.next_actions 已停止作为生产写路径使用,API 响应继续由 ContractActionContext 派生。

本片继续处理 cleanup migration 前的最后一段风险:确认是否仍有旧客户端在 PATCH 合同时提交:

  • next_action
  • next_actions

当前结论仍是先观测,不删列、不移除响应字段、不移除旧写入口。

本次实现

新增轻量观测模块:

  • yuqei_contract_api.deprecated_alias_observability

合同 PATCH 入口现在会识别 ContractUpdateRequest.model_fields_set 中是否出现旧 alias 字段。

当请求包含旧字段时,系统会:

  • 拒绝旧写入请求。
  • 返回 422,提示改用 action_hint。
  • 不再将旧 next_action 规范化为 action_hint。
  • 不再接受旧 next_actions 输入。
  • 写入一条结构化 warning 日志:Deprecated contract update action alias used。
  • 写入进程内观测窗口:app.state.deprecated_alias_usages。

新增只读查询端点:

GET /api/v1/metrics/deprecated-aliases
GET /api/v1/metrics/deprecated-aliases?alias_group=contract_update_action

返回字段包括:

  • alias_group
  • fields
  • target_field
  • compatibility_status
  • contract_id
  • actor_name_present
  • endpoint
  • method
  • trace_id
  • tenant_id
  • timestamp

隐私与安全边界

观测数据不记录旧字段的文本值。

例如旧请求:

{
  "next_action": "legacy-next-action-value-should-not-be-logged",
  "next_actions": ["ignored legacy button"]
}

观测记录只保留:

{
  "fields": ["next_action", "next_actions"],
  "target_field": "action_hint"
}

这样可以判断是否仍有旧客户端在使用 alias,同时避免把人工跟进提示、按钮文案等业务文本写入日志或指标。

cleanup migration 前置判断

后续进入删列或移除旧写入口前,建议至少满足:

  • smoke / 准生产连续观测窗口内 contract_update_action alias 使用量为 0。
  • 日志采集侧没有 Deprecated contract update action alias used。
  • 外部调用方确认不再提交 next_action / next_actions。
  • 前端只提交 action_hint 的 typecheck 和页面 smoke 仍通过。
  • schema-check 继续明确旧动作列只是 retained compatibility fields。

观察窗口执行方式

新增只读观察脚本:

python yuqei-infra\scripts\watch-deprecated-alias-usage.py `
  --base-url http://192.168.3.90:18100 `
  --duration-seconds 1800 `
  --interval-seconds 60

脚本会:

  • 启动时读取一次 /api/v1/metrics/deprecated-aliases?alias_group=contract_update_action 作为 baseline。
  • 在观察窗口内持续轮询。
  • 运行期间输出进度行:CONNECT、START、每次 POLL。
  • 只判断窗口内新增的旧 alias 使用记录。
  • 输出 JSON 报告。
  • 默认把报告写入 project-docs/qa-artifacts/v2-deprecated-alias-observation/。

这样即使 smoke 环境里已经存在手工抽样记录,也不会影响后续观察窗口结论。

注意:--duration-seconds 1800 表示观察 30 分钟。脚本不会退出,直到窗口结束;正常情况下会先显示 baseline,然后每 60 秒显示一次类似:

DEPRECATED_ALIAS_OBSERVATION_POLL sample=2 elapsed_seconds=60.1 remaining_seconds=1739.9 baseline_total=1 final_total=1 observed_delta=0 relevant_new_count=0 max_allowed_new=0

如果要中止观察,可以按 Ctrl+C。

短窗口 smoke 可使用:

python yuqei-infra\scripts\watch-deprecated-alias-usage.py `
  --base-url http://192.168.3.90:18100 `
  --duration-seconds 5 `
  --interval-seconds 2

验收口径:

  • status=pass
  • relevant_new_count=0
  • max_allowed_new=0
  • DEPRECATED_ALIAS_OBSERVATION_PASS

如果需要在观察期间允许合成探针,可以用 trace 过滤:

python yuqei-infra\scripts\watch-deprecated-alias-usage.py `
  --base-url http://192.168.3.90:18100 `
  --duration-seconds 1800 `
  --interval-seconds 60 `
  --ignore-trace-prefix trace-deprecated-alias-smoke

注意:过滤只能用于明确标记的合成流量,不能用于隐藏真实客户端兼容调用。

验证

python -m pytest `
  yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_contract_update_accepts_action_hint_and_rejects_legacy_next_action `
  yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_contract_update_legacy_action_alias_usage_is_observable `
  -q

结果:

  • 旧 alias accepted 阶段:2 passed。
  • Slice A 收紧后,测试名更新为:
python -m pytest `
  yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_contract_update_accepts_action_hint_and_rejects_legacy_next_action `
  yuqei-contract-platform\services\contract-api\tests\test_contract_workflow.py::test_contract_update_legacy_action_alias_usage_is_observable `
  -q
python yuqei-infra\scripts\watch-deprecated-alias-usage.py `
  --base-url http://192.168.3.90:18100 `
  --duration-seconds 5 `
  --interval-seconds 2

结果:

  • DEPRECATED_ALIAS_OBSERVATION_PASS。
  • baseline_total=1。
  • final_total=1。
  • observed_delta=0。
  • relevant_new_count=0。
  • artifact:project-docs/qa-artifacts/v2-deprecated-alias-observation/deprecated-alias-observation-2026-07-01T22-33-31.json。
  • 脚本已兼容远端宿主机 Python 3.6.8,并可在 192.168.3.90 直接执行:
    • baseline_total=1
    • final_total=1
    • observed_delta=0
    • relevant_new_count=0
    • DEPRECATED_ALIAS_OBSERVATION_PASS
  • 脚本已改为默认显示观察进度,远端 3 秒 smoke 输出了 CONNECT、START、3 次 POLL 和最终 PASS。

远端 smoke 验证

环境:

  • 宿主机:192.168.3.90
  • compose project:yuqei-contract-v2-smoke
  • Contract API:http://127.0.0.1:18100

部署结果:

  • contract-api 已重建并启动。
  • contract-api 容器状态:healthy。
  • /api/v1/runtime/schema-check 返回 status=ok。
  • display_cache_consistency.mismatch_count=0。
  • display_cache_consistency.checked_rows=12022。
  • display_cache_consistency.retained_compat_fields=next_action,next_actions。

旧 alias 抽样:

  • smoke 合同:contract-41ab55e94fe4
  • 请求字段:next_action=legacy-alias-observability-smoke-value
  • 请求字段:next_actions=["ignored legacy button"]
  • 响应字段:action_hint=legacy-alias-observability-smoke-value
  • 响应字段:next_action=legacy-alias-observability-smoke-value
  • metrics 初始值:total=0
  • metrics 抽样后:total=1
  • metrics item:
    • alias_group=contract_update_action
    • fields=["next_action","next_actions"]
    • target_field=action_hint
    • compatibility_status=accepted
    • contract_id=contract-41ab55e94fe4
    • trace_id=trace-deprecated-alias-smoke
    • tenant_id=tenant-deprecated-alias-smoke
  • metrics 中未出现旧字段文本值 legacy-alias-observability-smoke-value。
  • 最近 10 分钟 Deprecated contract update action alias used 日志计数为 1。
  • 最近 10 分钟 Contract display cache mismatch 日志计数为 0。

当前结论

旧 alias 使用已经具备可观测性。

30 分钟 smoke 观察窗口已通过:

  • 执行时间:2026-07-01T23:31:51+08:00 至 2026-07-02T00:01:51+08:00。
  • samples=31。
  • baseline_total=1。
  • final_total=1。
  • observed_delta=0。
  • relevant_new_count=0。
  • reset_detected=false。
  • artifact:project-docs/qa-artifacts/v2-deprecated-alias-observation/deprecated-alias-observation-2026-07-02T00-01-51.json。

这说明本轮观察窗口内没有新增旧 next_action / next_actions alias 调用。可以进入 cleanup migration 设计评审,但仍不建议直接删列。