# Kestra V53 阶段验收记录

- 代码分支：`codex/kestra-v50`
- 验收日期：2026-07-19
- Python：3.11.15
- 结论：V53 功能与定向验收完成；允许进入 V54，但尚不移除 n8n 主路径。

## 完成范围

### MCP 治理边界

- Context MCP 暴露 13 个只读、验证、估算和比较工具。
- Scheduling MCP 只暴露 8 个受治理复合操作：
  `create_candidate_plan`、`deploy_disabled_version`、`run_canary`、
  `promote_candidate`、`pause_schedule`、`retry_failed_execution`、
  `backfill_bounded_window`、`rollback_to_previous_version`。
- 不暴露原始 Kestra YAML、任意删除、连接修改、文件、KV、密钥或直接数据库操作。
- 身份、角色、业务域、环境和关联 ID 必须由 MCP 进程环境显式注入；缺失、越权或
  非法 UUID 时失败关闭。
- AI 不能提交 Runner 任务令牌、不能自行声明 Canary 成功、不能授予写权限。

### PostgreSQL 控制面

Alembic `20260719_80` 新增并验证：

- 候选版本的业务域、创建主体和可信写授权字段。
- `workflow_canary_evidence`：保存真实 Kestra 执行 ID 和可信验证结果。
- `workflow_gateway_operations`：保存发布/回滚幂等领取与完成状态。
- `workflow_runs.parent_run_id`、`attempt`、`run_metadata`：记录重试、补数和执行元数据。
- `workflow_plan_audits.actor_subject` 与 `idempotent_replay` 审计决策。

`PostgresSchedulingPlanStore` 已覆盖候选、禁用部署、Canary、发布、暂停、重试、
限界补数和回滚。幂等键绑定具体工作流版本；相同键用于其他版本时拒绝执行，不会
错误重放旧结果。

`PostgresAuditSink` 只写入有界安全明细，不持久化令牌、密码、连接串、原始业务
数据或任意日志正文。

### Canary 与发布切换

- Kestra 不允许直接执行禁用流。Gateway 在 Canary 时仅打开一个受控的手工执行
  窗口，发起执行后立即恢复禁用；编译后的所有计划触发器仍逐个保持禁用。
- 独立 `CanaryVerifier` 从持久证据读取执行 ID，并直接查询 Kestra 终态；只有它
  可以把证据更新为 `passed` 或 `failed`。
- 发布新版本时，先激活新流，再停用上一活动流，并在 PostgreSQL 中原子切换主版本。
  任一步失败会执行补偿恢复并释放幂等领取。
- 回滚会停用当前流、激活上一流；上一流激活失败时会恢复当前流。

### 重试与补数

- 仅失败执行允许重试；父执行、重放执行和尝试次数写入 `workflow_runs`。
- 补数同时受身份范围、最大天数、最大运行次数和 SchedulePlan 限制。
- 当前补数估算只接受语义明确的五段 Cron，并按 SchedulePlan 时区计算；不明确的
  Cron 或窗口内无运行实例时失败关闭。

### 生产启动与容器

- `app.core.mcp.bootstrap` 提供 Scheduling、Context 和 Canary Verifier 的生产工厂。
- Scheduling 工厂装配 PostgreSQL、Kestra Adapter、Runner `TaskTokenIssuer` 和
  持久审计；所有关键依赖缺失时拒绝启动。
- 新增 `deploy/docker/mcp.Dockerfile`：Python 3.11、非 root 用户、无 HTTP 端口。
- Compose `dataops-mcp` profile 提供 Context/Scheduling 两个只读文件系统的
  stdio 进程；身份范围必须通过环境配置。
- 新增 MCP 依赖采用兼容版本范围，允许向上升级并限制不兼容的大版本。

## 真实 L3 验收

`tests/integration/test_v53_mcp_kestra_runner_l3.py` 使用生产工厂和真实 MCP
`ClientSession` 完成：

1. MCP 创建同一数据流的 v1 候选。
2. MCP 编译并禁用部署到真实 Kestra。
3. MCP 内部签发短时节点令牌并发起 Canary。
4. Kestra 调用真实 Runner；Runner 从 Neo4j 定义和 PostgreSQL 加密凭据获取
   外部 PostgreSQL 数据源，查询成功。
5. 独立验证器读取真实 Kestra 终态并写入可信证据。
6. MCP 发布 v1。
7. 对 v2 重复候选、部署、Canary 和发布，验证 v1 在 Kestra 侧实际停用。
8. 使用相同幂等键重放 v2 发布，确认不产生第二次状态变更。
9. MCP 回滚 v2，验证 v1 恢复启用、v2 停用。
10. 验证 Runner 成功账本、Gateway 幂等账本和清理逻辑。

结果：`1 passed`。

## 增量验证证据

- V53 MCP、编排器、Runner、安全边界、PostgreSQL、容器握手、真实 L3、相关
  Kestra 回归和隔离迁移：`105 passed`。
- 迁移测试使用临时数据库，覆盖两次 `upgrade head`、`downgrade -1` 和自动清理。
- PostgreSQL 持久化与 Context 只读模型真实集成：通过。
- Context/Scheduling 两个构建后容器的 JSON-RPC initialize 和 tools/list：
  `2 passed`。
- Ruff（V53 变更范围）：通过。
- `pip check`：无依赖冲突。
- Compose 配置解析：通过。
- MCP 镜像构建：通过，镜像 ID
  `sha256:1246bb090da7c42b4171ec5f87b430b7891cbf72cad88f140c0a17841bbe7ca1`。

本阶段遵循增量验证原则，没有重复运行无关前端或全仓库测试。Python 3.11 升级时
已完成一次后端全量基线回归；V53 只验证受影响范围和高风险真实链路。

## 保持的安全边界与后续阶段

- 生产写节点继续失败关闭，AI 不具备自行授予写权限的路径。
- Context MCP 的容量与数据源健康结果是保守的控制面读模型，不替代 Runner 的
  实时业务查询。
- n8n 服务、现有绑定和主路径未删除。V54/V55 应继续按双轨方式推进流量观测、
  迁移批次、回退演练和最终切换；只有满足后续门禁后才能移除 n8n。
