Files
ai-contract-platform/project-docs/V2-P1-04.9-calendar-consent-slo-auditable-replay-2026-08-24.md
T
yuqei 1d85329a6a
Build and Test Quality Gate / Contract Web typecheck and build (pull_request) Successful in 9m12s
Build and Test Quality Gate / Isolated Alibaba and Tencent KMS gateway (pull_request) Failing after 4m53s
Build and Test Quality Gate / Python tests and Contract API migration (pull_request) Failing after 24m55s
Security Quality Gate / npm audit, Bandit, pip-audit, detect-secrets (pull_request) Failing after 8m42s
feat: deliver governed contract platform and async AI tasks
2026-08-26 12:53:47 +08:00

10 KiB
Raw Blame History

AI 合同平台 P1-04.9 企业日历上线治理、同步 SLO 与审计回放交付报告

日期:2026-08-24
阶段:P1-04.9 第一批
依据:《AI 合同平台系统性产品、市场、架构与体验审查报告》、P1-04.8 与 P1-04.8.1 交付报告

1. 本阶段结论

本阶段已把“日历能够连接和同步”推进为“连接必须有可审计授权、同步质量有租户目标、失败运行可以安全回放”。这三项是企业预发布的必要控制线:

  1. 外部日历连接不再等同于管理员已经批准。Google、Microsoft、钉钉和企业微信必须绑定当前连接的管理员同意证据,才允许人工或定时同步;
  2. 每个租户可以配置同步新鲜度、连续失败、调度延迟和回放退避目标,并在管理端看到健康、阻断和违约原因;
  3. 失败同步不会被覆盖。管理员填写原因后创建异步回放任务,Worker 生成新的同步运行并关联原运行,旧失败证据保持不可变。

当前实现可支撑没有真实厂商凭据的本地开发、隔离自动化和管理端 UAT。它没有替代真实预发布联调:正式开放前仍必须使用客户或公司的真实企业应用完成最小权限、管理员审批、令牌撤销、配额和网络故障演练。

2. 产品与市场判断

企业客户不会只询问“是否支持钉钉或企业微信”,还会继续询问:谁批准了应用、批准的是哪组权限、连接变化后旧审批是否仍有效、同步多久未更新算故障、失败后能否重放且不破坏审计链。本阶段直接回答这些采购和安全评审问题。

产品边界明确为:

  • 连接是技术事实,同意是治理事实,两者分别记录;
  • 同意证据绑定提供方、当前连接时间、实际 scope、应用标识、日历目标和主体的 SHA-256 指纹;
  • 改变提供方、Calendar ID、UnionID、OAuth 连接或企业应用凭据会使旧同意证据自动失效;
  • 只确认最小只读权限和“仅全天事件进入 SLA”后才能批准;
  • 撤销同意会立即停用日历源,但不删除历史同步运行或同意账本;
  • SLO 只监控已启用且定时同步的源,手动源不会被误报为违约;
  • 页面区分 blocked、pending、healthy、breached 和 not_monitored,不使用单一绿灯掩盖原因。

3. 实现内容

3.1 管理员同意证据

新增不可变 playbook_calendar_consent_evidence 账本和日历源当前同意状态:

  • approved:当前连接已经过管理员核验;
  • pending:已连接或连接发生变化,但尚未批准;
  • revoked:管理员或连接撤销;
  • not_required:日期清单和 ICS 等不依赖外部企业授权的源。

批准证据保存提供方、实际 scope 快照、连接指纹、外部/内部审批引用、边界确认、说明、操作者和时间。密钥、OAuth token 和应用 secret 不进入证据账本,也不通过查询接口返回。

连接、凭据、Calendar ID 或主体变化会追加 invalidated 记录,不会静默覆盖原批准记录。调度 Worker 只认领连接可用且同意状态为 approved 的外部日历源。

3.2 租户级同步 SLO

新增租户级策略:

  • 同步新鲜度目标,默认 120 分钟;
  • 连续失败阈值,默认 3 次;
  • 调度延迟容忍,默认 15 分钟;
  • 回放最大尝试次数,默认 3 次;
  • 回放基础退避,默认 5 分钟。

SLO 看板按源解释:连接不可用、管理员同意缺失、从未成功、新鲜度超标、连续失败达到阈值、调度积压超标。另提供最近 24 小时运行成功率和运行数。尚无成功运行的新源先进入目标时长宽限期,避免创建后立即误报。

3.3 错误分类与可观测证据

同步运行新增:

  • error_category:authentication、authorization、rate_limited、cursor_invalid、network、configuration、provider_error、validation、unknown;
  • provider_error_code:只保存已清洗的厂商错误码或 HTTP 分类,不保存 URL 和凭据;
  • retryable:决定 Worker 是否自动退避重试;
  • replay_job_id 与 replay_of_run_id:建立新运行与回放任务、原失败运行之间的证据链。

分类器会检查 HTTP 状态、异常因果链和安全化错误文本。认证、授权和配置问题默认需要人工处理;限流、游标失效、网络和 5xx 默认可重试。

3.4 异步审计回放

新增 playbook_calendar_replay_jobs:

  • 只有失败运行可以创建回放;
  • 同一失败运行不能同时存在多个活动回放;
  • 管理员必须填写不少于 8 个字符的原因;
  • Worker 使用数据库租约认领任务;
  • 可重试错误按租户策略指数退避;
  • 超过最大尝试或遇到不可重试错误进入 dead_letter;
  • 成功回放生成新的同步运行,原运行状态和错误证据不变。

回放优先于普通定时日历任务处理,使明确的人工恢复请求不会长期排在常规轮询之后。

3.5 API、前端与契约

新增 API:

  • GET /governance/calendar-consent-evidence;
  • POST /governance/calendar-sources/{source_id}/consent-evidence;
  • GET/PUT /governance/calendar-sync-slo-policy;
  • GET /governance/calendar-sync-slo-dashboard;
  • GET /governance/calendar-replay-jobs;
  • POST /governance/calendar-sync-runs/{source_run_id}/replay。

Contract Web 增加六个同源代理、SLO 指标与策略表单、同意证据表单、错误分类、失败回放入口和队列状态。页面标题升级为 Enterprise governance · P1-04.9。

OpenAPI 当前为 111 个路径、166 个 schema,0 个悬空 schema 引用。数据库迁移版本为 20260824_0061。

4. 不变量与安全边界

  1. 所有同意证据、SLO、同步运行和回放任务均按 tenant_id 查询和写入;
  2. 同意批准只允许 Playbook 管理员,查看允许 admin/legal/approver;
  3. 未连接的外部源不能批准同意证据;
  4. 外部源缺少当前同意证据时,人工同步会形成明确授权失败运行,定时 Worker 不会认领;
  5. 撤销同意停用源,但不删除历史账本和同步运行;
  6. 回放不复写原运行,不直接修改原错误分类;
  7. 企业 secret、OAuth token 和同步游标继续只加密保存,查询仅返回配置状态;
  8. 当前没有把本地开发密钥描述为 KMS,也没有把 MockTransport 测试描述为真实厂商联调。

5. 验证结果

5.1 自动化与迁移

  • 后端收集 353 项:349 项通过、4 项按既有环境条件跳过、0 项失败;
  • 日历治理与国内适配器专项:16/16 通过;
  • 新增专项覆盖同意批准、目标变化自动失效、错误分类、旧运行保留、异步回放、结果关联和 SLO 违约解释;
  • SQLite 隔离迁移完成 base → 0061 → 0060 → 0061;
  • PostgreSQL 正向迁移完成 0060 → 0061 (head);
  • 前端现有测试:45/45 通过;
  • TypeScript:通过;
  • Next.js 生产构建:通过,生成/收集 139 个页面;
  • OpenAPI YAML:111 个路径、166 个 schema、0 个悬空 schema 引用;
  • Python compileall:通过;
  • Contract API /health:200,status=ok;
  • 运行时日历集成检查:ok。

5.2 Chrome 超级管理员 UAT

工作空间:Playbook 隔离 UAT
账号:uat.legal.20260823@example.test
页面:http://127.0.0.1:3000/admin/playbook?tab=operations

已确认:

  • 页面显示 P1-04.9,登录态在 Web/API/Worker 重启后保持;
  • SLO 看板显示监控源、健康、违约、阻断和 24 小时成功率;
  • 新鲜度、失败阈值、调度延迟、回放次数和退避策略可见;
  • 保存租户日历 SLO 成功并返回版本证据;
  • 当前 UAT 只有日期清单源,因此同意证据选择为空、批准和撤销按钮保持禁用,不会产生虚假授权记录;
  • 同步运行显示人工/调度/回放来源、错误分类、可重试性和原运行关联;
  • 服务重启期间的临时加载错误在恢复后能自动清除,不再长期残留陈旧 404;
  • 页面可见区域没有控件重叠、不可达主要按钮或截断关键状态。

本轮没有真实钉钉、企业微信、Google 或 Microsoft 企业凭据,因此没有对厂商发起真实授权或日历同步,没有创建虚假成功连接,也没有向外部通道派发通知。真实连接成功路径由隔离自动化覆盖,仍需预发布企业租户提供最终证据。

6. 当前架构评估

继续采用统一日历领域模型、PostgreSQL 事务账本和治理 Worker 是合理的:

  • 同意、同步、SLO 和回放都与租户治理事实强关联,优先保证事务一致和可追溯;
  • 数据库租约已满足当前吞吐量,并允许多个 Worker 使用 skip locked 竞争;
  • 回放任务与同步运行解耦,未来迁移到专用消息队列时不需要改变前端 API 或证据模型;
  • 错误分类是确定性规则,不把不可解释模型用于运行控制;
  • 当前规模没有必要为日历单独拆微服务,避免额外分布式事务和凭据边界。

需要注意:当真实租户数、日历源数或回放吞吐显著增长时,应将任务派发迁到专用队列,并为租约积压、任务年龄和提供方配额建立统一指标。迁移触发条件应以压测和真实 SLO 数据决定,而不是预先拆分。

7. 发布门槛与下一步

正式开放外部企业日历前仍需:

  1. 在两个隔离预发布租户分别使用真实钉钉与企业微信最小只读应用,完成管理员审批引用、应用可见范围、全天事件边界、增删改取消、撤销和租户隔离验证;
  2. 对 Google/Microsoft 保留可选集成,但中国大陆默认入口和文案继续优先钉钉、企业微信;
  3. 把日历令牌加密密钥和通知签名主密钥迁入 KMS/Vault 或只读 secret file,完成轮换、恢复和旧密文不可用告警演练;
  4. 把 SLO 违约、OAuth/企业凭据失效、连续失败、配额/限流和回放死信接入统一通知升级链路;
  5. 建立日历提供方错误码目录与运营处置手册,并在管理端加入 dead-letter 人工重新入队和负责人;
  6. 完成 P1-04.9 剩余项:反馈离线基准集、50k 关系图 Worker/LOD 压测和专用通知通道;
  7. 收集真实客户办公生态数据后,再决定是否进入 P1-04.8.2 飞书,而不是仅因技术上可接入就扩展供应商。

下一阶段建议进入 P1-04.9.1:KMS/Vault 密钥托管与恢复演练、日历 SLO 告警升级、回放死信人工接管和提供方错误运营手册。真实厂商预发布联调需要企业应用凭据和管理员配合,应作为并行发布门禁,不在本地伪造完成。