10 KiB
AI 合同平台 P1-04.9 企业日历上线治理、同步 SLO 与审计回放交付报告
日期:2026-08-24
阶段:P1-04.9 第一批
依据:《AI 合同平台系统性产品、市场、架构与体验审查报告》、P1-04.8 与 P1-04.8.1 交付报告
1. 本阶段结论
本阶段已把“日历能够连接和同步”推进为“连接必须有可审计授权、同步质量有租户目标、失败运行可以安全回放”。这三项是企业预发布的必要控制线:
- 外部日历连接不再等同于管理员已经批准。Google、Microsoft、钉钉和企业微信必须绑定当前连接的管理员同意证据,才允许人工或定时同步;
- 每个租户可以配置同步新鲜度、连续失败、调度延迟和回放退避目标,并在管理端看到健康、阻断和违约原因;
- 失败同步不会被覆盖。管理员填写原因后创建异步回放任务,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. 不变量与安全边界
- 所有同意证据、SLO、同步运行和回放任务均按
tenant_id查询和写入; - 同意批准只允许 Playbook 管理员,查看允许 admin/legal/approver;
- 未连接的外部源不能批准同意证据;
- 外部源缺少当前同意证据时,人工同步会形成明确授权失败运行,定时 Worker 不会认领;
- 撤销同意停用源,但不删除历史账本和同步运行;
- 回放不复写原运行,不直接修改原错误分类;
- 企业 secret、OAuth token 和同步游标继续只加密保存,查询仅返回配置状态;
- 当前没有把本地开发密钥描述为 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. 发布门槛与下一步
正式开放外部企业日历前仍需:
- 在两个隔离预发布租户分别使用真实钉钉与企业微信最小只读应用,完成管理员审批引用、应用可见范围、全天事件边界、增删改取消、撤销和租户隔离验证;
- 对 Google/Microsoft 保留可选集成,但中国大陆默认入口和文案继续优先钉钉、企业微信;
- 把日历令牌加密密钥和通知签名主密钥迁入 KMS/Vault 或只读 secret file,完成轮换、恢复和旧密文不可用告警演练;
- 把 SLO 违约、OAuth/企业凭据失效、连续失败、配额/限流和回放死信接入统一通知升级链路;
- 建立日历提供方错误码目录与运营处置手册,并在管理端加入 dead-letter 人工重新入队和负责人;
- 完成 P1-04.9 剩余项:反馈离线基准集、50k 关系图 Worker/LOD 压测和专用通知通道;
- 收集真实客户办公生态数据后,再决定是否进入 P1-04.8.2 飞书,而不是仅因技术上可接入就扩展供应商。
下一阶段建议进入 P1-04.9.1:KMS/Vault 密钥托管与恢复演练、日历 SLO 告警升级、回放死信人工接管和提供方错误运营手册。真实厂商预发布联调需要企业应用凭据和管理员配合,应作为并行发布门禁,不在本地伪造完成。